diff --git a/assets/images/yat_logo.png b/assets/images/yat_logo.png index 73732566f..1139e40d8 100644 Binary files a/assets/images/yat_logo.png and b/assets/images/yat_logo.png differ diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index 82db7d5d9..3c94e8322 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -20,4 +20,5 @@ class PreferencesKey { static const moneroTransactionPriority = 'current_fee_priority_monero'; static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin'; static const shouldShowReceiveWarning = 'should_show_receive_warning'; + static const shouldShowYatPopup = 'should_show_yat_popup'; } diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index a7070f5ce..8cf178153 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -156,14 +156,17 @@ class DashboardPage extends BasePage { pages.add(BalancePage(dashboardViewModel: walletViewModel)); pages.add(TransactionsPage(dashboardViewModel: walletViewModel)); - await Future.delayed(Duration(seconds: 1)); - await showPopUp( - context: context, - builder: (BuildContext context) { - return YatPopup( - dashboardViewModel: walletViewModel, - onClose: () => Navigator.of(context).pop()); - }); + if (walletViewModel.shouldShowYatPopup) { + await Future.delayed(Duration(seconds: 1)); + await showPopUp( + context: context, + builder: (BuildContext context) { + return YatPopup( + dashboardViewModel: walletViewModel, + onClose: () => Navigator.of(context).pop()); + }); + walletViewModel.furtherShowYatPopup(false); + } autorun((_) async { if (!walletViewModel.isOutdatedElectrumWallet) { diff --git a/lib/src/screens/send/widgets/choose_yat_address_alert.dart b/lib/src/screens/send/widgets/choose_yat_address_alert.dart index 64020a200..2b19075ff 100644 --- a/lib/src/screens/send/widgets/choose_yat_address_alert.dart +++ b/lib/src/screens/send/widgets/choose_yat_address_alert.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; @@ -22,51 +23,98 @@ class ChooseYatAddressAlert extends BaseAlertDialog { bool get barrierDismissible => false; @override - Widget actionButtons(BuildContext context) { - return Container( - width: 300, - height: 105, - color: Theme.of(context).accentTextTheme.body1.backgroundColor, - child: ListView.separated( - padding: EdgeInsets.all(0), - itemCount: addresses.length, - separatorBuilder: (_, __) => Container( - height: 1, - color: Theme.of(context).dividerColor, - ), - itemBuilder: (context, index) { - final address = addresses[index]; + Widget actionButtons(BuildContext context) => + ChooseYatAddressButtons(addresses); +} - return GestureDetector( - onTap: () => Navigator.of(context).pop(address), - child: Container( - width: 300, - height: 52, - padding: EdgeInsets.only(left: 24, right: 24), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Text( - address, - textAlign: TextAlign.center, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w600, - fontFamily: 'Lato', - color: Theme.of(context).primaryTextTheme.title.color, - decoration: TextDecoration.none, - ), - ) - ) - ], - ) - ), - ); - }) +class ChooseYatAddressButtons extends StatefulWidget { + ChooseYatAddressButtons(this.addresses); + + final List addresses; + + @override + ChooseYatAddressButtonsState createState() => + ChooseYatAddressButtonsState(addresses); +} + +class ChooseYatAddressButtonsState extends State { + ChooseYatAddressButtonsState(this.addresses) + : itemCount = addresses?.length ?? 0; + + final List addresses; + final int itemCount; + final double backgroundHeight = 118; + final double thumbHeight = 72; + ScrollController controller = ScrollController(); + double fromTop = 0; + + @override + Widget build(BuildContext context) { + controller.addListener(() { + fromTop = controller.hasClients + ? (controller.offset / controller.position.maxScrollExtent * + (backgroundHeight - thumbHeight)) + : 0; + setState(() {}); + }); + + return Stack( + alignment: Alignment.center, + clipBehavior: Clip.none, + children: [ + Container( + width: 300, + height: 158, + color: Theme.of(context).accentTextTheme.body1.backgroundColor, + child: ListView.separated( + controller: controller, + padding: EdgeInsets.all(0), + itemCount: itemCount, + separatorBuilder: (_, __) => Container( + height: 1, + color: Theme.of(context).dividerColor, + ), + itemBuilder: (context, index) { + final address = addresses[index]; + + return GestureDetector( + onTap: () => Navigator.of(context).pop(address), + child: Container( + width: 300, + height: 52, + padding: EdgeInsets.only(left: 24, right: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Text( + address, + textAlign: TextAlign.center, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + fontFamily: 'Lato', + color: Theme.of(context).primaryTextTheme.title.color, + decoration: TextDecoration.none, + ), + ) + ) + ], + ) + ), + ); + }) + ), + if (itemCount > 3) CakeScrollbar( + backgroundHeight: backgroundHeight, + thumbHeight: thumbHeight, + fromTop: fromTop, + //rightOffset: -15 + ) + ] ); } } \ No newline at end of file diff --git a/lib/src/screens/yat/widgets/yat_bar.dart b/lib/src/screens/yat/widgets/yat_bar.dart index 03b3556b0..7e1d725b2 100644 --- a/lib/src/screens/yat/widgets/yat_bar.dart +++ b/lib/src/screens/yat/widgets/yat_bar.dart @@ -5,7 +5,7 @@ class YatBar extends StatelessWidget { YatBar({this.onClose}); final VoidCallback onClose; - final image = Image.asset('assets/images/yat_logo.png'); + final image = Image.asset('assets/images/yat_logo.png', width: 81, height: 28); @override Widget build(BuildContext context) { diff --git a/lib/src/screens/yat/yat_alert.dart b/lib/src/screens/yat/yat_alert.dart index 7c97e6c22..8f54282b3 100644 --- a/lib/src/screens/yat/yat_alert.dart +++ b/lib/src/screens/yat/yat_alert.dart @@ -11,7 +11,9 @@ import 'package:lottie/lottie.dart'; class YatAlert extends StatelessWidget { YatAlert(this.yatStore) - : baseUrl = isYatDevMode ? baseDevUrl : baseReleaseUrl; + : baseUrl = YatLink.isDevMode + ? YatLink.baseDevUrl + : YatLink.baseReleaseUrl; final YatStore yatStore; final String baseUrl; @@ -86,7 +88,7 @@ class YatAlert extends StatelessWidget { .arrow_up_right_square, mainAxisAlignment: MainAxisAlignment.end, onPressed: () { - final url = baseUrl + createSuffix; + final url = baseUrl + YatLink.createSuffix; launch(url); }), Padding( @@ -102,11 +104,11 @@ class YatAlert extends StatelessWidget { .arrow_up_right_square, mainAxisAlignment: MainAxisAlignment.end, onPressed: () { - String url = baseUrl + signInSuffix; + String url = baseUrl + YatLink.signInSuffix; final parameters = yatStore.defineQueryParameters(); if (parameters.isNotEmpty) { - url += queryParameter + parameters; + url += YatLink.queryParameter + parameters; } launch(url); }) diff --git a/lib/src/screens/yat/yat_popup.dart b/lib/src/screens/yat/yat_popup.dart index 05d0c8dad..bae0af591 100644 --- a/lib/src/screens/yat/yat_popup.dart +++ b/lib/src/screens/yat/yat_popup.dart @@ -14,7 +14,9 @@ import 'package:url_launcher/url_launcher.dart'; class YatPopup extends StatelessWidget { YatPopup({this.dashboardViewModel, this.onClose}) - : baseUrl = isYatDevMode ? baseDevUrl : baseReleaseUrl; + : baseUrl = YatLink.isDevMode + ? YatLink.baseDevUrl + : YatLink.baseReleaseUrl; static const durationInMilliseconds = 250; @@ -157,15 +159,15 @@ class YatPopup extends StatelessWidget { child: ThirdIntroduction( onClose: onClose, onGet: () { - final url = baseUrl + createSuffix; + final url = baseUrl + YatLink.createSuffix; launch(url); }, onConnect: () { - String url = baseUrl + signInSuffix; + String url = baseUrl + YatLink.signInSuffix; final parameters = dashboardViewModel .yatStore.defineQueryParameters(); if (parameters.isNotEmpty) { - url += queryParameter + parameters; + url += YatLink.queryParameter + parameters; } launch(url); } diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 84887d32a..5b52f9b19 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -38,6 +38,7 @@ abstract class SettingsStoreBase with Store { @required Map nodes, @required TransactionPriority initialBitcoinTransactionPriority, @required TransactionPriority initialMoneroTransactionPriority, + @required this.shouldShowYatPopup, @required this.isBitcoinBuyEnabled, this.actionlistDisplayMode}) { fiatCurrency = initialFiatCurrency; @@ -59,6 +60,11 @@ abstract class SettingsStoreBase with Store { (FiatCurrency fiatCurrency) => sharedPreferences.setString( PreferencesKey.currentFiatCurrencyKey, fiatCurrency.serialize())); + reaction( + (_) => shouldShowYatPopup, + (bool shouldShowYatPopup) => sharedPreferences + .setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup)); + priority.observe((change) { final key = change.key == WalletType.monero ? PreferencesKey.moneroTransactionPriority @@ -110,6 +116,9 @@ abstract class SettingsStoreBase with Store { @observable FiatCurrency fiatCurrency; + @observable + bool shouldShowYatPopup; + @observable ObservableList actionlistDisplayMode; @@ -217,6 +226,8 @@ abstract class SettingsStoreBase with Store { final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId); final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId); final packageInfo = await PackageInfo.fromPlatform(); + final shouldShowYatPopup = + sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true; return SettingsStore( sharedPreferences: sharedPreferences, @@ -236,7 +247,8 @@ abstract class SettingsStoreBase with Store { initialPinLength: pinLength, initialLanguageCode: savedLanguageCode, initialMoneroTransactionPriority: moneroTransactionPriority, - initialBitcoinTransactionPriority: bitcoinTransactionPriority); + initialBitcoinTransactionPriority: bitcoinTransactionPriority, + shouldShowYatPopup: shouldShowYatPopup); } Future reload( @@ -270,6 +282,7 @@ abstract class SettingsStoreBase with Store { pinCodeLength = settings.pinCodeLength; languageCode = settings.languageCode; appVersion = settings.appVersion; + shouldShowYatPopup = settings.shouldShowYatPopup; } Future _saveCurrentNode(Node node, WalletType walletType) async { diff --git a/lib/store/yat/yat_store.dart b/lib/store/yat/yat_store.dart index 5c66c2937..6af8c99fc 100644 --- a/lib/store/yat/yat_store.dart +++ b/lib/store/yat/yat_store.dart @@ -15,18 +15,24 @@ import 'package:http/http.dart'; part 'yat_store.g.dart'; -const baseDevUrl = 'https://yat.fyi'; -const baseReleaseUrl = 'https://y.at'; -const signInSuffix = '/partner/CW/link-email'; -const createSuffix = '/create'; -const queryParameter = '?addresses='; -const requestDevUrl = 'https://a.yat.fyi/emoji_id/'; -const requestReleaseUrl = 'https://a.y.at/emoji_id/'; -const isYatDevMode = true; +class YatLink { + static const baseDevUrl = 'https://yat.fyi'; + static const baseReleaseUrl = 'https://y.at'; + static const signInSuffix = '/partner/CW/link-email'; + static const createSuffix = '/create'; + static const queryParameter = '?addresses='; + static const requestDevUrl = 'https://a.yat.fyi/emoji_id/'; + static const requestReleaseUrl = 'https://a.y.at/emoji_id/'; + static const isDevMode = true; + static const tags = >{"XMR" : ['0x1001', '0x1002'], + "BTC" : ['0x1003'], "LTC" : ['0x3fff']}; +} Future> fetchYatAddress(String emojiId, String ticker) async { - final requestURL = isYatDevMode ? requestDevUrl : requestReleaseUrl; - final url = requestURL + emojiId + '/' + ticker.toUpperCase(); + final requestURL = YatLink.isDevMode + ? YatLink.requestDevUrl + : YatLink.requestReleaseUrl; + final url = requestURL + emojiId; final response = await get(url); if (response.statusCode != 200) { @@ -41,11 +47,18 @@ Future> fetchYatAddress(String emojiId, String ticker) async { } final List addresses = []; + final currency = ticker.toUpperCase(); for (var elem in result) { - final yatAddress = elem['data'] as String; - if (yatAddress?.isNotEmpty ?? false) { - addresses.add(yatAddress); + final tag = elem['tag'] as String; + if (tag?.isEmpty ?? true) { + continue; + } + if (YatLink.tags[currency]?.contains(tag) ?? false) { + final yatAddress = elem['data'] as String; + if (yatAddress?.isNotEmpty ?? false) { + addresses.add(yatAddress); + } } } @@ -123,8 +136,8 @@ abstract class YatStoreBase with Store { } parameters += subaddress.address.startsWith('4') - ? '0x1001%3D' - : '0x1002%3D'; + ? YatLink.tags["XMR"].first + '%3D' + : YatLink.tags["XMR"].last + '%3D'; parameters += subaddress.address; }); @@ -141,7 +154,7 @@ abstract class YatStoreBase with Store { isFirstAddress = !isFirstAddress; } - parameters += '0x1003%3D' + record.address; + parameters += YatLink.tags["BTC"].first + '%3D' + record.address; }); break; case WalletType.litecoin: @@ -155,7 +168,7 @@ abstract class YatStoreBase with Store { isFirstAddress = !isFirstAddress; } - parameters += '0x3fff%3D' + record.address; + parameters += YatLink.tags["LTC"].first + '%3D' + record.address; }); break; default: diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index 623a2af86..b99e03ca6 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -236,6 +236,12 @@ abstract class DashboardViewModelBase with Store { bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled; + bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup; + + @action + void furtherShowYatPopup(bool shouldShow) => + settingsStore.shouldShowYatPopup = shouldShow; + ReactionDisposer _onMoneroAccountChangeReaction; ReactionDisposer _onMoneroBalanceChangeReaction;