diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt new file mode 100644 index 000000000..6a091fc90 --- /dev/null +++ b/assets/text/Monerocom_Release_Notes.txt @@ -0,0 +1,13 @@ +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges +WWEE(enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate) +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Keep screen awake while the synchronization function +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate) +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Keep screen awake while the synchronization function +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate) +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Keep screen awake while the synchronizatio \ No newline at end of file diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt new file mode 100644 index 000000000..6a091fc90 --- /dev/null +++ b/assets/text/Release_Notes.txt @@ -0,0 +1,13 @@ +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges +WWEE(enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate) +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Keep screen awake while the synchronization function +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate) +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Keep screen awake while the synchronization function +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate) +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Changed algorithm for choosing of change address for BTC and LTC electrum wallets +Keep screen awake while the synchronizatio \ No newline at end of file diff --git a/lib/di.dart b/lib/di.dart index 584bc8b8e..d1b4bda42 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -208,7 +208,7 @@ Future setup( required Box transactionDescriptionBox, required Box ordersSource, Box? unspentCoinsInfoSource, - required Box anonpayInvoiceInfoSource + required Box anonpayInvoiceInfoSource, }) async { _walletInfoSource = walletInfoSource; _nodeSource = nodeSource; @@ -396,6 +396,7 @@ Future setup( dashboardViewModel: getIt.get(), addressListViewModel: getIt.get(), )); + getIt.registerFactory(() { final GlobalKey _navigatorKey = GlobalKey(); return DesktopSidebarWrapper( diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index a1a35125b..77298c2b5 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -42,6 +42,13 @@ Future defaultSettingsMigration( // check current nodes for nullability regardless of the version await checkCurrentNodes(nodes, sharedPreferences); + final isNewInstall = sharedPreferences + .getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null; + + await sharedPreferences.setBool( + PreferencesKey.isNewInstall, isNewInstall); + + final currentVersion = sharedPreferences .getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) ?? 0; diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index f5741a98b..90b57668d 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -41,6 +41,8 @@ class PreferencesKey { static const exchangeProvidersSelection = 'exchange-providers-selection'; static const clearnetDonationLink = 'clearnet_donation_link'; - static const onionDonationLink = 'onion_donation_link'; + static const onionDonationLink = 'onion_donation_link'; + static const lastSeenAppVersion = 'last_seen_app_version'; static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard'; + static const isNewInstall = 'is_new_install'; } diff --git a/lib/main.dart b/lib/main.dart index 8cc2629c9..53ec3fb65 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -187,8 +187,7 @@ Future initialSetup( transactionDescriptionBox: transactionDescriptions, ordersSource: ordersSource, anonpayInvoiceInfoSource: anonpayInvoiceInfo, - unspentCoinsInfoSource: unspentCoinsInfoSource, - ); + unspentCoinsInfoSource: unspentCoinsInfoSource); await bootstrap(navigatorKey); monero?.onStartup(); } diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index fbd976aa8..a76b93fc0 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -1,8 +1,10 @@ import 'dart:async'; +import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/entities/main_actions.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart'; +import 'package:cake_wallet/utils/version_comparator.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; @@ -22,8 +24,12 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:cake_wallet/main.dart'; +import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart'; class DashboardPage extends StatelessWidget { DashboardPage({ @@ -117,7 +123,7 @@ class _DashboardPageView extends BasePage { @override Widget body(BuildContext context) { final controller = PageController(initialPage: initialPage); - + reaction((_) => dashboardViewModel.shouldShowMarketPlaceInDashboard, (bool value) { if (!dashboardViewModel.shouldShowMarketPlaceInDashboard) { controller.jumpToPage(0); @@ -131,7 +137,7 @@ class _DashboardPageView extends BasePage { } else { controller.jumpToPage(0); } - }); + }); _setEffects(context); return SafeArea( @@ -266,6 +272,25 @@ class _DashboardPageView extends BasePage { } }); + final sharedPrefs = await SharedPreferences.getInstance(); + final currentAppVersion = + VersionComparator.getExtendedVersionNumber(dashboardViewModel.settingsStore.appVersion); + final lastSeenAppVersion = sharedPrefs.getInt(PreferencesKey.lastSeenAppVersion); + final isNewInstall = sharedPrefs.getBool(PreferencesKey.isNewInstall); + + if (currentAppVersion != lastSeenAppVersion && !isNewInstall!) { + await Future.delayed(Duration(seconds: 1)); + await showPopUp( + context: context, + builder: (BuildContext context) { + return ReleaseNotesScreen( + title: 'Version ${dashboardViewModel.settingsStore.appVersion}'); + }); + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); + } else if (isNewInstall!) { + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); + } + var needToPresentYat = false; var isInactive = false; diff --git a/lib/src/screens/dashboard/desktop_dashboard_page.dart b/lib/src/screens/dashboard/desktop_dashboard_page.dart index 64f8a9aac..df74a3f6f 100644 --- a/lib/src/screens/dashboard/desktop_dashboard_page.dart +++ b/lib/src/screens/dashboard/desktop_dashboard_page.dart @@ -1,9 +1,12 @@ import 'dart:async'; +import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart'; import 'package:cake_wallet/src/screens/yat_emoji_id.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/utils/version_comparator.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart'; @@ -11,6 +14,7 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_v import 'package:mobx/mobx.dart'; import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/router.dart' as Router; +import 'package:shared_preferences/shared_preferences.dart'; class DesktopDashboardPage extends StatelessWidget { DesktopDashboardPage({ @@ -107,5 +111,24 @@ class DesktopDashboardPage extends StatelessWidget { needToPresentYat = true; }); + + final sharedPrefs = await SharedPreferences.getInstance(); + final currentAppVersion = + VersionComparator.getExtendedVersionNumber(dashboardViewModel.settingsStore.appVersion); + final lastSeenAppVersion = sharedPrefs.getInt(PreferencesKey.lastSeenAppVersion); + final isNewInstall = sharedPrefs.getBool(PreferencesKey.isNewInstall); + + if (currentAppVersion != lastSeenAppVersion && !isNewInstall!) { + await Future.delayed(Duration(seconds: 1)); + await showPopUp( + context: context, + builder: (BuildContext context) { + return ReleaseNotesScreen( + title: 'Version ${dashboardViewModel.settingsStore.appVersion}'); + }); + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); + } else if (isNewInstall!) { + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); + } } } diff --git a/lib/src/screens/dashboard/widgets/filter_widget.dart b/lib/src/screens/dashboard/widgets/filter_widget.dart index 17df0bc5e..9b8c87ea3 100644 --- a/lib/src/screens/dashboard/widgets/filter_widget.dart +++ b/lib/src/screens/dashboard/widgets/filter_widget.dart @@ -16,7 +16,6 @@ class FilterWidget extends StatelessWidget { FilterWidget({required this.dashboardViewModel}); final DashboardViewModel dashboardViewModel; - final closeIcon = Image.asset('assets/images/close.png', color: Palette.darkBlueCraiola); @override Widget build(BuildContext context) { @@ -101,7 +100,7 @@ class FilterWidget extends StatelessWidget { ), ], ), - AlertCloseButton(image: closeIcon) + AlertCloseButton() ], ), ); diff --git a/lib/src/screens/monero_accounts/monero_account_list_page.dart b/lib/src/screens/monero_accounts/monero_account_list_page.dart index 7fe15948f..145a2d8a4 100644 --- a/lib/src/screens/monero_accounts/monero_account_list_page.dart +++ b/lib/src/screens/monero_accounts/monero_account_list_page.dart @@ -27,9 +27,6 @@ class MoneroAccountListPage extends StatelessWidget { } final MoneroAccountListViewModel accountListViewModel; - final closeIcon = Image.asset('assets/images/close.png', - color: Palette.darkBlueCraiola, - ); ScrollController controller; double backgroundHeight; @@ -163,7 +160,7 @@ class MoneroAccountListPage extends StatelessWidget { ) ], ), - AlertCloseButton(image: closeIcon) + AlertCloseButton() ], ), ); diff --git a/lib/src/screens/release_notes/release_notes_screen.dart b/lib/src/screens/release_notes/release_notes_screen.dart new file mode 100644 index 000000000..f8b3730fb --- /dev/null +++ b/lib/src/screens/release_notes/release_notes_screen.dart @@ -0,0 +1,141 @@ +import 'dart:convert'; +import 'package:cake_wallet/src/widgets/alert_background.dart'; +import 'package:cake_wallet/src/widgets/alert_close_button.dart'; +import 'package:cake_wallet/wallet_type_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class ReleaseNotesScreen extends StatelessWidget { + const ReleaseNotesScreen({ + required this.title, + }); + + final String title; + + Future> _loadStrings() async { + String notesContent = await rootBundle.loadString( + isMoneroOnly ? 'assets/text/Monerocom_Release_Notes.txt' : 'assets/text/Release_Notes.txt'); + return LineSplitter().convert(notesContent); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + AlertBackground( + child: AlertDialog( + insetPadding: EdgeInsets.only(left: 16, right: 16, bottom: 48), + elevation: 0.0, + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30))), + content: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30.0), + gradient: LinearGradient(colors: [ + Theme.of(context).colorScheme.secondary, + Theme.of(context).scaffoldBackgroundColor, + ], begin: Alignment.centerLeft, end: Alignment.centerRight)), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Stack( + children: [ + SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Container( + alignment: Alignment.bottomCenter, + child: DefaultTextStyle( + style: TextStyle( + decoration: TextDecoration.none, + fontSize: 24.0, + fontWeight: FontWeight.bold, + fontFamily: 'Lato', + color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!, + ), + child: Text(title), + ), + ), + ), + ), + SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(top: 48, bottom: 16), + child: Container( + width: double.maxFinite, + child: Column( + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.7, + ), + child: _getNotesWidget(), + ) + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + AlertCloseButton( + bottom: 30, + ) + ], + ); + } + + Widget _getNotesWidget() { + return FutureBuilder>( + future: _loadStrings(), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return ListView.builder( + shrinkWrap: true, + itemCount: snapshot.data!.length, + itemBuilder: (BuildContext context, int index) { + return _getNoteItemWidget(snapshot.data![index], context); + }, + ); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Center(child: CircularProgressIndicator()); + } + }, + ); + } + + Widget _getNoteItemWidget(String myString, BuildContext context) { + return Column( + children: [ + DefaultTextStyle( + style: TextStyle( + decoration: TextDecoration.none, + fontSize: 16.0, + fontFamily: 'Lato', + color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Text('•'), + ), + Expanded( + child: Text(myString), + ), + ], + )), + SizedBox( + height: 16.0, + ) + ], + ); + } +} diff --git a/lib/src/screens/seed_language/widgets/seed_language_picker.dart b/lib/src/screens/seed_language/widgets/seed_language_picker.dart index 0e1e63f57..0aa22088f 100644 --- a/lib/src/screens/seed_language/widgets/seed_language_picker.dart +++ b/lib/src/screens/seed_language/widgets/seed_language_picker.dart @@ -47,23 +47,19 @@ const List seedLanguages = [ enum Places { topLeft, topRight, bottomLeft, bottomRight, inside } class SeedLanguagePicker extends StatefulWidget { - SeedLanguagePicker( - {Key? key, - this.selected = defaultSeedLanguage, - required this.onItemSelected}) + SeedLanguagePicker({Key? key, this.selected = defaultSeedLanguage, required this.onItemSelected}) : super(key: key); final String selected; final Function(String) onItemSelected; @override - SeedLanguagePickerState createState() => SeedLanguagePickerState( - selected: selected, onItemSelected: onItemSelected); + SeedLanguagePickerState createState() => + SeedLanguagePickerState(selected: selected, onItemSelected: onItemSelected); } class SeedLanguagePickerState extends State { - SeedLanguagePickerState( - {required this.selected, required this.onItemSelected}); + SeedLanguagePickerState({required this.selected, required this.onItemSelected}); final String selected; final Function(String) onItemSelected; diff --git a/lib/src/widgets/alert_close_button.dart b/lib/src/widgets/alert_close_button.dart index 1aa8277f3..a3657190a 100644 --- a/lib/src/widgets/alert_close_button.dart +++ b/lib/src/widgets/alert_close_button.dart @@ -15,20 +15,18 @@ class AlertCloseButton extends StatelessWidget { @override Widget build(BuildContext context) { return Positioned( - bottom: bottom ?? 60, - child: GestureDetector( - onTap: () => Navigator.of(context).pop(), - child: Container( - height: 42, - width: 42, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle - ), - child: Center( - child: image ?? closeButton, - ), + bottom: bottom ?? 60, + child: GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: Container( + height: 42, + width: 42, + decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle), + child: Center( + child: image ?? closeButton, ), - )); + ), + ), + ); } -} \ No newline at end of file +} diff --git a/lib/utils/version_comparator.dart b/lib/utils/version_comparator.dart new file mode 100644 index 000000000..e0864568a --- /dev/null +++ b/lib/utils/version_comparator.dart @@ -0,0 +1,13 @@ +class VersionComparator { + static bool isVersion1Greater({required String v1, required String v2}) { + int v1Number = getExtendedVersionNumber(v1); + int v2Number = getExtendedVersionNumber(v2); + return v1Number > v2Number; + } + + static int getExtendedVersionNumber(String version) { + List stringVersionCells = version.split('.'); + List intVersionCells = stringVersionCells.map((i) => int.parse(i)).toList(); + return intVersionCells[0] * 100000 + intVersionCells[1] * 1000 + intVersionCells[2]; + } +} diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index 6cfbe1455..c28603a51 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -43,8 +43,7 @@ abstract class DashboardViewModelBase with Store { required this.settingsStore, required this.yatStore, required this.ordersStore, - required this.anonpayTransactionsStore, - }) + required this.anonpayTransactionsStore}) : isOutdatedElectrumWallet = false, hasSellAction = false, isEnabledSellAction = false,