CW-59-New-update-highlight-popup (#863)

* add update pop up * add release notes for monero com * PR comments fixes * Pr coments fixes * minor fixes * update from main * [skip ci] remove unrelated mac os files * add check isNewInstall * update pop-up UI * fix size * Add update popup to desktop dashboard page [skip ci] --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>

Serhii committed Apr 21, 2023 at 18:21 UTC 8ffac75e8c939c9dffc54c5b4744b0571a146920
15 files changed +263 -37
assets/text/Monerocom_Release_Notes.txt new
+13
@@ -0,0 +1,13 @@
1 +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges
2 +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)
3 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
4 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
5 +Keep screen awake while the synchronization function
6 +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)
7 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
8 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
9 +Keep screen awake while the synchronization function
10 +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)
11 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
12 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
13 +Keep screen awake while the synchronizatio
\ No newline at end of file
assets/text/Release_Notes.txt new
+13
@@ -0,0 +1,13 @@
1 +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)Added Fixed Rate for exchanges
2 +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)
3 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
4 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
5 +Keep screen awake while the synchronization function
6 +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)
7 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
8 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
9 +Keep screen awake while the synchronization function
10 +Added Fixed Rate for exchanges (enter the "receive" amount on the exchange page to get the fixed rate)
11 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
12 +Changed algorithm for choosing of change address for BTC and LTC electrum wallets
13 +Keep screen awake while the synchronizatio
\ No newline at end of file
lib/di.dart
+2 -1
@@ -208,7 +208,7 @@ Future setup(
208 required Box<TransactionDescription> transactionDescriptionBox,
209 required Box<Order> ordersSource,
210 Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
211 - required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource
211 + required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
212 }) async {
213 _walletInfoSource = walletInfoSource;
214 _nodeSource = nodeSource;
@@ -396,6 +396,7 @@ Future setup(
396 dashboardViewModel: getIt.get<DashboardViewModel>(),
397 addressListViewModel: getIt.get<WalletAddressListViewModel>(),
398 ));
399 +
400 getIt.registerFactory<DesktopSidebarWrapper>(() {
401 final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
402 return DesktopSidebarWrapper(
lib/entities/default_settings_migration.dart
+7
@@ -42,6 +42,13 @@ Future defaultSettingsMigration(
42 // check current nodes for nullability regardless of the version
43 await checkCurrentNodes(nodes, sharedPreferences);
44
45 + final isNewInstall = sharedPreferences
46 + .getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null;
47 +
48 + await sharedPreferences.setBool(
49 + PreferencesKey.isNewInstall, isNewInstall);
50 +
51 +
52 final currentVersion = sharedPreferences
53 .getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) ??
54 0;
lib/entities/preferences_key.dart
+3 -1
@@ -41,6 +41,8 @@ class PreferencesKey {
41
42 static const exchangeProvidersSelection = 'exchange-providers-selection';
43 static const clearnetDonationLink = 'clearnet_donation_link';
44 - static const onionDonationLink = 'onion_donation_link';
44 + static const onionDonationLink = 'onion_donation_link';
45 + static const lastSeenAppVersion = 'last_seen_app_version';
46 static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard';
47 + static const isNewInstall = 'is_new_install';
48 }
lib/main.dart
+1 -2
@@ -187,8 +187,7 @@ Future<void> initialSetup(
187 transactionDescriptionBox: transactionDescriptions,
188 ordersSource: ordersSource,
189 anonpayInvoiceInfoSource: anonpayInvoiceInfo,
190 - unspentCoinsInfoSource: unspentCoinsInfoSource,
191 - );
190 + unspentCoinsInfoSource: unspentCoinsInfoSource);
191 await bootstrap(navigatorKey);
192 monero?.onStartup();
193 }
lib/src/screens/dashboard/dashboard_page.dart
+27 -2
@@ -1,8 +1,10 @@
1 import 'dart:async';
2 +import 'package:cake_wallet/entities/preferences_key.dart';
3 import 'package:cake_wallet/di.dart';
4 import 'package:cake_wallet/entities/main_actions.dart';
5 import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
6 import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
7 +import 'package:cake_wallet/utils/version_comparator.dart';
8 import 'package:cake_wallet/wallet_type_utils.dart';
9 import 'package:cake_wallet/generated/i18n.dart';
10 import 'package:cake_wallet/routes.dart';
@@ -22,8 +24,12 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
24 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
25 import 'package:flutter_mobx/flutter_mobx.dart';
26 import 'package:mobx/mobx.dart';
27 +import 'package:shared_preferences/shared_preferences.dart';
28 import 'package:smooth_page_indicator/smooth_page_indicator.dart';
29 import 'package:cake_wallet/main.dart';
30 +import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
31 +import 'package:url_launcher/url_launcher.dart';
32 +import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
33
34 class DashboardPage extends StatelessWidget {
35 DashboardPage({
@@ -117,7 +123,7 @@ class _DashboardPageView extends BasePage {
123 @override
124 Widget body(BuildContext context) {
125 final controller = PageController(initialPage: initialPage);
120 -
126 +
127 reaction((_) => dashboardViewModel.shouldShowMarketPlaceInDashboard, (bool value) {
128 if (!dashboardViewModel.shouldShowMarketPlaceInDashboard) {
129 controller.jumpToPage(0);
@@ -131,7 +137,7 @@ class _DashboardPageView extends BasePage {
137 } else {
138 controller.jumpToPage(0);
139 }
134 - });
140 + });
141 _setEffects(context);
142
143 return SafeArea(
@@ -266,6 +272,25 @@ class _DashboardPageView extends BasePage {
272 }
273 });
274
275 + final sharedPrefs = await SharedPreferences.getInstance();
276 + final currentAppVersion =
277 + VersionComparator.getExtendedVersionNumber(dashboardViewModel.settingsStore.appVersion);
278 + final lastSeenAppVersion = sharedPrefs.getInt(PreferencesKey.lastSeenAppVersion);
279 + final isNewInstall = sharedPrefs.getBool(PreferencesKey.isNewInstall);
280 +
281 + if (currentAppVersion != lastSeenAppVersion && !isNewInstall!) {
282 + await Future<void>.delayed(Duration(seconds: 1));
283 + await showPopUp<void>(
284 + context: context,
285 + builder: (BuildContext context) {
286 + return ReleaseNotesScreen(
287 + title: 'Version ${dashboardViewModel.settingsStore.appVersion}');
288 + });
289 + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
290 + } else if (isNewInstall!) {
291 + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
292 + }
293 +
294 var needToPresentYat = false;
295 var isInactive = false;
296
lib/src/screens/dashboard/desktop_dashboard_page.dart
+23
@@ -1,9 +1,12 @@
1 import 'dart:async';
2 +import 'package:cake_wallet/entities/preferences_key.dart';
3 import 'package:cake_wallet/generated/i18n.dart';
4 import 'package:cake_wallet/routes.dart';
5 +import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
6 import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
7 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
8 import 'package:cake_wallet/utils/show_pop_up.dart';
9 +import 'package:cake_wallet/utils/version_comparator.dart';
10 import 'package:flutter/material.dart';
11 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
12 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
14 import 'package:mobx/mobx.dart';
15 import 'package:cake_wallet/main.dart';
16 import 'package:cake_wallet/router.dart' as Router;
17 +import 'package:shared_preferences/shared_preferences.dart';
18
19 class DesktopDashboardPage extends StatelessWidget {
20 DesktopDashboardPage({
@@ -107,5 +111,24 @@ class DesktopDashboardPage extends StatelessWidget {
111
112 needToPresentYat = true;
113 });
114 +
115 + final sharedPrefs = await SharedPreferences.getInstance();
116 + final currentAppVersion =
117 + VersionComparator.getExtendedVersionNumber(dashboardViewModel.settingsStore.appVersion);
118 + final lastSeenAppVersion = sharedPrefs.getInt(PreferencesKey.lastSeenAppVersion);
119 + final isNewInstall = sharedPrefs.getBool(PreferencesKey.isNewInstall);
120 +
121 + if (currentAppVersion != lastSeenAppVersion && !isNewInstall!) {
122 + await Future<void>.delayed(Duration(seconds: 1));
123 + await showPopUp<void>(
124 + context: context,
125 + builder: (BuildContext context) {
126 + return ReleaseNotesScreen(
127 + title: 'Version ${dashboardViewModel.settingsStore.appVersion}');
128 + });
129 + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
130 + } else if (isNewInstall!) {
131 + sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
132 + }
133 }
134 }
lib/src/screens/dashboard/widgets/filter_widget.dart
+1 -2
@@ -16,7 +16,6 @@ class FilterWidget extends StatelessWidget {
16 FilterWidget({required this.dashboardViewModel});
17
18 final DashboardViewModel dashboardViewModel;
19 - final closeIcon = Image.asset('assets/images/close.png', color: Palette.darkBlueCraiola);
19
20 @override
21 Widget build(BuildContext context) {
@@ -101,7 +100,7 @@ class FilterWidget extends StatelessWidget {
100 ),
101 ],
102 ),
104 - AlertCloseButton(image: closeIcon)
103 + AlertCloseButton()
104 ],
105 ),
106 );
lib/src/screens/monero_accounts/monero_account_list_page.dart
+1 -4
@@ -27,9 +27,6 @@ class MoneroAccountListPage extends StatelessWidget {
27 }
28
29 final MoneroAccountListViewModel accountListViewModel;
30 - final closeIcon = Image.asset('assets/images/close.png',
31 - color: Palette.darkBlueCraiola,
32 - );
30
31 ScrollController controller;
32 double backgroundHeight;
@@ -163,7 +160,7 @@ class MoneroAccountListPage extends StatelessWidget {
160 )
161 ],
162 ),
166 - AlertCloseButton(image: closeIcon)
163 + AlertCloseButton()
164 ],
165 ),
166 );
lib/src/screens/release_notes/release_notes_screen.dart new
+141
@@ -0,0 +1,141 @@
1 +import 'dart:convert';
2 +import 'package:cake_wallet/src/widgets/alert_background.dart';
3 +import 'package:cake_wallet/src/widgets/alert_close_button.dart';
4 +import 'package:cake_wallet/wallet_type_utils.dart';
5 +import 'package:flutter/material.dart';
6 +import 'package:flutter/services.dart';
7 +
8 +class ReleaseNotesScreen extends StatelessWidget {
9 + const ReleaseNotesScreen({
10 + required this.title,
11 + });
12 +
13 + final String title;
14 +
15 + Future<List<String>> _loadStrings() async {
16 + String notesContent = await rootBundle.loadString(
17 + isMoneroOnly ? 'assets/text/Monerocom_Release_Notes.txt' : 'assets/text/Release_Notes.txt');
18 + return LineSplitter().convert(notesContent);
19 + }
20 +
21 + @override
22 + Widget build(BuildContext context) {
23 + return Stack(
24 + alignment: Alignment.center,
25 + children: [
26 + AlertBackground(
27 + child: AlertDialog(
28 + insetPadding: EdgeInsets.only(left: 16, right: 16, bottom: 48),
29 + elevation: 0.0,
30 + contentPadding: EdgeInsets.zero,
31 + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30))),
32 + content: Container(
33 + decoration: BoxDecoration(
34 + borderRadius: BorderRadius.circular(30.0),
35 + gradient: LinearGradient(colors: [
36 + Theme.of(context).colorScheme.secondary,
37 + Theme.of(context).scaffoldBackgroundColor,
38 + ], begin: Alignment.centerLeft, end: Alignment.centerRight)),
39 + child: Padding(
40 + padding: const EdgeInsets.symmetric(horizontal: 24.0),
41 + child: Stack(
42 + children: [
43 + SingleChildScrollView(
44 + child: Padding(
45 + padding: const EdgeInsets.only(top: 16.0),
46 + child: Container(
47 + alignment: Alignment.bottomCenter,
48 + child: DefaultTextStyle(
49 + style: TextStyle(
50 + decoration: TextDecoration.none,
51 + fontSize: 24.0,
52 + fontWeight: FontWeight.bold,
53 + fontFamily: 'Lato',
54 + color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
55 + ),
56 + child: Text(title),
57 + ),
58 + ),
59 + ),
60 + ),
61 + SingleChildScrollView(
62 + child: Padding(
63 + padding: EdgeInsets.only(top: 48, bottom: 16),
64 + child: Container(
65 + width: double.maxFinite,
66 + child: Column(
67 + children: <Widget>[
68 + ConstrainedBox(
69 + constraints: BoxConstraints(
70 + maxHeight: MediaQuery.of(context).size.height * 0.7,
71 + ),
72 + child: _getNotesWidget(),
73 + )
74 + ],
75 + ),
76 + ),
77 + ),
78 + ),
79 + ],
80 + ),
81 + ),
82 + ),
83 + ),
84 + ),
85 + AlertCloseButton(
86 + bottom: 30,
87 + )
88 + ],
89 + );
90 + }
91 +
92 + Widget _getNotesWidget() {
93 + return FutureBuilder<List<String>>(
94 + future: _loadStrings(),
95 + builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
96 + if (snapshot.hasData) {
97 + return ListView.builder(
98 + shrinkWrap: true,
99 + itemCount: snapshot.data!.length,
100 + itemBuilder: (BuildContext context, int index) {
101 + return _getNoteItemWidget(snapshot.data![index], context);
102 + },
103 + );
104 + } else if (snapshot.hasError) {
105 + return Text('Error: ${snapshot.error}');
106 + } else {
107 + return Center(child: CircularProgressIndicator());
108 + }
109 + },
110 + );
111 + }
112 +
113 + Widget _getNoteItemWidget(String myString, BuildContext context) {
114 + return Column(
115 + children: [
116 + DefaultTextStyle(
117 + style: TextStyle(
118 + decoration: TextDecoration.none,
119 + fontSize: 16.0,
120 + fontFamily: 'Lato',
121 + color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
122 + ),
123 + child: Row(
124 + crossAxisAlignment: CrossAxisAlignment.start,
125 + children: [
126 + Padding(
127 + padding: const EdgeInsets.only(right: 8.0),
128 + child: Text('•'),
129 + ),
130 + Expanded(
131 + child: Text(myString),
132 + ),
133 + ],
134 + )),
135 + SizedBox(
136 + height: 16.0,
137 + )
138 + ],
139 + );
140 + }
141 +}
lib/src/screens/seed_language/widgets/seed_language_picker.dart
+4 -8
@@ -47,23 +47,19 @@ const List<String> seedLanguages = [
47 enum Places { topLeft, topRight, bottomLeft, bottomRight, inside }
48
49 class SeedLanguagePicker extends StatefulWidget {
50 - SeedLanguagePicker(
51 - {Key? key,
52 - this.selected = defaultSeedLanguage,
53 - required this.onItemSelected})
50 + SeedLanguagePicker({Key? key, this.selected = defaultSeedLanguage, required this.onItemSelected})
51 : super(key: key);
52
53 final String selected;
54 final Function(String) onItemSelected;
55
56 @override
60 - SeedLanguagePickerState createState() => SeedLanguagePickerState(
61 - selected: selected, onItemSelected: onItemSelected);
57 + SeedLanguagePickerState createState() =>
58 + SeedLanguagePickerState(selected: selected, onItemSelected: onItemSelected);
59 }
60
61 class SeedLanguagePickerState extends State<SeedLanguagePicker> {
65 - SeedLanguagePickerState(
66 - {required this.selected, required this.onItemSelected});
62 + SeedLanguagePickerState({required this.selected, required this.onItemSelected});
63
64 final String selected;
65 final Function(String) onItemSelected;
lib/src/widgets/alert_close_button.dart
+13 -15
@@ -15,20 +15,18 @@ class AlertCloseButton extends StatelessWidget {
15 @override
16 Widget build(BuildContext context) {
17 return Positioned(
18 - bottom: bottom ?? 60,
19 - child: GestureDetector(
20 - onTap: () => Navigator.of(context).pop(),
21 - child: Container(
22 - height: 42,
23 - width: 42,
24 - decoration: BoxDecoration(
25 - color: Colors.white,
26 - shape: BoxShape.circle
27 - ),
28 - child: Center(
29 - child: image ?? closeButton,
30 - ),
18 + bottom: bottom ?? 60,
19 + child: GestureDetector(
20 + onTap: () => Navigator.of(context).pop(),
21 + child: Container(
22 + height: 42,
23 + width: 42,
24 + decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle),
25 + child: Center(
26 + child: image ?? closeButton,
27 ),
32 - ));
28 + ),
29 + ),
30 + );
31 }
34 -}
\ No newline at end of file
32 +}
lib/utils/version_comparator.dart new
+13
@@ -0,0 +1,13 @@
1 +class VersionComparator {
2 + static bool isVersion1Greater({required String v1, required String v2}) {
3 + int v1Number = getExtendedVersionNumber(v1);
4 + int v2Number = getExtendedVersionNumber(v2);
5 + return v1Number > v2Number;
6 + }
7 +
8 + static int getExtendedVersionNumber(String version) {
9 + List<String> stringVersionCells = version.split('.');
10 + List<int> intVersionCells = stringVersionCells.map((i) => int.parse(i)).toList();
11 + return intVersionCells[0] * 100000 + intVersionCells[1] * 1000 + intVersionCells[2];
12 + }
13 +}
lib/view_model/dashboard/dashboard_view_model.dart
+1 -2
@@ -43,8 +43,7 @@ abstract class DashboardViewModelBase with Store {
43 required this.settingsStore,
44 required this.yatStore,
45 required this.ordersStore,
46 - required this.anonpayTransactionsStore,
47 - })
46 + required this.anonpayTransactionsStore})
47 : isOutdatedElectrumWallet = false,
48 hasSellAction = false,
49 isEnabledSellAction = false,