From 8e727ff999e12a528555af68c2e4c522251b9bf7 Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 9 Oct 2022 13:28:39 -0600 Subject: [PATCH 1/2] delete account ui for ios --- lib/pages/intro_view.dart | 2 + .../delete_account_view.dart | 75 +++++++++++++++++++ .../global_settings_view.dart | 17 +++++ lib/route_generator.dart | 14 ++++ 4 files changed, 108 insertions(+) create mode 100644 lib/pages/settings_views/global_settings_view/delete_account_view.dart diff --git a/lib/pages/intro_view.dart b/lib/pages/intro_view.dart index ca8725886..17ee90f1d 100644 --- a/lib/pages/intro_view.dart +++ b/lib/pages/intro_view.dart @@ -12,6 +12,8 @@ import 'package:url_launcher/url_launcher.dart'; class IntroView extends StatefulWidget { const IntroView({Key? key}) : super(key: key); + static const String routeName = "/introView"; + @override State createState() => _IntroViewState(); } diff --git a/lib/pages/settings_views/global_settings_view/delete_account_view.dart b/lib/pages/settings_views/global_settings_view/delete_account_view.dart new file mode 100644 index 000000000..5fdabf6ad --- /dev/null +++ b/lib/pages/settings_views/global_settings_view/delete_account_view.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/pages/intro_view.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; +import 'package:stackwallet/widgets/desktop/primary_button.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; + +class DeleteAccountView extends StatefulWidget { + const DeleteAccountView({Key? key}) : super(key: key); + + static const String routeName = "/deleteAccountView"; + + @override + State createState() => _DeleteAccountViewState(); +} + +class _DeleteAccountViewState extends State { + final isDesktop = Util.isDesktop; + + Future onConfirmDeleteAccount() async { + // TODO delete everything then pop to intro view + await Navigator.of(context).pushNamedAndRemoveUntil( + IntroView.routeName, + (route) => false, + ); + } + + @override + Widget build(BuildContext context) { + return MasterScaffold( + isDesktop: isDesktop, + appBar: isDesktop + ? DesktopAppBar(isCompactHeight: true) + : AppBar( + leading: AppBarBackButton( + onPressed: () async { + if (FocusScope.of(context).hasFocus) { + FocusScope.of(context).unfocus(); + await Future.delayed( + const Duration(milliseconds: 75)); + } + if (mounted) { + Navigator.of(context).pop(); + } + }, + ), + title: Text( + "Delete account", + style: STextStyles.navBarTitle(context), + ), + ), + body: Padding( + padding: const EdgeInsets.all(14), + child: Column( + children: [ + RoundedWhiteContainer( + child: Text( + "There is no account to delete, but Apple requires that we have a way to 'delete accounts' in the app and will reject our app updates if we don't, so here it is. Clicking this will delete all app data (not from our servers, because we never had it in the first place).\n\nWhen you click confirm, all app data will be deleted, including wallets and preferences, and you will be taken back to the very first onboarding screen. BE SURE TO BACKUP ALL SEEDS!!\n\nAre you sure you want to delete your \"account\"?", + style: STextStyles.smallMed12(context), + ), + ), + const Spacer(), + PrimaryButton( + label: "Confirm", + onPressed: onConfirmDeleteAccount, + ) + ], + ), + ), + ); + } +} diff --git a/lib/pages/settings_views/global_settings_view/global_settings_view.dart b/lib/pages/settings_views/global_settings_view/global_settings_view.dart index 1b334cf18..85e71f44f 100644 --- a/lib/pages/settings_views/global_settings_view/global_settings_view.dart +++ b/lib/pages/settings_views/global_settings_view/global_settings_view.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:stackwallet/pages/address_book_views/address_book_view.dart'; import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; @@ -5,6 +7,7 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/about_view import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_views/advanced_settings_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/appearance_settings_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/currency_view.dart'; +import 'package:stackwallet/pages/settings_views/global_settings_view/delete_account_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/language_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/security_views/security_view.dart'; @@ -224,6 +227,20 @@ class GlobalSettingsView extends StatelessWidget { .pushNamed(SupportView.routeName); }, ), + if (Platform.isIOS) + const SizedBox( + height: 8, + ), + if (Platform.isIOS) + SettingsListButton( + iconAssetName: Assets.svg.circleAlert, + iconSize: 16, + title: "Delete account", + onPressed: () async { + await Navigator.of(context) + .pushNamed(DeleteAccountView.routeName); + }, + ), // TextButton( // style: Theme.of(context) // .textButtonTheme diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 368188171..2529a1e39 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -33,6 +33,7 @@ import 'package:stackwallet/pages/exchange_view/send_from_view.dart'; import 'package:stackwallet/pages/exchange_view/trade_details_view.dart'; import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; +import 'package:stackwallet/pages/intro_view.dart'; import 'package:stackwallet/pages/manage_favorites_view/manage_favorites_view.dart'; import 'package:stackwallet/pages/notification_views/notifications_view.dart'; import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart'; @@ -43,6 +44,7 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_v import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_views/debug_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/appearance_settings_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/currency_view.dart'; +import 'package:stackwallet/pages/settings_views/global_settings_view/delete_account_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/global_settings_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/hidden_settings.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/language_view.dart'; @@ -97,6 +99,18 @@ class RouteGenerator { final args = settings.arguments; switch (settings.name) { + case IntroView.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const IntroView(), + settings: RouteSettings(name: settings.name)); + + case DeleteAccountView.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DeleteAccountView(), + settings: RouteSettings(name: settings.name)); + case HomeView.routeName: return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, From bf27f38bb51c799d0bf5829999f77fbc6c319c6c Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 11 Oct 2022 08:15:51 -0600 Subject: [PATCH 2/2] WIP startup privacy options page layout --- lib/pages/stack_privacy_calls.dart | 260 +++++++++++++++++++++++------ lib/utilities/prefs.dart | 25 +++ 2 files changed, 236 insertions(+), 49 deletions(-) diff --git a/lib/pages/stack_privacy_calls.dart b/lib/pages/stack_privacy_calls.dart index c16e9d741..6f971408a 100644 --- a/lib/pages/stack_privacy_calls.dart +++ b/lib/pages/stack_privacy_calls.dart @@ -2,15 +2,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; -import 'package:stackwallet/hive/db.dart'; -import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/util.dart'; - class StackPrivacyCalls extends ConsumerStatefulWidget { const StackPrivacyCalls({ Key? key, @@ -73,55 +73,66 @@ class _StackPrivacyCalls extends ConsumerState { const SizedBox( height: 36, ), - Center( - child: CustomRadio((bool isEasy) { - setState(() { - this.isEasy = isEasy; - - DB.instance.put( - boxName: DB.boxNamePrefs, - key: "externalCalls", - value: isEasy); - }); - }), + const Padding( + padding: EdgeInsets.symmetric( + horizontal: 16, + ), + child: PrivacyToggle(), ), + // Center( + // child: CustomRadio((bool isEasy) { + // setState(() { + // this.isEasy = isEasy; + // + // DB.instance.put( + // boxName: DB.boxNamePrefs, + // key: "externalCalls", + // value: isEasy); + // }); + // }), + // ), const SizedBox( height: 36, ), - RoundedWhiteContainer( - child: Center( - child: RichText( - textAlign: TextAlign.left, - text: TextSpan( - style: - STextStyles.label(context).copyWith(fontSize: 12.0), - children: isEasy - ? const [ - TextSpan( - text: - "Exchange data preloaded for a seamless experience."), - TextSpan( - text: - "\n\nCoinGecko enabled: (24 hour price change shown in-app, total wallet value shown in USD or other currency)."), - TextSpan( - text: - "\n\nRecommended for most crypto users.", - style: - TextStyle(fontWeight: FontWeight.bold)), - ] - : const [ - TextSpan( - text: - "Exchange data not preloaded (slower experience)."), - TextSpan( - text: - "\n\nCoinGecko disabled (price changes not shown, no wallet value shown in other currencies)."), - TextSpan( - text: - "\n\nRecommended for the privacy conscious.", - style: - TextStyle(fontWeight: FontWeight.bold)), - ], + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + ), + child: RoundedWhiteContainer( + child: Center( + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: STextStyles.label(context) + .copyWith(fontSize: 12.0), + children: isEasy + ? const [ + TextSpan( + text: + "Exchange data preloaded for a seamless experience."), + TextSpan( + text: + "\n\nCoinGecko enabled: (24 hour price change shown in-app, total wallet value shown in USD or other currency)."), + TextSpan( + text: + "\n\nRecommended for most crypto users.", + style: TextStyle( + fontWeight: FontWeight.bold)), + ] + : const [ + TextSpan( + text: + "Exchange data not preloaded (slower experience)."), + TextSpan( + text: + "\n\nCoinGecko disabled (price changes not shown, no wallet value shown in other currencies)."), + TextSpan( + text: + "\n\nRecommended for the privacy conscious.", + style: TextStyle( + fontWeight: FontWeight.bold)), + ], + ), ), ), ), @@ -153,6 +164,157 @@ class _StackPrivacyCalls extends ConsumerState { } } +class PrivacyToggle extends ConsumerStatefulWidget { + const PrivacyToggle({Key? key}) : super(key: key); + + @override + ConsumerState createState() => _PrivacyToggleState(); +} + +class _PrivacyToggleState extends ConsumerState { + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: RawMaterialButton( + fillColor: Theme.of(context).extension()!.popupBG, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius * 2, + ), + ), + onPressed: () { + ref.read(prefsChangeNotifierProvider).externalCalls = true; + }, + child: Padding( + padding: const EdgeInsets.all( + 12, + ), + child: Column( + children: [ + SvgPicture.asset( + Assets.svg.personaEasy, + // color: Theme.of(context).extension()!.textWhite, + width: 96, + height: 96, + ), + const Text( + "Easy Crypto", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + const Text( + "Recommended", + ), + ], + ), + ), + ), + ), + const SizedBox( + width: 16, + ), + Expanded( + child: RawMaterialButton( + elevation: 0, + fillColor: Theme.of(context).extension()!.popupBG, + shape: RoundedRectangleBorder( + side: ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.externalCalls, + ), + ) + ? BorderSide.none + : BorderSide( + color: Theme.of(context) + .extension()! + .infoItemIcons, + width: 2, + ), + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius * 2, + ), + ), + onPressed: () { + ref.read(prefsChangeNotifierProvider).externalCalls = false; + }, + child: Padding( + padding: const EdgeInsets.all( + 12, + ), + child: Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SvgPicture.asset( + Assets.svg.personaIncognito, + width: 96, + height: 96, + ), + const Center( + child: Text( + "Incognito", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + const Center( + child: Text( + "Privacy conscious", + ), + ), + ], + ), + if (!ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.externalCalls, + ), + )) + Positioned( + top: 4, + right: 4, + child: SvgPicture.asset( + Assets.svg.checkCircle, + width: 20, + height: 20, + color: Theme.of(context) + .extension()! + .infoItemIcons, + ), + ), + if (ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.externalCalls, + ), + )) + Positioned( + top: 4, + right: 4, + child: Container( + width: 20, + height: 20, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(1000), + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, + ), + ), + ), + ], + ), + ), + ), + ), + ], + ); + } +} + class ContinueButton extends StatelessWidget { const ContinueButton({Key? key, required this.isDesktop}) : super(key: key); diff --git a/lib/utilities/prefs.dart b/lib/utilities/prefs.dart index 578cf35a4..7e1096550 100644 --- a/lib/utilities/prefs.dart +++ b/lib/utilities/prefs.dart @@ -36,6 +36,7 @@ class Prefs extends ChangeNotifier { _hideBlockExplorerWarning = await _getHideBlockExplorerWarning(); _gotoWalletOnStartup = await _getGotoWalletOnStartup(); _startupWalletId = await _getStartupWalletId(); + _externalCalls = await _getHasExternalCalls(); _initialized = true; } @@ -544,4 +545,28 @@ class Prefs extends ChangeNotifier { return await DB.instance.get( boxName: DB.boxNamePrefs, key: "startupWalletId") as String?; } + + bool _externalCalls = false; + + bool get externalCalls => _externalCalls; + + set externalCalls(bool externalCalls) { + if (_externalCalls != externalCalls) { + DB.instance + .put( + boxName: DB.boxNamePrefs, + key: "externalCalls", + value: externalCalls) + .then((_) { + _externalCalls = externalCalls; + notifyListeners(); + }); + } + } + + Future _getHasExternalCalls() async { + return await DB.instance.get( + boxName: DB.boxNamePrefs, key: "externalCalls") as bool? ?? + false; + } }