landing_page_widget.dart 7.6 KB

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