diff --git a/app/assets/fingerprint.svg b/app/assets/fingerprint.svg new file mode 100644 index 000000000..8773bff64 --- /dev/null +++ b/app/assets/fingerprint.svg @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/journey.svg b/app/assets/journey.svg new file mode 100644 index 000000000..7099a7ffd --- /dev/null +++ b/app/assets/journey.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/news.svg b/app/assets/news.svg new file mode 100644 index 000000000..66843c0be --- /dev/null +++ b/app/assets/news.svg @@ -0,0 +1,5034 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/tft.png b/app/assets/tft.png new file mode 100644 index 000000000..43d518239 Binary files /dev/null and b/app/assets/tft.png differ diff --git a/app/assets/tft.svg b/app/assets/tft.svg new file mode 100644 index 000000000..543c11fe5 --- /dev/null +++ b/app/assets/tft.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 7e85dbad9..4727f21da 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -42,6 +42,8 @@ PODS: - Flutter - url_launcher_ios (0.0.1): - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter DEPENDENCIES: - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) @@ -60,6 +62,7 @@ DEPENDENCIES: - sodium_libs (from `.symlinks/plugins/sodium_libs/ios`) - uni_links (from `.symlinks/plugins/uni_links/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) SPEC REPOS: trunk: @@ -100,6 +103,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/uni_links/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 @@ -121,6 +126,7 @@ SPEC CHECKSUMS: sodium_libs: 0486eb2c3172ce494406367d4b379042444b769d uni_links: d97da20c7701486ba192624d99bffaaffcfc298a url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe + webview_flutter_wkwebview: 2a23822e9039b7b1bc52e5add778e5d89ad488d1 PODFILE CHECKSUM: 2262097366c615de59b03ca3bf748d7aaad51773 diff --git a/app/lib/main.dart b/app/lib/main.dart index c858342a6..2e7e39942 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; import 'package:threebotlogin/helpers/globals.dart'; import 'package:threebotlogin/screens/splash_screen.dart'; import 'package:threebotlogin/services/shared_preference_service.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:threebotlogin/widgets/wizard/terms_agreement.dart'; extension ColorSchemeExtension on ColorScheme { Color get warning => brightness == Brightness.light @@ -37,7 +39,9 @@ Future main() async { await setGlobalValues(); bool registered = doubleName != null; - runApp(MyApp(initDone: initDone, registered: registered)); + runApp(ChangeNotifierProvider( + create: ((context) => TermsAgreement()), + child: MyApp(initDone: initDone, registered: registered))); } Future setGlobalValues() async { diff --git a/app/lib/screens/init_screen.dart b/app/lib/screens/init_screen.dart index f94b52810..92a07e0e6 100644 --- a/app/lib/screens/init_screen.dart +++ b/app/lib/screens/init_screen.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:threebotlogin/app_config.dart'; -import 'package:threebotlogin/services/shared_preference_service.dart'; +import 'package:threebotlogin/screens/wizard/swipe_page.dart'; class InitScreen extends StatefulWidget { const InitScreen({super.key}); @@ -11,56 +9,9 @@ class InitScreen extends StatefulWidget { } class _InitState extends State { - late InAppWebViewController webView; - late InAppWebView iaWebView; - - finish(List params) async { - print('**** LOAD DONE '); - saveInitDone(); - Navigator.pop(context, true); - } - - addHandler() { - webView.addJavaScriptHandler(handlerName: 'FINISH', callback: finish); - } - - _InitState() { - iaWebView = InAppWebView( - initialUrlRequest: URLRequest( - url: Uri.parse( - '${AppConfig().wizardUrl()}?cache_buster=${DateTime.now().millisecondsSinceEpoch}')), - initialOptions: InAppWebViewGroupOptions( - android: AndroidInAppWebViewOptions( - supportMultipleWindows: true, useHybridComposition: true), - ), - onWebViewCreated: (InAppWebViewController controller) { - webView = controller; - addHandler(); - }, - onCreateWindow: - (InAppWebViewController controller, CreateWindowAction req) { - return Future.value(true); - }, - onLoadStart: (InAppWebViewController controller, Uri? url) {}, - onLoadStop: (InAppWebViewController controller, Uri? url) async {}, - onProgressChanged: (InAppWebViewController controller, int progress) {}, - ); - } - - @override - void initState() { - super.initState(); - } - - @override - void dispose() { - super.dispose(); - } @override Widget build(BuildContext context) { - return MaterialApp( - home: SafeArea(child: iaWebView), - ); + return const Scaffold(body: SafeArea(child: SwipePage())); } } diff --git a/app/lib/screens/wizard/page1.dart b/app/lib/screens/wizard/page1.dart new file mode 100644 index 000000000..7dce47259 --- /dev/null +++ b/app/lib/screens/wizard/page1.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:threebotlogin/widgets/wizard/common_page.dart'; + +class Page1 extends StatelessWidget { + const Page1({super.key}); + + @override + Widget build(BuildContext context) { + return const CommonPage( + title: 'Welcome to', + subtitle: '', + imagePath: 'assets/TF_log_horizontal.svg', + widthPercentage: 0.75, + heightPercentage: 0.2, + description: + 'Threefold Connect is your main access point to the Threefold Grid and more. Please allow us to quickly show you around!', + ); + } +} diff --git a/app/lib/screens/wizard/page2.dart b/app/lib/screens/wizard/page2.dart new file mode 100644 index 000000000..0f09fbe23 --- /dev/null +++ b/app/lib/screens/wizard/page2.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:threebotlogin/widgets/wizard/common_page.dart'; + +class Page2 extends StatelessWidget { + const Page2({super.key}); + + @override + Widget build(BuildContext context) { + return const CommonPage( + title: 'MAXIMUM', + subtitle: 'SECURITY', + imagePath: 'assets/fingerprint.svg', + widthPercentage: 0.75, + heightPercentage: 0.5, + description: + 'The app provides a secure authentication mechanism that provides your identity on the Threefold Grid.', + ); + } +} diff --git a/app/lib/screens/wizard/page3.dart b/app/lib/screens/wizard/page3.dart new file mode 100644 index 000000000..ca54e4046 --- /dev/null +++ b/app/lib/screens/wizard/page3.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:threebotlogin/widgets/wizard/common_page.dart'; + +class Page3 extends StatelessWidget { + const Page3({super.key}); + + @override + Widget build(BuildContext context) { + return const CommonPage( + title: 'THREEFOLD', + subtitle: 'WALLET', + imagePath: 'assets/tft.png', + description: + 'Access your ThreeFold Wallet and your ThreeFold Tokens (TFT). More currencies are to be added in the future.', + heightPercentage: 0.4, + widthPercentage: 0.75, + ); + } +} diff --git a/app/lib/screens/wizard/page4.dart b/app/lib/screens/wizard/page4.dart new file mode 100644 index 000000000..2622d5641 --- /dev/null +++ b/app/lib/screens/wizard/page4.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:threebotlogin/widgets/wizard/common_page.dart'; + +class Page4 extends StatelessWidget { + const Page4({super.key}); + + @override + Widget build(BuildContext context) { + return const CommonPage( + title: 'THREEFOLD', + subtitle: 'NEWS', + imagePath: 'assets/news.svg', + description: + "Stay updated with ThreeFold's latest updates via the News section within the app.", + heightPercentage: 0.5, + widthPercentage: 0.8, + ); + } +} diff --git a/app/lib/screens/wizard/page5.dart b/app/lib/screens/wizard/page5.dart new file mode 100644 index 000000000..8255fc461 --- /dev/null +++ b/app/lib/screens/wizard/page5.dart @@ -0,0 +1,154 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:provider/provider.dart'; +import 'package:threebotlogin/screens/main_screen.dart'; +import 'package:threebotlogin/screens/wizard/web_view.dart'; +import 'package:threebotlogin/services/shared_preference_service.dart'; +import 'package:threebotlogin/widgets/wizard/terms_agreement.dart'; + +class Page5 extends StatefulWidget { + const Page5({super.key}); + + @override + State createState() => _Page5State(); +} + +class _Page5State extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: MediaQuery.of(context).size.height * 0.25, + child: SvgPicture.asset( + 'assets/journey.svg', + alignment: Alignment.center, + ), + ), + SizedBox( + height: MediaQuery.of(context).size.height * 0.02, + ), + Column(children: [ + Text( + 'STARTYOUR', + style: Theme.of(context).textTheme.displayMedium!.copyWith( + color: Theme.of(context).colorScheme.onBackground, + fontWeight: FontWeight.bold, + ), + ), + Text( + 'THREEFOLD', + style: Theme.of(context).textTheme.displayMedium!.copyWith( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, + ), + ), + Text( + 'JOURNEY', + style: Theme.of(context).textTheme.displayMedium!.copyWith( + color: Theme.of(context).colorScheme.onBackground, + fontWeight: FontWeight.bold, + ), + ), + Padding( + padding: const EdgeInsets.all(10), + child: ElevatedButton( + onPressed: () async { + final termsAgreement = + Provider.of(context, listen: false); + if (!termsAgreement.isChecked) { + termsAgreement.attemptToContinue(); + } else { + saveInitDone(); + await Navigator.of(context).push(MaterialPageRoute( + builder: (context) => const MainScreen( + initDone: true, + registered: false, + ))); + } + }, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + backgroundColor: Theme.of(context).colorScheme.primary, + ), + child: Text( + 'GET STARTED', + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Theme.of(context).colorScheme.onPrimary), + )), + ), + Consumer( + builder: (context, termsAgreement, child) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Checkbox( + value: termsAgreement.isChecked, + onChanged: (bool? value) { + termsAgreement.toggleChecked(value ?? false); + }, + ), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "I agree to Threefold's ", + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: termsAgreement + .attemptedWithoutAccepting && + !termsAgreement.isChecked + ? Theme.of(context).colorScheme.error + : Theme.of(context) + .colorScheme + .onBackground, + ), + ), + TextSpan( + text: 'Terms and conditions.', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: termsAgreement + .attemptedWithoutAccepting && + !termsAgreement.isChecked + ? Theme.of(context).colorScheme.error + : Colors.blue, + decoration: TextDecoration.underline, + decorationColor: termsAgreement + .attemptedWithoutAccepting && + !termsAgreement.isChecked + ? Theme.of(context).colorScheme.error + : Colors.blue, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const WebView()), + ); + }, + ), + ], + ), + ), + ], + ); + }) + ]) + ], + ), + ), + ); + } +} diff --git a/app/lib/screens/wizard/swipe_page.dart b/app/lib/screens/wizard/swipe_page.dart new file mode 100644 index 000000000..38b6560dc --- /dev/null +++ b/app/lib/screens/wizard/swipe_page.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:smooth_page_indicator/smooth_page_indicator.dart'; +import 'package:threebotlogin/screens/wizard/page1.dart'; +import 'package:threebotlogin/screens/wizard/page2.dart'; +import 'package:threebotlogin/screens/wizard/page3.dart'; +import 'package:threebotlogin/screens/wizard/page4.dart'; +import 'package:threebotlogin/screens/wizard/page5.dart'; + +import '../../widgets/wizard/terms_and_conditions.dart'; + +class SwipePage extends StatefulWidget { + const SwipePage({super.key}); + + @override + State createState() => _SwipePagesState(); +} + +class _SwipePagesState extends State { + final PageController _pageController = + PageController(); // Controls the PageView + + @override + void dispose() { + _pageController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Padding( + padding: + EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.01), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return const TermsAndConditions(); + }, + ); + }, + child: Text( + 'SKIP', + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Theme.of(context).colorScheme.onBackground), + )) + ], + ), + ), + Expanded( + child: PageView( + controller: _pageController, + onPageChanged: (int index) { + setState(() {}); + }, + children: const [Page1(), Page2(), Page3(), Page4(), Page5()], + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16, bottom: 16), + child: Column( + children: [ + SmoothPageIndicator( + controller: _pageController, + count: 5, + effect: ExpandingDotsEffect( + dotWidth: 20, + dotHeight: 20, + activeDotColor: Theme.of(context).colorScheme.primary, + dotColor: Theme.of(context).colorScheme.outline, + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/app/lib/screens/wizard/web_view.dart b/app/lib/screens/wizard/web_view.dart new file mode 100644 index 000000000..1815848d2 --- /dev/null +++ b/app/lib/screens/wizard/web_view.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class WebView extends StatefulWidget { + const WebView({super.key}); + + @override + State createState() => _WebViewState(); +} + +class _WebViewState extends State { + bool isLoading = true; + late WebViewController controller; + + @override + void dispose() { + super.dispose(); + } + + @override + void initState() { + super.initState(); + controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setNavigationDelegate( + NavigationDelegate( + onPageFinished: (url) { + setState(() { + isLoading = false; + }); + }, + onWebResourceError: (error) { + print('Error loading: ${error.description}'); + }, + ), + ) + ..loadRequest(Uri.parse('https://library.threefold.me/info/legal/')); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Terms & Conditions'), + ), + body: Stack( + children: [ + WebViewWidget(controller: controller), + if (isLoading) const Center(child: CircularProgressIndicator()), + ], + ), + ); + } +} diff --git a/app/lib/widgets/wizard/common_page.dart b/app/lib/widgets/wizard/common_page.dart new file mode 100644 index 000000000..37b1e3b23 --- /dev/null +++ b/app/lib/widgets/wizard/common_page.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +class CommonPage extends StatefulWidget { + final String title; + final String subtitle; + final String imagePath; + final String description; + final double? heightPercentage; + final double? widthPercentage; + + const CommonPage({ + Key? key, + required this.title, + required this.subtitle, + required this.imagePath, + required this.description, + this.heightPercentage = 100, + this.widthPercentage = 300, + }) : super(key: key); + + @override + State createState() => _CommonPageState(); +} + +class _CommonPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + children: [ + SizedBox( + height: MediaQuery.of(context).size.width * 0.9, + child: Column(children: [ + Text( + widget.title, + style: Theme.of(context).textTheme.displayMedium!.copyWith( + color: Theme.of(context).colorScheme.onBackground, + fontWeight: FontWeight.bold, + ), + ), + if (widget.subtitle.isNotEmpty) + Text( + widget.subtitle, + style: Theme.of(context).textTheme.displayMedium!.copyWith( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, + ), + ), + widget.imagePath.endsWith('.svg') + ? SizedBox( + width: widget.widthPercentage != null + ? MediaQuery.of(context).size.width * + widget.widthPercentage! + : null, + height: widget.heightPercentage != null + ? MediaQuery.of(context).size.width * + widget.heightPercentage! + : null, + child: SvgPicture.asset( + widget.imagePath, + alignment: Alignment.center, + colorFilter: ColorFilter.mode( + Theme.of(context).colorScheme.onBackground, + BlendMode.srcIn, + ), + ), + ) + : SizedBox( + width: widget.widthPercentage != null + ? MediaQuery.of(context).size.width * + widget.widthPercentage! + : null, + height: widget.heightPercentage != null + ? MediaQuery.of(context).size.width * + widget.heightPercentage! + : null, + child: Image.asset( + widget.imagePath, + fit: BoxFit.contain, + ), + ), + ]), + ), + SizedBox( + width: MediaQuery.of(context).size.width - 100, + height: MediaQuery.of(context).size.height * 0.2, + child: Text( + widget.description, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Theme.of(context).colorScheme.onBackground, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + ); + } +} diff --git a/app/lib/widgets/wizard/terms_agreement.dart b/app/lib/widgets/wizard/terms_agreement.dart new file mode 100644 index 000000000..b3f66c16c --- /dev/null +++ b/app/lib/widgets/wizard/terms_agreement.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class TermsAgreement with ChangeNotifier { + bool _isChecked = false; + bool _attemptedWithoutAccepting = false; + + bool get isChecked => _isChecked; + bool get attemptedWithoutAccepting => _attemptedWithoutAccepting; + + void toggleChecked(bool value) { + _isChecked = value; + _attemptedWithoutAccepting = false; + notifyListeners(); + } + + void attemptToContinue() { + _attemptedWithoutAccepting = true; + notifyListeners(); + } +} diff --git a/app/lib/widgets/wizard/terms_and_conditions.dart b/app/lib/widgets/wizard/terms_and_conditions.dart new file mode 100644 index 000000000..e9f450935 --- /dev/null +++ b/app/lib/widgets/wizard/terms_and_conditions.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:threebotlogin/screens/main_screen.dart'; +import 'package:threebotlogin/screens/wizard/web_view.dart'; +import 'package:threebotlogin/services/shared_preference_service.dart'; +import 'package:threebotlogin/widgets/custom_dialog.dart'; +import 'package:threebotlogin/widgets/wizard/terms_agreement.dart'; + +class TermsAndConditions extends StatefulWidget { + const TermsAndConditions({Key? key}) : super(key: key); + + @override + State createState() => _TermsAndConditionsState(); +} + +class _TermsAndConditionsState extends State { + @override + Widget build(BuildContext context) { + return CustomDialog( + title: 'Accept the terms and conditions?', + widgetDescription: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Before you can start using the app, you must accept the Terms and Conditions.', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: Theme.of(context).colorScheme.onBackground)), + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const WebView()), + ); + }, + child: Text('Terms and Conditions', + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Colors.blue, + decoration: TextDecoration.underline, + decorationColor: Colors.blue)), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.01), + Consumer(builder: (context, termsAgreement, child) { + return Row( + children: [ + Checkbox( + value: termsAgreement.isChecked, + onChanged: (bool? value) { + termsAgreement.toggleChecked(value ?? false); + }, + ), + Expanded( + child: Text('I Accept the terms and conditions.', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: termsAgreement.attemptedWithoutAccepting && + !termsAgreement.isChecked + ? Theme.of(context).colorScheme.error + : Theme.of(context).colorScheme.onBackground)), + ), + ], + ); + }) + ], + ), + ), + actions: [ + TextButton( + onPressed: () async { + final termsAgreement = + Provider.of(context, listen: false); + if (!termsAgreement.isChecked) { + termsAgreement.attemptToContinue(); + } else { + saveInitDone(); + Navigator.of(context).pop(); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const MainScreen( + initDone: true, + registered: false, + ))); + } + }, + child: const Text('Continue'), + ), + ], + ); + } +} diff --git a/app/pubspec.lock b/app/pubspec.lock index 41a4285f6..1531e0374 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -656,6 +656,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1+beta.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" open_filex: dependency: "direct main" description: @@ -888,6 +896,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" pub_semver: dependency: transitive description: @@ -1142,6 +1158,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + smooth_page_indicator: + dependency: "direct main" + description: + name: smooth_page_indicator + sha256: "3b28b0c545fa67ed9e5997d9f9720d486f54c0c607e056a1094544e36934dff3" + url: "https://pub.dev" + source: hosted + version: "1.2.0+3" socket_io_client: dependency: "direct main" description: @@ -1217,9 +1241,11 @@ packages: stellar_client: dependency: "direct main" description: - path: "../../../codescalers/tfgrid-sdk-dart/packages/stellar_client" - relative: true - source: path + path: "packages/stellar_client" + ref: tfchain_graphql_hotfix_2 + resolved-ref: "563cc0297d79dc333157fe69a7540f0190ff3496" + url: "https://github.com/codescalers/tfgrid-sdk-dart" + source: git version: "0.1.0" stellar_flutter_sdk: dependency: transitive @@ -1532,6 +1558,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522" + url: "https://pub.dev" + source: hosted + version: "4.8.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: "0d21cfc3bfdd2e30ab2ebeced66512b91134b39e72e97b43db2d47dda1c4e53a" + url: "https://pub.dev" + source: hosted + version: "3.16.3" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb" + url: "https://pub.dev" + source: hosted + version: "3.14.0" win32: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index df049d7cd..ad6d23cb6 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: stellar_client: git: url: https://github.com/codescalers/tfgrid-sdk-dart - ref: tfchain_graphql_hotfix + ref: tfchain_graphql_hotfix_2 path: packages/stellar_client gridproxy_client: git: @@ -59,6 +59,9 @@ dependencies: pinenacl: ^0.5.1 pinput: 3.0.1 build_runner: ^2.4.9 + smooth_page_indicator: ^1.2.0+3 + webview_flutter: ^4.8.0 + provider: ^6.1.2 qr_flutter: ^4.1.0 screen_brightness: ^1.0.1 validators: ^3.0.0