landing_page_widget.dart 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import 'dart:io';
  2. import 'package:dots_indicator/dots_indicator.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:photos/core/configuration.dart';
  5. import 'package:photos/ente_theme_data.dart';
  6. import 'package:photos/ui/account/email_entry_page.dart';
  7. import 'package:photos/ui/account/login_page.dart';
  8. import 'package:photos/ui/account/password_entry_page.dart';
  9. import 'package:photos/ui/account/password_reentry_page.dart';
  10. import 'package:photos/ui/common/gradientButton.dart';
  11. import 'package:photos/ui/payment/subscription.dart';
  12. class LandingPageWidget extends StatefulWidget {
  13. const LandingPageWidget({Key key}) : super(key: key);
  14. @override
  15. State<LandingPageWidget> createState() => _LandingPageWidgetState();
  16. }
  17. class _LandingPageWidgetState extends State<LandingPageWidget> {
  18. double _featureIndex = 0;
  19. @override
  20. Widget build(BuildContext context) {
  21. return Scaffold(body: _getBody(), resizeToAvoidBottomInset: false);
  22. }
  23. Widget _getBody() {
  24. return Center(
  25. child: SingleChildScrollView(
  26. child: Column(
  27. children: [
  28. Padding(padding: const EdgeInsets.all(12)),
  29. Text(
  30. "ente",
  31. style: TextStyle(
  32. fontWeight: FontWeight.bold,
  33. fontFamily: 'Montserrat',
  34. fontSize: 42,
  35. ),
  36. ),
  37. Padding(
  38. padding: EdgeInsets.all(28),
  39. ),
  40. _getFeatureSlider(),
  41. Padding(
  42. padding: EdgeInsets.all(12),
  43. ),
  44. DotsIndicator(
  45. dotsCount: 3,
  46. position: _featureIndex,
  47. decorator: DotsDecorator(
  48. activeColor:
  49. Theme.of(context).colorScheme.dotsIndicatorActiveColor,
  50. color: Theme.of(context).colorScheme.dotsIndicatorInactiveColor,
  51. activeShape: RoundedRectangleBorder(
  52. borderRadius: BorderRadius.circular(3),
  53. ),
  54. shape: RoundedRectangleBorder(
  55. borderRadius: BorderRadius.circular(3),
  56. ),
  57. size: Size(100, 5),
  58. activeSize: Size(100, 5),
  59. spacing: EdgeInsets.all(3),
  60. ),
  61. ),
  62. Padding(
  63. padding: EdgeInsets.all(28),
  64. ),
  65. _getSignUpButton(context),
  66. Container(
  67. width: double.infinity,
  68. padding: EdgeInsets.fromLTRB(20, 12, 20, 28),
  69. child: Hero(
  70. tag: "log_in",
  71. child: ElevatedButton(
  72. style:
  73. Theme.of(context).colorScheme.optionalActionButtonStyle,
  74. onPressed: _navigateToSignInPage,
  75. child: Text(
  76. "Existing user",
  77. style: TextStyle(
  78. color: Colors.black, // same for both themes
  79. ),
  80. ),
  81. ),
  82. ),
  83. ),
  84. Padding(
  85. padding: EdgeInsets.all(20),
  86. ),
  87. ],
  88. ),
  89. ),
  90. );
  91. }
  92. Widget _getSignUpButton(BuildContext context) {
  93. return Container(
  94. width: double.infinity,
  95. padding: EdgeInsets.symmetric(horizontal: 20),
  96. child: GradientButton(
  97. linearGradientColors: const [
  98. Color(0xFF2CD267),
  99. Color(0xFF1DB954),
  100. ],
  101. onTap: _navigateToSignUpPage,
  102. child: Text(
  103. "New to ente",
  104. style: gradientButtonTextTheme(),
  105. ),
  106. ),
  107. );
  108. }
  109. Widget _getFeatureSlider() {
  110. return ConstrainedBox(
  111. constraints: BoxConstraints(maxHeight: 320),
  112. child: PageView(
  113. children: [
  114. FeatureItemWidget(
  115. "assets/onboarding_lock.png",
  116. "Private backups",
  117. "for your memories",
  118. "End-to-end encrypted by default",
  119. ),
  120. FeatureItemWidget(
  121. "assets/onboarding_safe.png",
  122. "Safely stored",
  123. "at a fallout shelter",
  124. "Designed to outlive",
  125. ),
  126. FeatureItemWidget(
  127. "assets/onboarding_lock.png",
  128. "Available",
  129. "everywhere",
  130. Platform.isAndroid
  131. ? "Android, iOS, Web, Desktop"
  132. : "iOS, Android, Web, Desktop",
  133. ),
  134. ],
  135. onPageChanged: (index) {
  136. setState(() {
  137. _featureIndex = double.parse(index.toString());
  138. });
  139. },
  140. ),
  141. );
  142. }
  143. void _navigateToSignUpPage() {
  144. Widget page;
  145. if (Configuration.instance.getEncryptedToken() == null) {
  146. page = EmailEntryPage();
  147. } else {
  148. // No key
  149. if (Configuration.instance.getKeyAttributes() == null) {
  150. // Never had a key
  151. page = PasswordEntryPage();
  152. } else if (Configuration.instance.getKey() == null) {
  153. // Yet to decrypt the key
  154. page = PasswordReentryPage();
  155. } else {
  156. // All is well, user just has not subscribed
  157. page = getSubscriptionPage(isOnBoarding: true);
  158. }
  159. }
  160. Navigator.of(context).push(
  161. MaterialPageRoute(
  162. builder: (BuildContext context) {
  163. return page;
  164. },
  165. ),
  166. );
  167. }
  168. void _navigateToSignInPage() {
  169. Widget page;
  170. if (Configuration.instance.getEncryptedToken() == null) {
  171. page = LoginPage();
  172. } else {
  173. // No key
  174. if (Configuration.instance.getKeyAttributes() == null) {
  175. // Never had a key
  176. page = PasswordEntryPage();
  177. } else if (Configuration.instance.getKey() == null) {
  178. // Yet to decrypt the key
  179. page = PasswordReentryPage();
  180. } else {
  181. // All is well, user just has not subscribed
  182. page = getSubscriptionPage(isOnBoarding: true);
  183. }
  184. }
  185. Navigator.of(context).push(
  186. MaterialPageRoute(
  187. builder: (BuildContext context) {
  188. return page;
  189. },
  190. ),
  191. );
  192. }
  193. }
  194. class FeatureItemWidget extends StatelessWidget {
  195. final String assetPath,
  196. featureTitleFirstLine,
  197. featureTitleSecondLine,
  198. subText;
  199. const FeatureItemWidget(
  200. this.assetPath,
  201. this.featureTitleFirstLine,
  202. this.featureTitleSecondLine,
  203. this.subText, {
  204. Key key,
  205. }) : super(key: key);
  206. @override
  207. Widget build(BuildContext context) {
  208. return Column(
  209. crossAxisAlignment: CrossAxisAlignment.stretch,
  210. children: [
  211. Image.asset(
  212. assetPath,
  213. height: 160,
  214. ),
  215. Padding(padding: EdgeInsets.all(16)),
  216. Column(
  217. crossAxisAlignment: CrossAxisAlignment.center,
  218. mainAxisAlignment: MainAxisAlignment.start,
  219. children: [
  220. Text(
  221. featureTitleFirstLine,
  222. style: Theme.of(context).textTheme.headline5,
  223. ),
  224. Padding(padding: EdgeInsets.all(2)),
  225. Text(
  226. featureTitleSecondLine,
  227. style: Theme.of(context).textTheme.headline5,
  228. ),
  229. Padding(padding: EdgeInsets.all(12)),
  230. Text(
  231. subText,
  232. textAlign: TextAlign.center,
  233. style: TextStyle(
  234. color: Theme.of(context).colorScheme.onSurface.withOpacity(0.5),
  235. fontSize: 16,
  236. ),
  237. ),
  238. ],
  239. ),
  240. ],
  241. );
  242. }
  243. }