CAKE-360 | merged all yat branches into current; saving information about yat to connected wallet; fixed qr widget; applied yat, unstoppable domains and open alias to contact book
OleksandrSobol committed
Oct 1, 2021 at 18:13 UTC
f353442a2a298aaa45a184b768d4d1daca19afad
26 files changed
+789
-113
assets/images/emoji_popup.png
Binary files /dev/null and b/assets/images/emoji_popup.png differ
lib/di.dart
+7
-3
@@ -62,7 +62,7 @@ import 'package:cake_wallet/src/screens/send/send_page.dart';
62
import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart';
63
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
64
import 'package:cake_wallet/store/wallet_list_store.dart';
65
-import 'package:cake_wallet/store/yat_store.dart';
65
+import 'package:cake_wallet/store/yat/yat_store.dart';
66
import 'package:cake_wallet/view_model/backup_view_model.dart';
67
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
68
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
@@ -193,7 +193,9 @@ Future setup(
193
SendTemplateStore(templateSource: _templates));
194
getIt.registerSingleton<ExchangeTemplateStore>(
195
ExchangeTemplateStore(templateSource: _exchangeTemplates));
196
- getIt.registerSingleton<YatStore>(YatStore());
196
+ getIt.registerSingleton<YatStore>(YatStore(
197
+ appStore: getIt.get<AppStore>()
198
+ ));
199
200
final secretStore =
201
await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
@@ -254,6 +256,7 @@ Future setup(
256
tradeFilterStore: getIt.get<TradeFilterStore>(),
257
transactionFilterStore: getIt.get<TransactionFilterStore>(),
258
settingsStore: settingsStore,
259
+ yatStore: getIt.get<YatStore>(),
260
ordersStore: getIt.get<OrdersStore>()));
261
262
getIt.registerFactory<AuthService>(() => AuthService(
@@ -391,7 +394,8 @@ Future setup(
394
395
getIt.registerFactory(() {
396
final appStore = getIt.get<AppStore>();
394
- return SettingsViewModel(appStore.settingsStore, appStore.wallet);
397
+ final yatStore = getIt.get<YatStore>();
398
+ return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet);
399
});
400
401
getIt.registerFactory(() => SettingsPage(getIt.get<SettingsViewModel>()));
lib/entities/parse_address_from_domain.dart
+1
-1
@@ -1,7 +1,7 @@
1
import 'package:cake_wallet/entities/openalias_record.dart';
2
import 'package:cake_wallet/entities/parsed_address.dart';
3
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
4
-import 'package:cake_wallet/yat/yat_record.dart';
4
+import 'package:cake_wallet/store/yat/yat_store.dart';
5
6
const unstoppableDomains = [
7
'crypto',
lib/entities/wallet_info.dart
+17
-3
@@ -7,7 +7,8 @@ part 'wallet_info.g.dart';
7
@HiveType(typeId: WalletInfo.typeId)
8
class WalletInfo extends HiveObject {
9
WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight,
10
- this.timestamp, this.dirPath, this.path, this.address);
10
+ this.timestamp, this.dirPath, this.path, this.address, this.yatEid,
11
+ this.yatRefreshToken);
12
13
factory WalletInfo.external(
14
{@required String id,
@@ -18,9 +19,12 @@ class WalletInfo extends HiveObject {
19
@required DateTime date,
20
@required String dirPath,
21
@required String path,
21
- @required String address}) {
22
+ @required String address,
23
+ String yatEid ='',
24
+ String yatRefreshToken = ''}) {
25
return WalletInfo(id, name, type, isRecovery, restoreHeight,
23
- date.millisecondsSinceEpoch ?? 0, dirPath, path, address);
26
+ date.millisecondsSinceEpoch ?? 0, dirPath, path, address,
27
+ yatEid, yatRefreshToken);
28
}
29
30
static const typeId = 4;
@@ -56,5 +60,15 @@ class WalletInfo extends HiveObject {
60
@HiveField(10)
61
Map<String, String> addresses;
62
63
+ @HiveField(11)
64
+ String yatEid;
65
+
66
+ @HiveField(12)
67
+ String yatRefreshToken;
68
+
69
+ String get yatEmojiId => yatEid ?? '';
70
+
71
+ String get yatToken => yatRefreshToken ?? '';
72
+
73
DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp);
74
}
lib/main.dart
+11
-9
@@ -2,7 +2,7 @@ import 'dart:async';
2
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
3
import 'package:cake_wallet/entities/language_service.dart';
4
import 'package:cake_wallet/buy/order.dart';
5
-import 'package:cake_wallet/store/yat_store.dart';
5
+import 'package:cake_wallet/store/yat/yat_store.dart';
6
import 'package:flutter/foundation.dart';
7
import 'package:flutter/material.dart';
8
import 'package:flutter/services.dart';
@@ -190,8 +190,8 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
190
@override
191
void initState() {
192
super.initState();
193
- _handleIncomingLinks(yatStore);
194
- _handleInitialUri(yatStore);
193
+ _handleIncomingLinks();
194
+ _handleInitialUri();
195
}
196
197
@override
@@ -200,25 +200,25 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
200
super.dispose();
201
}
202
203
- Future<void> _handleInitialUri(YatStore yatStore) async {
203
+ Future<void> _handleInitialUri() async {
204
try {
205
final uri = await getInitialUri();
206
if (uri == null) {
207
return;
208
}
209
if (!mounted) return;
210
- _fetchEmojiFromUri(uri, yatStore);
210
+ _fetchEmojiFromUri(uri);
211
} catch (e) {
212
if (!mounted) return;
213
print(e.toString());
214
}
215
}
216
217
- void _handleIncomingLinks(YatStore yatStore) {
217
+ void _handleIncomingLinks() {
218
if (!kIsWeb) {
219
stream = getUriLinksStream().listen((Uri uri) {
220
if (!mounted) return;
221
- _fetchEmojiFromUri(uri, yatStore);
221
+ _fetchEmojiFromUri(uri);
222
}, onError: (Object error) {
223
if (!mounted) return;
224
print('Error: $error');
@@ -226,16 +226,18 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
226
}
227
}
228
229
- void _fetchEmojiFromUri(Uri uri, YatStore yatStore) {
229
+ void _fetchEmojiFromUri(Uri uri) {
230
final queryParameters = uri.queryParameters;
231
if (queryParameters?.isEmpty ?? true) {
232
return;
233
}
234
final emoji = queryParameters['eid'];
235
- if (emoji?.isEmpty ?? true) {
235
+ final refreshToken = queryParameters['refresh_token'];
236
+ if ((emoji?.isEmpty ?? true)||(refreshToken?.isEmpty ?? true)) {
237
return;
238
}
239
yatStore.emoji = emoji;
240
+ yatStore.refreshToken = refreshToken;
241
}
242
243
@override
lib/src/screens/contact/contact_page.dart
+4
-2
@@ -1,3 +1,4 @@
1
+import 'package:cake_wallet/core/validator.dart';
2
import 'package:cake_wallet/palette.dart';
3
import 'package:cake_wallet/utils/show_pop_up.dart';
4
import 'package:flutter/material.dart';
@@ -97,8 +98,9 @@ class ContactPage extends BasePage {
98
buttonColor: Theme.of(context).accentTextTheme.display2.color,
99
iconColor: PaletteDark.gray,
100
borderColor: Theme.of(context).primaryTextTheme.title.backgroundColor,
100
- validator: AddressValidator(
101
- type: contactViewModel.currency),
101
+ validator: TextValidator()
102
+ // AddressValidator(
103
+ // type: contactViewModel.currency),
104
)),
105
)
106
],
lib/src/screens/dashboard/dashboard_page.dart
+11
-1
@@ -1,6 +1,7 @@
1
import 'package:cake_wallet/entities/wallet_type.dart';
2
import 'package:cake_wallet/generated/i18n.dart';
3
import 'package:cake_wallet/routes.dart';
4
+import 'package:cake_wallet/src/screens/yat/yat_popup.dart';
5
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
6
import 'package:cake_wallet/themes/theme_base.dart';
7
import 'package:cake_wallet/utils/show_pop_up.dart';
@@ -145,7 +146,7 @@ class DashboardPage extends BasePage {
146
));
147
}
148
148
- void _setEffects(BuildContext context) {
149
+ void _setEffects(BuildContext context) async {
150
if (_isEffectsInstalled) {
151
return;
152
}
@@ -155,6 +156,15 @@ class DashboardPage extends BasePage {
156
pages.add(BalancePage(dashboardViewModel: walletViewModel));
157
pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
158
159
+ await Future<void>.delayed(Duration(seconds: 1));
160
+ await showPopUp<void>(
161
+ context: context,
162
+ builder: (BuildContext context) {
163
+ return YatPopup(
164
+ dashboardViewModel: walletViewModel,
165
+ onClose: () => Navigator.of(context).pop());
166
+ });
167
+
168
autorun((_) async {
169
if (!walletViewModel.isOutdatedElectrumWallet) {
170
return;
lib/src/screens/exchange/exchange_page.dart
+18
@@ -235,6 +235,15 @@ class ExchangePage extends BasePage {
235
await fetchParsedAddress(
236
context, domain, ticker);
237
},
238
+ onPushAddressBookButton: (context) async {
239
+ final domain =
240
+ exchangeViewModel.depositAddress;
241
+ final ticker = exchangeViewModel
242
+ .depositCurrency.title.toLowerCase();
243
+ exchangeViewModel.depositAddress =
244
+ await fetchParsedAddress(
245
+ context, domain, ticker);
246
+ },
247
),
248
),
249
),
@@ -291,6 +300,15 @@ class ExchangePage extends BasePage {
300
await fetchParsedAddress(
301
context, domain, ticker);
302
},
303
+ onPushAddressBookButton: (context) async {
304
+ final domain =
305
+ exchangeViewModel.receiveAddress;
306
+ final ticker = exchangeViewModel
307
+ .receiveCurrency.title.toLowerCase();
308
+ exchangeViewModel.receiveAddress =
309
+ await fetchParsedAddress(
310
+ context, domain, ticker);
311
+ },
312
)),
313
)
314
],
lib/src/screens/exchange/widgets/exchange_card.dart
+6
-1
@@ -34,7 +34,8 @@ class ExchangeCard extends StatefulWidget {
34
this.addressFocusNode,
35
this.hasAllAmount = false,
36
this.allAmount,
37
- this.onPushPasteButton})
37
+ this.onPushPasteButton,
38
+ this.onPushAddressBookButton})
39
: super(key: key);
40
41
final List<CryptoCurrency> currencies;
@@ -59,6 +60,7 @@ class ExchangeCard extends StatefulWidget {
60
final bool hasAllAmount;
61
final Function allAmount;
62
final Function(BuildContext context) onPushPasteButton;
63
+ final Function(BuildContext context) onPushAddressBookButton;
64
65
@override
66
ExchangeCardState createState() => ExchangeCardState();
@@ -321,6 +323,7 @@ class ExchangeCardState extends State<ExchangeCard> {
323
buttonColor: widget.addressButtonsColor,
324
validator: widget.addressTextFieldValidator,
325
onPushPasteButton: widget.onPushPasteButton,
326
+ onPushAddressBookButton: widget.onPushAddressBookButton
327
),
328
)
329
: Padding(
@@ -366,6 +369,8 @@ class ExchangeCardState extends State<ExchangeCard> {
369
setState(() =>
370
addressController.text =
371
contact.address);
372
+ widget.onPushAddressBookButton
373
+ ?.call(context);
374
}
375
},
376
child: Container(
lib/src/screens/receive/widgets/qr_widget.dart
+2
-2
@@ -101,7 +101,7 @@ class QRWidget extends StatelessWidget {
101
),
102
),
103
Padding(
104
- padding: EdgeInsets.only(top: 16, bottom: 16),
104
+ padding: EdgeInsets.only(top: 10, bottom: 10),
105
child: Builder(
106
builder: (context) => Observer(
107
builder: (context) => GestureDetector(
@@ -164,7 +164,7 @@ class QRWidget extends StatelessWidget {
164
addressListViewModel.emoji,
165
textAlign: TextAlign.center,
166
style: TextStyle(
167
- fontSize: 13,
167
+ fontSize: 26,
168
),
169
)
170
)
lib/src/screens/send/widgets/send_card.dart
+4
-2
@@ -156,8 +156,10 @@ class SendCardState extends State<SendCard>
156
output.resetParsedAddress();
157
await output.fetchParsedAddress(context);
158
},
159
- onPushAddressBookButton: (context) =>
160
- output.resetParsedAddress(),
159
+ onPushAddressBookButton: (context) async {
160
+ output.resetParsedAddress();
161
+ await output.fetchParsedAddress(context);
162
+ },
163
validator: validator,
164
);
165
}),
lib/src/screens/yat/widgets/first_introduction.dart
new
+90
@@ -0,0 +1,90 @@
1
+import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
2
+import 'package:cake_wallet/src/screens/yat/widgets/yat_page_indicator.dart';
3
+import 'package:cake_wallet/src/widgets/primary_button.dart';
4
+import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
5
+import 'package:flutter/cupertino.dart';
6
+import 'package:flutter/material.dart';
7
+import 'package:cake_wallet/palette.dart';
8
+import 'package:lottie/lottie.dart';
9
+
10
+class FirstIntroduction extends StatelessWidget {
11
+ FirstIntroduction({this.onClose, this.onNext});
12
+
13
+ static const aspectRatioImage = 1.133;
14
+ final VoidCallback onClose;
15
+ final VoidCallback onNext;
16
+ final animation = Lottie.asset('assets/animation/anim1.json');
17
+
18
+ @override
19
+ Widget build(BuildContext context) {
20
+ final screenHeight = MediaQuery.of(context).size.height;
21
+ final screenWidth = MediaQuery.of(context).size.width;
22
+
23
+ return Container(
24
+ height: screenHeight,
25
+ width: screenWidth,
26
+ color: Colors.white,
27
+ child: ScrollableWithBottomSection(
28
+ contentPadding: EdgeInsets.only(top: 40, bottom: 40),
29
+ content: Column(
30
+ children: [
31
+ Container(
32
+ height: 45,
33
+ padding: EdgeInsets.only(left: 24, right: 24),
34
+ child: YatBar(onClose: () => Navigator.of(context).pop())
35
+ ),
36
+ animation,
37
+ Container(
38
+ padding: EdgeInsets.only(left: 30, right: 30),
39
+ child: Column(
40
+ children: [
41
+ Text(
42
+ 'Send and receive crypto more easily with Yat',
43
+ textAlign: TextAlign.center,
44
+ style: TextStyle(
45
+ fontSize: 24,
46
+ fontWeight: FontWeight.bold,
47
+ fontFamily: 'Lato',
48
+ color: Colors.black,
49
+ decoration: TextDecoration.none,
50
+ )
51
+ ),
52
+ Padding(
53
+ padding: EdgeInsets.only(top: 20),
54
+ child: Text(
55
+ 'Cake Wallet users can now send and receive all their favorite currencies with a one-of-a-kind emoji-based username.',
56
+ textAlign: TextAlign.center,
57
+ style: TextStyle(
58
+ fontSize: 16,
59
+ fontWeight: FontWeight.normal,
60
+ fontFamily: 'Lato',
61
+ color: Colors.black,
62
+ decoration: TextDecoration.none,
63
+ )
64
+ )
65
+ )
66
+ ]
67
+ )
68
+ )
69
+ ]
70
+ ),
71
+ bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
72
+ bottomSection: Column(
73
+ crossAxisAlignment: CrossAxisAlignment.center,
74
+ children: [
75
+ PrimaryButton(
76
+ text: 'Next',
77
+ textColor: Colors.white,
78
+ color: Palette.protectiveBlue,
79
+ onPressed: onNext
80
+ ),
81
+ Padding(
82
+ padding: EdgeInsets.only(top: 24),
83
+ child: YatPageIndicator(filled: 0)
84
+ )
85
+ ]
86
+ ),
87
+ )
88
+ );
89
+ }
90
+}
\ No newline at end of file
lib/src/screens/yat/widgets/second_introduction.dart
new
+89
@@ -0,0 +1,89 @@
1
+import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
2
+import 'package:cake_wallet/src/screens/yat/widgets/yat_page_indicator.dart';
3
+import 'package:cake_wallet/src/widgets/primary_button.dart';
4
+import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
5
+import 'package:flutter/cupertino.dart';
6
+import 'package:flutter/material.dart';
7
+import 'package:cake_wallet/palette.dart';
8
+import 'package:lottie/lottie.dart';
9
+
10
+class SecondIntroduction extends StatelessWidget {
11
+ SecondIntroduction({this.onClose, this.onNext});
12
+
13
+ final VoidCallback onClose;
14
+ final VoidCallback onNext;
15
+ final animation = Lottie.asset('assets/animation/anim2.json');
16
+
17
+ @override
18
+ Widget build(BuildContext context) {
19
+ final screenHeight = MediaQuery.of(context).size.height;
20
+ final screenWidth = MediaQuery.of(context).size.width;
21
+
22
+ return Container(
23
+ height: screenHeight,
24
+ width: screenWidth,
25
+ color: Colors.white,
26
+ child: ScrollableWithBottomSection(
27
+ contentPadding: EdgeInsets.only(top: 40, bottom: 40),
28
+ content: Column(
29
+ children: [
30
+ Container(
31
+ height: 45,
32
+ padding: EdgeInsets.only(left: 24, right: 24),
33
+ child: YatBar(onClose: onClose)
34
+ ),
35
+ animation,
36
+ Padding(
37
+ padding: EdgeInsets.only(top: 40, left: 30, right: 30),
38
+ child: Column(
39
+ children: [
40
+ Text(
41
+ 'One emoji address to rule them all',
42
+ textAlign: TextAlign.center,
43
+ style: TextStyle(
44
+ fontSize: 24,
45
+ fontWeight: FontWeight.bold,
46
+ fontFamily: 'Lato',
47
+ color: Colors.black,
48
+ decoration: TextDecoration.none,
49
+ )
50
+ ),
51
+ Padding(
52
+ padding: EdgeInsets.only(top: 20),
53
+ child: Text(
54
+ 'Your Yat is a single unique emoji address that replaces all of your long hexadecimal addresses for all of your currencies.',
55
+ textAlign: TextAlign.center,
56
+ style: TextStyle(
57
+ fontSize: 16,
58
+ fontWeight: FontWeight.normal,
59
+ fontFamily: 'Lato',
60
+ color: Colors.black,
61
+ decoration: TextDecoration.none,
62
+ )
63
+ )
64
+ )
65
+ ]
66
+ ),
67
+ ),
68
+ ],
69
+ ),
70
+ bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
71
+ bottomSection: Column(
72
+ crossAxisAlignment: CrossAxisAlignment.center,
73
+ children: [
74
+ PrimaryButton(
75
+ text: 'Next',
76
+ textColor: Colors.white,
77
+ color: Palette.protectiveBlue,
78
+ onPressed: onNext
79
+ ),
80
+ Padding(
81
+ padding: EdgeInsets.only(top: 24),
82
+ child: YatPageIndicator(filled: 1)
83
+ )
84
+ ]
85
+ ),
86
+ )
87
+ );
88
+ }
89
+}
\ No newline at end of file
lib/src/screens/yat/widgets/third_introduction.dart
new
+109
@@ -0,0 +1,109 @@
1
+import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
2
+import 'package:cake_wallet/src/screens/yat/widgets/yat_page_indicator.dart';
3
+import 'package:cake_wallet/src/widgets/primary_button.dart';
4
+import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
5
+import 'package:flutter/cupertino.dart';
6
+import 'package:flutter/material.dart';
7
+import 'package:cake_wallet/palette.dart';
8
+import 'package:lottie/lottie.dart';
9
+
10
+class ThirdIntroduction extends StatelessWidget {
11
+ ThirdIntroduction({this.onClose, this.onGet, this.onConnect});
12
+
13
+ final VoidCallback onClose;
14
+ final VoidCallback onGet;
15
+ final VoidCallback onConnect;
16
+ final animation = Lottie.asset('assets/animation/anim3.json');
17
+
18
+ @override
19
+ Widget build(BuildContext context) {
20
+ final screenHeight = MediaQuery.of(context).size.height;
21
+ final screenWidth = MediaQuery.of(context).size.width;
22
+
23
+ return Container(
24
+ height: screenHeight,
25
+ width: screenWidth,
26
+ color: Colors.white,
27
+ child: ScrollableWithBottomSection(
28
+ contentPadding: EdgeInsets.only(top: 40, bottom: 40),
29
+ content: Column(
30
+ children: [
31
+ Container(
32
+ height: 90,
33
+ padding: EdgeInsets.only(left: 24, right: 24),
34
+ child: YatBar(onClose: onClose)
35
+ ),
36
+ animation,
37
+ Padding(
38
+ padding: EdgeInsets.only(top: 40, left: 30, right: 30),
39
+ child: Column(
40
+ children: [
41
+ Text(
42
+ 'Yat plays nicely with others',
43
+ textAlign: TextAlign.center,
44
+ style: TextStyle(
45
+ fontSize: 24,
46
+ fontWeight: FontWeight.bold,
47
+ fontFamily: 'Lato',
48
+ color: Colors.black,
49
+ decoration: TextDecoration.none,
50
+ )
51
+ ),
52
+ Padding(
53
+ padding: EdgeInsets.only(top: 20),
54
+ child: Text(
55
+ 'Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!',
56
+ textAlign: TextAlign.center,
57
+ style: TextStyle(
58
+ fontSize: 16,
59
+ fontWeight: FontWeight.normal,
60
+ fontFamily: 'Lato',
61
+ color: Colors.black,
62
+ decoration: TextDecoration.none,
63
+ )
64
+ )
65
+ )
66
+ ]
67
+ )
68
+ ),
69
+ ],
70
+ ),
71
+ bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
72
+ bottomSection: Column(
73
+ crossAxisAlignment: CrossAxisAlignment.center,
74
+ children: [
75
+ PrimaryIconButton(
76
+ text: 'Get your Yat',
77
+ textColor: Colors.white,
78
+ color: Palette.protectiveBlue,
79
+ borderColor: Palette.protectiveBlue,
80
+ iconColor: Colors.white,
81
+ iconBackgroundColor: Colors.transparent,
82
+ iconData: CupertinoIcons
83
+ .arrow_up_right_square,
84
+ mainAxisAlignment: MainAxisAlignment.end,
85
+ onPressed: onGet),
86
+ Padding(
87
+ padding: EdgeInsets.only(top: 12),
88
+ child: PrimaryIconButton(
89
+ text: 'Connect an existing Yat',
90
+ textColor: Colors.black,
91
+ color: Palette.blueAlice,
92
+ borderColor: Palette.blueAlice,
93
+ iconColor: Colors.black,
94
+ iconBackgroundColor: Colors.transparent,
95
+ iconData: CupertinoIcons
96
+ .arrow_up_right_square,
97
+ mainAxisAlignment: MainAxisAlignment.end,
98
+ onPressed: onConnect)
99
+ ),
100
+ Padding(
101
+ padding: EdgeInsets.only(top: 24),
102
+ child: YatPageIndicator(filled: 2)
103
+ )
104
+ ]
105
+ ),
106
+ )
107
+ );
108
+ }
109
+}
\ No newline at end of file
lib/src/screens/yat/widgets/yat_page_indicator.dart
new
+33
@@ -0,0 +1,33 @@
1
+import 'package:flutter/material.dart';
2
+import 'package:cake_wallet/palette.dart';
3
+
4
+class YatPageIndicator extends StatelessWidget {
5
+ YatPageIndicator({this.filled});
6
+
7
+ final int filled;
8
+
9
+ @override
10
+ Widget build(BuildContext context) {
11
+ return Container(
12
+ width: 44,
13
+ child: Row(
14
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
15
+ children: List.generate(3, (index) {
16
+ final size = 8.0;
17
+ final isFilled = index == filled;
18
+
19
+ return Container(
20
+ height: size,
21
+ width: size,
22
+ decoration: BoxDecoration(
23
+ shape: BoxShape.circle,
24
+ color: isFilled
25
+ ? Palette.frostySky
26
+ : Palette.stateGray.withOpacity(0.1)
27
+ )
28
+ );
29
+ })
30
+ )
31
+ );
32
+ }
33
+}
\ No newline at end of file
lib/src/screens/yat/yat_alert.dart
+14
-44
@@ -1,8 +1,7 @@
1
-import 'package:cake_wallet/core/wallet_base.dart';
2
-import 'package:cake_wallet/entities/wallet_type.dart';
1
import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
2
import 'package:cake_wallet/src/widgets/primary_button.dart';
3
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
4
+import 'package:cake_wallet/store/yat/yat_store.dart';
5
import 'package:flutter/cupertino.dart';
6
import 'package:flutter/material.dart';
7
import 'package:cake_wallet/palette.dart';
@@ -11,22 +10,13 @@ import 'package:cake_wallet/generated/i18n.dart';
10
import 'package:lottie/lottie.dart';
11
12
class YatAlert extends StatelessWidget {
14
- YatAlert({@required this.wallet, this.isYatDevMode = false})
15
- : baseUrl = isYatDevMode ? _baseDevUrl : _baseReleaseUrl,
16
- address = wallet.walletAddresses.address;
13
+ YatAlert(this.yatStore)
14
+ : baseUrl = isYatDevMode ? baseDevUrl : baseReleaseUrl;
15
18
- final WalletBase wallet;
19
- final bool isYatDevMode;
20
- final String address;
16
+ final YatStore yatStore;
17
final String baseUrl;
18
static const aspectRatioImage = 1.133;
23
- static const _baseDevUrl = 'https://yat.fyi';
24
- static const _baseReleaseUrl = 'https://y.at';
25
- static const _signInSuffix = '/partner/CW/link-email';
26
- static const _createSuffix = '/create';
27
- static const _queryParameter = '?addresses=';
28
- final image = Image.asset('assets/images/yat_crypto.png');
29
- final anim = Lottie.asset('assets/animation/anim1.json');
19
+ final animation = Lottie.asset('assets/animation/anim1.json');
20
21
@override
22
Widget build(BuildContext context) {
@@ -42,15 +32,11 @@ class YatAlert extends StatelessWidget {
32
content: Column(
33
children: [
34
Container(
45
- height: 45, // 90
35
+ height: 45,
36
padding: EdgeInsets.only(left: 24, right: 24),
37
child: YatBar(onClose: () => Navigator.of(context).pop())
38
),
49
- anim,
50
- // AspectRatio(
51
- // aspectRatio: aspectRatioImage,
52
- // child: FittedBox(child: image, fit: BoxFit.fill)
53
- // ),
39
+ animation,
40
Container(
41
padding: EdgeInsets.only(left: 30, right: 30),
42
child: Column(
@@ -100,7 +86,7 @@ class YatAlert extends StatelessWidget {
86
.arrow_up_right_square,
87
mainAxisAlignment: MainAxisAlignment.end,
88
onPressed: () {
103
- final url = baseUrl + _createSuffix;
89
+ final url = baseUrl + createSuffix;
90
launch(url);
91
}),
92
Padding(
@@ -116,8 +102,12 @@ class YatAlert extends StatelessWidget {
102
.arrow_up_right_square,
103
mainAxisAlignment: MainAxisAlignment.end,
104
onPressed: () {
119
- final url = baseUrl + _signInSuffix + _queryParameter +
120
- _defineTag() + '%3D' + address;
105
+ String url = baseUrl + signInSuffix;
106
+ final parameters =
107
+ yatStore.defineQueryParameters();
108
+ if (parameters.isNotEmpty) {
109
+ url += queryParameter + parameters;
110
+ }
111
launch(url);
112
})
113
)
@@ -126,24 +116,4 @@ class YatAlert extends StatelessWidget {
116
)
117
);
118
}
129
-
130
- String _defineTag() {
131
- String tag;
132
- switch (wallet.type) {
133
- case WalletType.monero:
134
- tag = address.startsWith('4')
135
- ? '0x1001'
136
- : '0x1002';
137
- break;
138
- case WalletType.bitcoin:
139
- tag = '0x1003';
140
- break;
141
- case WalletType.litecoin:
142
- tag = '0x3fff';
143
- break;
144
- default:
145
- tag = '0x3fff';
146
- }
147
- return tag;
148
- }
119
}
\ No newline at end of file
lib/src/screens/yat/yat_popup.dart
new
+178
@@ -0,0 +1,178 @@
1
+import 'package:cake_wallet/palette.dart';
2
+import 'package:cake_wallet/src/screens/yat/widgets/first_introduction.dart';
3
+import 'package:cake_wallet/src/screens/yat/widgets/second_introduction.dart';
4
+import 'package:cake_wallet/src/screens/yat/widgets/third_introduction.dart';
5
+import 'package:cake_wallet/src/screens/yat/widgets/yat_close_button.dart';
6
+import 'package:cake_wallet/src/widgets/alert_background.dart';
7
+import 'package:cake_wallet/src/widgets/primary_button.dart';
8
+import 'package:cake_wallet/store/yat/yat_store.dart';
9
+import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
10
+import 'package:flutter/material.dart';
11
+import 'package:animate_do/animate_do.dart';
12
+import 'package:flutter_mobx/flutter_mobx.dart';
13
+import 'package:url_launcher/url_launcher.dart';
14
+
15
+class YatPopup extends StatelessWidget {
16
+ YatPopup({this.dashboardViewModel, this.onClose})
17
+ : baseUrl = isYatDevMode ? baseDevUrl : baseReleaseUrl;
18
+
19
+ static const durationInMilliseconds = 250;
20
+
21
+ final DashboardViewModel dashboardViewModel;
22
+ final VoidCallback onClose;
23
+ final String baseUrl;
24
+ final image = Image.asset('assets/images/emoji_popup.png');
25
+
26
+ @override
27
+ Widget build(BuildContext context) {
28
+ final screenWidth = MediaQuery.of(context).size.width;
29
+
30
+ return Stack(
31
+ clipBehavior: Clip.none,
32
+ alignment: Alignment.bottomCenter,
33
+ children: [
34
+ AlertBackground(
35
+ child: Container()
36
+ ),
37
+ SlideInUp(
38
+ from: 420,
39
+ duration: Duration(milliseconds: durationInMilliseconds),
40
+ child: ClipRRect(
41
+ borderRadius: BorderRadius.only(
42
+ topLeft: Radius.circular(24),
43
+ topRight: Radius.circular(24)),
44
+ child: Container(
45
+ height: 420,
46
+ color: Colors.white,
47
+ padding: EdgeInsets.fromLTRB(24, 15, 24, 24),
48
+ child: Column(
49
+ mainAxisSize: MainAxisSize.max,
50
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
51
+ children: [
52
+ Column(
53
+ children: [
54
+ Row(
55
+ mainAxisSize: MainAxisSize.max,
56
+ mainAxisAlignment: MainAxisAlignment.end,
57
+ children: [
58
+ YatCloseButton(onClose: onClose)
59
+ ]
60
+ ),
61
+ Row(
62
+ mainAxisSize: MainAxisSize.max,
63
+ mainAxisAlignment: MainAxisAlignment.center,
64
+ children: [
65
+ Container(
66
+ height: 64,
67
+ width: 165,
68
+ alignment: Alignment.center,
69
+ decoration: BoxDecoration(
70
+ color: Colors.white,
71
+ borderRadius: BorderRadius
72
+ .all(Radius.circular(32)),
73
+ boxShadow: [
74
+ BoxShadow(
75
+ color: Colors.black.withOpacity(0.05),
76
+ blurRadius: 15,
77
+ offset: Offset(0, 5)
78
+ )
79
+ ]
80
+ ),
81
+ child: image
82
+ )
83
+ ]
84
+ )
85
+ ]
86
+ ),
87
+ Container(
88
+ padding: EdgeInsets.only(left: 6, right: 6),
89
+ child: Column(
90
+ children: [
91
+ Text(
92
+ 'Your wallet address can be emojified.',
93
+ textAlign: TextAlign.center,
94
+ style: TextStyle(
95
+ fontSize: 24,
96
+ fontWeight: FontWeight.bold,
97
+ fontFamily: 'Lato',
98
+ color: Colors.black,
99
+ decoration: TextDecoration.none,
100
+ )
101
+ ),
102
+ Padding(
103
+ padding: EdgeInsets.only(top: 20),
104
+ child: Text(
105
+ 'You can now send and receive crypto in Cake Wallet with your Yat - a short, emoji-based username. Manage Yats at any time on the settings screen',
106
+ textAlign: TextAlign.center,
107
+ style: TextStyle(
108
+ fontSize: 16,
109
+ fontWeight: FontWeight.normal,
110
+ fontFamily: 'Lato',
111
+ color: Colors.black,
112
+ decoration: TextDecoration.none,
113
+ )
114
+ )
115
+ )
116
+ ]
117
+ )
118
+ ),
119
+ PrimaryButton(
120
+ text: 'Learn More',
121
+ textColor: Colors.white,
122
+ color: Palette.protectiveBlue,
123
+ onPressed: () => dashboardViewModel
124
+ .isShowFirstYatIntroduction = true
125
+ )
126
+ ],
127
+ )
128
+ )
129
+ ),
130
+ ),
131
+ Observer(builder: (_) => dashboardViewModel.isShowFirstYatIntroduction
132
+ ? SlideInRight(
133
+ from: screenWidth,
134
+ duration: Duration(milliseconds: durationInMilliseconds),
135
+ child: FirstIntroduction(
136
+ onClose: onClose,
137
+ onNext: () => dashboardViewModel
138
+ .isShowSecondYatIntroduction = true
139
+ ))
140
+ : Container()
141
+ ),
142
+ Observer(builder: (_) => dashboardViewModel.isShowSecondYatIntroduction
143
+ ? SlideInRight(
144
+ from: screenWidth,
145
+ duration: Duration(milliseconds: durationInMilliseconds),
146
+ child: SecondIntroduction(
147
+ onClose: onClose,
148
+ onNext: () => dashboardViewModel
149
+ .isShowThirdYatIntroduction = true
150
+ ))
151
+ : Container()
152
+ ),
153
+ Observer(builder: (_) => dashboardViewModel.isShowThirdYatIntroduction
154
+ ? SlideInRight(
155
+ from: screenWidth,
156
+ duration: Duration(milliseconds: durationInMilliseconds),
157
+ child: ThirdIntroduction(
158
+ onClose: onClose,
159
+ onGet: () {
160
+ final url = baseUrl + createSuffix;
161
+ launch(url);
162
+ },
163
+ onConnect: () {
164
+ String url = baseUrl + signInSuffix;
165
+ final parameters = dashboardViewModel
166
+ .yatStore.defineQueryParameters();
167
+ if (parameters.isNotEmpty) {
168
+ url += queryParameter + parameters;
169
+ }
170
+ launch(url);
171
+ }
172
+ ))
173
+ : Container()
174
+ )
175
+ ],
176
+ );
177
+ }
178
+}
\ No newline at end of file
lib/store/yat/yat_exception.dart
renamed
lib/store/yat/yat_store.dart
new
+166
@@ -0,0 +1,166 @@
1
+import 'package:cake_wallet/core/transaction_history.dart';
2
+import 'package:cake_wallet/core/wallet_base.dart';
3
+import 'package:cake_wallet/entities/balance.dart';
4
+import 'package:cake_wallet/entities/transaction_info.dart';
5
+import 'package:cake_wallet/store/app_store.dart';
6
+import 'package:flutter/foundation.dart';
7
+import 'package:mobx/mobx.dart';
8
+import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
9
+import 'package:cake_wallet/entities/wallet_type.dart';
10
+import 'package:cake_wallet/monero/monero_subaddress_list.dart';
11
+import 'package:cake_wallet/monero/monero_wallet.dart';
12
+import 'dart:convert';
13
+import 'package:cake_wallet/store/yat/yat_exception.dart';
14
+import 'package:http/http.dart';
15
+
16
+part 'yat_store.g.dart';
17
+
18
+const baseDevUrl = 'https://yat.fyi';
19
+const baseReleaseUrl = 'https://y.at';
20
+const signInSuffix = '/partner/CW/link-email';
21
+const createSuffix = '/create';
22
+const queryParameter = '?addresses=';
23
+const requestDevUrl = 'https://a.yat.fyi/emoji_id/';
24
+const requestReleaseUrl = 'https://a.y.at/emoji_id/';
25
+const isYatDevMode = true;
26
+
27
+Future<List<String>> fetchYatAddress(String emojiId, String ticker) async {
28
+ final requestURL = isYatDevMode ? requestDevUrl : requestReleaseUrl;
29
+ final url = requestURL + emojiId + '/' + ticker.toUpperCase();
30
+ final response = await get(url);
31
+
32
+ if (response.statusCode != 200) {
33
+ throw YatException(text: response.body.toString());
34
+ }
35
+
36
+ final responseJSON = json.decode(response.body) as Map<String, dynamic>;
37
+ final result = responseJSON['result'] as List<dynamic>;
38
+
39
+ if (result?.isEmpty ?? true) {
40
+ return [];
41
+ }
42
+
43
+ final List<String> addresses = [];
44
+
45
+ for (var elem in result) {
46
+ final yatAddress = elem['data'] as String;
47
+ if (yatAddress?.isNotEmpty ?? false) {
48
+ addresses.add(yatAddress);
49
+ }
50
+ }
51
+
52
+ return addresses;
53
+}
54
+
55
+class YatStore = YatStoreBase with _$YatStore;
56
+
57
+abstract class YatStoreBase with Store {
58
+ YatStoreBase({@required this.appStore}) {
59
+ _wallet ??= appStore.wallet;
60
+ emoji = _wallet?.walletInfo?.yatEmojiId ?? '';
61
+ refreshToken = _wallet?.walletInfo?.yatToken ?? '';
62
+ reaction((_) => appStore.wallet, _onWalletChange);
63
+ reaction((_) => emoji, (String emoji) => _onEmojiChange());
64
+ }
65
+
66
+ AppStore appStore;
67
+
68
+ @observable
69
+ String emoji;
70
+
71
+ @observable
72
+ String refreshToken;
73
+
74
+ @observable
75
+ WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
76
+ _wallet;
77
+
78
+ @action
79
+ void _onWalletChange(
80
+ WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
81
+ TransactionInfo>
82
+ wallet) {
83
+ this._wallet = wallet;
84
+ emoji = wallet?.walletInfo?.yatEmojiId ?? '';
85
+ refreshToken = wallet?.walletInfo?.yatToken ?? '';
86
+ }
87
+
88
+ @action
89
+ void _onEmojiChange() {
90
+ try {
91
+ final walletInfo = _wallet.walletInfo;
92
+
93
+ if (walletInfo == null) {
94
+ return;
95
+ }
96
+
97
+ walletInfo.yatEid = emoji;
98
+ walletInfo.yatRefreshToken = refreshToken;
99
+
100
+ if (walletInfo.isInBox) {
101
+ walletInfo.save();
102
+ }
103
+ } catch (e) {
104
+ print(e.toString());
105
+ }
106
+ }
107
+
108
+ String defineQueryParameters() {
109
+ String parameters = '';
110
+ switch (_wallet.type) {
111
+ case WalletType.monero:
112
+ final wallet = _wallet as MoneroWallet;
113
+ final subaddressList = MoneroSubaddressList();
114
+ var isFirstAddress = true;
115
+
116
+ wallet.walletAddresses.accountList.accounts.forEach((account) {
117
+ subaddressList.update(accountIndex: account.id);
118
+ subaddressList.subaddresses.forEach((subaddress) {
119
+ if (!isFirstAddress) {
120
+ parameters += '%7C';
121
+ } else {
122
+ isFirstAddress = !isFirstAddress;
123
+ }
124
+
125
+ parameters += subaddress.address.startsWith('4')
126
+ ? '0x1001%3D'
127
+ : '0x1002%3D';
128
+
129
+ parameters += subaddress.address;
130
+ });
131
+ });
132
+ break;
133
+ case WalletType.bitcoin:
134
+ final wallet = _wallet as ElectrumWallet;
135
+ var isFirstAddress = true;
136
+
137
+ wallet.walletAddresses.addresses.forEach((record) {
138
+ if (!isFirstAddress) {
139
+ parameters += '%7C';
140
+ } else {
141
+ isFirstAddress = !isFirstAddress;
142
+ }
143
+
144
+ parameters += '0x1003%3D' + record.address;
145
+ });
146
+ break;
147
+ case WalletType.litecoin:
148
+ final wallet = _wallet as ElectrumWallet;
149
+ var isFirstAddress = true;
150
+
151
+ wallet.walletAddresses.addresses.forEach((record) {
152
+ if (!isFirstAddress) {
153
+ parameters += '%7C';
154
+ } else {
155
+ isFirstAddress = !isFirstAddress;
156
+ }
157
+
158
+ parameters += '0x3fff%3D' + record.address;
159
+ });
160
+ break;
161
+ default:
162
+ parameters = '';
163
+ }
164
+ return parameters;
165
+ }
166
+}
\ No newline at end of file
lib/store/yat_store.dart
deleted
-12
@@ -1,12 +0,0 @@
1
-import 'package:mobx/mobx.dart';
2
-
3
-part 'yat_store.g.dart';
4
-
5
-class YatStore = YatStoreBase with _$YatStore;
6
-
7
-abstract class YatStoreBase with Store {
8
- YatStoreBase() : emoji = '';
9
-
10
- @observable
11
- String emoji;
12
-}
\ No newline at end of file
lib/view_model/dashboard/dashboard_view_model.dart
+16
@@ -12,6 +12,7 @@ import 'package:cake_wallet/entities/transaction_info.dart';
12
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
13
import 'package:cake_wallet/store/settings_store.dart';
14
import 'package:cake_wallet/store/dashboard/orders_store.dart';
15
+import 'package:cake_wallet/store/yat/yat_store.dart';
16
import 'package:cake_wallet/utils/mobx.dart';
17
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
18
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
@@ -46,6 +47,7 @@ abstract class DashboardViewModelBase with Store {
47
this.tradeFilterStore,
48
this.transactionFilterStore,
49
this.settingsStore,
50
+ this.yatStore,
51
this.ordersStore}) {
52
filterItems = {
53
S.current.transactions: [
@@ -86,6 +88,9 @@ abstract class DashboardViewModelBase with Store {
88
type = wallet.type;
89
isOutdatedElectrumWallet =
90
wallet.type == WalletType.bitcoin && wallet.seed.split(' ').length < 24;
91
+ isShowFirstYatIntroduction = false;
92
+ isShowSecondYatIntroduction = false;
93
+ isShowThirdYatIntroduction = false;
94
final _wallet = wallet;
95
96
if (_wallet is MoneroWallet) {
@@ -147,6 +152,15 @@ abstract class DashboardViewModelBase with Store {
152
@observable
153
String subname;
154
155
+ @observable
156
+ bool isShowFirstYatIntroduction;
157
+
158
+ @observable
159
+ bool isShowSecondYatIntroduction;
160
+
161
+ @observable
162
+ bool isShowThirdYatIntroduction;
163
+
164
@computed
165
String get address => wallet.walletAddresses.address;
166
@@ -208,6 +222,8 @@ abstract class DashboardViewModelBase with Store {
222
223
SettingsStore settingsStore;
224
225
+ YatStore yatStore;
226
+
227
TradesStore tradesStore;
228
229
OrdersStore ordersStore;
lib/view_model/settings/settings_view_model.dart
+4
-1
@@ -1,4 +1,5 @@
1
import 'package:cake_wallet/src/screens/yat/yat_alert.dart';
2
+import 'package:cake_wallet/store/yat/yat_store.dart';
3
import 'package:cake_wallet/utils/show_pop_up.dart';
4
import 'package:flutter/cupertino.dart';
5
import 'package:mobx/mobx.dart';
@@ -50,6 +51,7 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
51
abstract class SettingsViewModelBase with Store {
52
SettingsViewModelBase(
53
this._settingsStore,
54
+ this._yatStore,
55
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
56
TransactionInfo>
57
wallet)
@@ -162,7 +164,7 @@ abstract class SettingsViewModelBase with Store {
164
await showPopUp<void>(
165
context: context,
166
builder: (BuildContext context) {
165
- return YatAlert(wallet: wallet, isYatDevMode: true);
167
+ return YatAlert(_yatStore);
168
});
169
},
170
),
@@ -213,6 +215,7 @@ abstract class SettingsViewModelBase with Store {
215
final Map<String, String> itemHeaders;
216
List<List<SettingsListItem>> sections;
217
final SettingsStore _settingsStore;
218
+ final YatStore _yatStore;
219
final WalletType _walletType;
220
final BiometricAuth _biometricAuth;
221
lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+1
-1
@@ -1,4 +1,4 @@
1
-import 'package:cake_wallet/store/yat_store.dart';
1
+import 'package:cake_wallet/store/yat/yat_store.dart';
2
import 'package:flutter/foundation.dart';
3
import 'package:mobx/mobx.dart';
4
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
lib/yat/yat_record.dart
deleted
-31
@@ -1,31 +0,0 @@
1
-import 'dart:convert';
2
-import 'package:cake_wallet/yat/yat_exception.dart';
3
-import 'package:http/http.dart';
4
-
5
-Future<List<String>> fetchYatAddress(String emojiId, String ticker) async {
6
- const _requestURL = 'https://a.y.at/emoji_id/';
7
- final url = _requestURL + emojiId + '/' + ticker.toUpperCase();
8
- final response = await get(url);
9
-
10
- if (response.statusCode != 200) {
11
- throw YatException(text: response.body.toString());
12
- }
13
-
14
- final responseJSON = json.decode(response.body) as Map<String, dynamic>;
15
- final result = responseJSON['result'] as List<dynamic>;
16
-
17
- if (result?.isEmpty ?? true) {
18
- return [];
19
- }
20
-
21
- final List<String> addresses = [];
22
-
23
- for (var elem in result) {
24
- final yatAddress = elem['data'] as String;
25
- if (yatAddress?.isNotEmpty ?? false) {
26
- addresses.add(yatAddress);
27
- }
28
- }
29
-
30
- return addresses;
31
-}
\ No newline at end of file
pubspec.lock
+7
@@ -15,6 +15,13 @@ packages:
15
url: "https://pub.dartlang.org"
16
source: hosted
17
version: "0.41.2"
18
+ animate_do:
19
+ dependency: "direct main"
20
+ description:
21
+ name: animate_do
22
+ url: "https://pub.dartlang.org"
23
+ source: hosted
24
+ version: "2.0.0"
25
archive:
26
dependency: "direct main"
27
description:
pubspec.yaml
+1
@@ -59,6 +59,7 @@ dependencies:
59
flutter_spinkit: ^5.0.0
60
uni_links: ^0.4.0
61
lottie: ^0.7.0
62
+ animate_do: ^2.0.0
63
64
# The following adds the Cupertino Icons font to your application.
65
# Use with the CupertinoIcons class for iOS style icons.