From b92e98b299375d287271588b8377aaaa29b7eb09 Mon Sep 17 00:00:00 2001 From: mokeyCode Date: Thu, 27 Apr 2023 23:45:28 +0800 Subject: [PATCH] add new function --- images/2.0x/logo_b_40.png | Bin 0 -> 8880 bytes images/2.0x/qr.png | Bin 0 -> 558 bytes images/3.0x/logo_b_40.png | Bin 0 -> 13920 bytes images/3.0x/qr.png | Bin 0 -> 723 bytes images/logo_b_40.png | Bin 0 -> 3306 bytes images/qr.png | Bin 0 -> 383 bytes lib/common/color.dart | 3 + lib/common/global.dart | 4 +- lib/l10n/app_de.arb | 10 +- lib/l10n/app_en.arb | 10 +- lib/l10n/app_es.arb | 10 +- lib/l10n/app_fr.arb | 18 +- lib/l10n/app_it.arb | 10 +- lib/l10n/app_ja.arb | 10 +- lib/l10n/app_ru.arb | 10 +- lib/l10n/app_zh.arb | 10 +- lib/model/config_modal.dart | 9 +- lib/page/common/check_page.dart | 9 +- lib/page/common/langs_select.dart | 2 +- lib/page/common/webview.dart | 3 + lib/page/detail/receive_page.dart | 105 ++++---- lib/page/detail/transaction_page.dart | 334 +++++++++++++++----------- lib/page/wallet/wallet_page.dart | 5 +- lib/widget/home_button.dart | 5 +- lib/widget/home_transaction_item.dart | 4 +- lib/widget/home_widget.dart | 1 - lib/widget/modal_frame.dart | 5 +- lib/widget/wallet_header.dart | 38 ++- pubspec.lock | 8 +- pubspec.yaml | 14 +- 30 files changed, 368 insertions(+), 269 deletions(-) create mode 100644 images/2.0x/logo_b_40.png create mode 100644 images/2.0x/qr.png create mode 100644 images/3.0x/logo_b_40.png create mode 100644 images/3.0x/qr.png create mode 100644 images/logo_b_40.png create mode 100644 images/qr.png diff --git a/images/2.0x/logo_b_40.png b/images/2.0x/logo_b_40.png new file mode 100644 index 0000000000000000000000000000000000000000..27dfb21dcd39a1e976a9e5fe1a609f821c66469a GIT binary patch literal 8880 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 literal 0 HcmV?d00001 diff --git a/images/3.0x/logo_b_40.png b/images/3.0x/logo_b_40.png new file mode 100644 index 0000000000000000000000000000000000000000..53e8338727db555caecd3665949b702fa87b84fd GIT binary patch literal 13920 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 oM`i5rv*^stxtjS07*qoM6N<$g7a!TGXMYp literal 0 HcmV?d00001 diff --git a/images/qr.png b/images/qr.png new file mode 100644 index 0000000000000000000000000000000000000000..6f4d550c5989ea2a55e493e456fda8bfe8d0d6b9 GIT binary patch literal 383 zcmV-_0f7FAP)4$y%Pqytic=pZUMZ;rgrbTcr9CLfFv zf}uMke8%Q5{BL1|T^G4i}&i#hQa7PO=0??59CGWXLMV z?tUR4Qq{<=BzTq1|Gz2Sn!bn6*%qBM&kZo#rk>c9&tD|mfg5n_30%`#$o7;TQ8JtY dCKZEzk0

&V>XKsr&!{002ovPDHLkV1f*xmofkV literal 0 HcmV?d00001 diff --git a/lib/common/color.dart b/lib/common/color.dart index bf057e6..6e44bbf 100644 --- a/lib/common/color.dart +++ b/lib/common/color.dart @@ -12,6 +12,9 @@ class DarkColors { static const bottomNavColor = Color(0xCCA0A3BD); static const transactionColor = Color(0x4DA0A3BD); static const greenColor = Color(0xFF168A3C); + // 20% opacity + static const greenColorMask = Color(0x66168A3C); + static const redColor = Color(0xFFDD4556); // gold static const yellowColor = Color(0xFFE8B000); diff --git a/lib/common/global.dart b/lib/common/global.dart index 10b7303..e83ae59 100644 --- a/lib/common/global.dart +++ b/lib/common/global.dart @@ -43,10 +43,10 @@ class Global { static String buildNumber = ''; static const String rpcURL = 'https://testnet-rpc.xdagj.org'; - static const String explorURL = 'https://testexplorer.xdag.io/api'; + static const String explorURL = 'https://testexplorer.xdag.io'; static const String mainRpcURL = 'https://mainnet-rpc.xdagj.org'; - static const String mainExplorURL = 'https://mainnet-explorer.xdagj.org/api'; + static const String mainExplorURL = 'https://mainnet-explorer.xdagj.org'; static const bool isTest = false; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index ff10bd5..091fb38 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -120,8 +120,14 @@ "contact_tips":"Bitte beachten Sie, dass Kontakte nur lokal auf diesem Gerät gespeichert werden. Wenn Sie die App löschen, gehen Ihre Kontakte dauerhaft verloren und können nicht wiederhergestellt werden.", "no_contacts":"Keine Kontakte", "tips":"Tipps", - "wallet_tips":"Wischen Sie den Eintrag nach rechts, um das Wallet zu löschen。", + "wallet_tips":"Wischen Sie das Element nach links, um die Brieftasche zu löschen.", "hide_balance":"Guthaben ausblenden", "contact_address_repeat": "Kontaktadresse existiert bereits", - "no_wallets":"Keine Wallet" + "no_wallets":"Keine Wallet", + "view_in_explorer":"Im Explorer anzeigen", + "details":"Details", + "sent":"Gesendet", + "received":"Empfangen", + "qr_code":"QR-code", + "save_to_album":"In Album speichern" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 88d7e27..3b0f892 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -120,8 +120,14 @@ "contact_tips":"Please note that contacts are only stored locally on this device. If you delete the app, your contacts will be permanently lost and cannot be recovered.", "no_contacts":"Any contact", "tips":"Tips", - "wallet_tips":"Swipe the item to the right to delete the wallet.", + "wallet_tips":"Swipe the item to the left to delete the wallet.", "hide_balance":"Hide Balance", "contact_address_repeat":"Contact address already exists", - "no_wallets":"Any wallet" + "no_wallets":"Any wallet", + "view_in_explorer":"View in explorer", + "details":"Details", + "sent":"Sent", + "received":"Received", + "qr_code":"QR Code", + "save_to_album":"Save to album" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 4ccc523..e363b25 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -120,8 +120,14 @@ "contact_tips": "Ten en cuenta que los contactos se almacenan solo localmente en este dispositivo. Si eliminas la aplicación, tus contactos se perderán permanentemente y no se podrán recuperar.", "no_contacts": "Cualquier contacto", "tips": "Consejos", - "wallet_tips": "Desliza el elemento hacia la derecha para eliminar la billetera.", + "wallet_tips":"Desliza el elemento hacia la izquierda para eliminar la billetera.", "hide_balance": "Ocultar saldo", "contact_address_repeat": "La dirección del contacto ya existe", - "no_wallets": "Cualquier cartera" + "no_wallets": "Cualquier cartera", + "view_in_explorer": "Ver en el explorador", + "details": "Detalles", + "sent": "Enviado", + "received": "Recibido", + "qr_code": "Código QR", + "save_to_album": "Guardar en el álbum" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 5c7fbc6..d517a33 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -48,11 +48,11 @@ "enter_password": "Entrez le code secret", "use_biometrics_tips_1": "Appuyez pour utiliser Face ID", "use_biometrics_tips_2": "Appuyez pour utiliser Touch ID", - "use_biometrics_tips_3": "Appuyez pour utiliser les biométriques", + "use_biometrics_tips_3": "Appuyez pour utiliser contrôle biométrique", "use_password": "Utiliser le code secret", "use_biometrics_1": "Utiliser Face ID", "use_biometrics_2": "Utiliser Touch ID", - "use_biometrics_3": "Utiliser les biométriques", + "use_biometrics_3": "Utiliser contrôle biométrique", "delete_tip": "Si vous supprimez votre portefeuille sans le sauvegarder, vous perdrez tous vos actifs numériques de manière permanente et ils ne pourront pas être récupérés.", "write_Down_Mnemonics": "Noter les mnémoniques", "write_Down_PrivateKey": "Noter la clé privée", @@ -63,10 +63,10 @@ "change_password_success": "Code secret changé avec succès", "enable_biometrics_1": "Activer Face ID", "enable_biometrics_2": "Activer Touch ID", - "enable_biometrics_3": "Activer les biométriques", + "enable_biometrics_3": "Activer contrôle biométrique", "disenable_biometrics_1": "Désactiver Face ID", "disenable_biometrics_2": "Désactiver Touch ID", - "disenable_biometrics_3": "Désactiver les biométriques", + "disenable_biometrics_3": "Désactiver contrôle biométrique", "no_transactions": "Aucune transaction", "send_on": "Envoyé le", "receive_on": "Reçu le", @@ -120,8 +120,14 @@ "contact_tips":"Veuillez noter que les contacts sont uniquement stockés localement sur cet appareil. Si vous supprimez l'application, vos contacts seront définitivement perdus et ne pourront pas être récupérés.", "no_contacts":"Aucun contact", "tips":"Conseils", - "wallet_tips":"Balayez l'élément vers la droite pour supprimer le portefeuille.", + "wallet_tips":"Balayez l'élément vers la gauche pour supprimer le portefeuille.", "hide_balance":"Masquer le solde", "contact_address_repeat": "L'adresse de contact existe déjà", - "no_wallets": "Aucun portefeuille" + "no_wallets": "Aucun portefeuille", + "view_in_explorer": "Voir dans l'explorateur", + "details": "Détails", + "sent": "Envoyé", + "received": "Reçu", + "qr_code": "Code QR", + "save_to_album": "Enregistrer dans l'album" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 5e98bc5..8707f5a 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -120,8 +120,14 @@ "contact_tips": "Si prega di notare che i contatti sono conservati solo localmente su questo dispositivo. Se si elimina l'app, i contatti verranno persi in modo permanente e non saranno recuperabili.", "no_contacts": "Nessun contatto", "tips": "Suggerimenti", - "wallet_tips": "Scorri l'elemento verso destra per eliminare il portafoglio", + "wallet_tips": "Scorri l'elemento a sinistra per eliminare il portafoglio.", "hide_balance": "Nascondi saldo", "contact_address_repeat": "L'indirizzo del contatto è già stato aggiunto", - "no_wallets": "Nessun portafoglio" + "no_wallets": "Nessun portafoglio", + "view_in_explorer": "Visualizza in Explorer", + "details":"dettagli", + "sent":"Inviato", + "received":"Ricevuto", + "qr_code":"Codice QR", + "save_to_album":"Salva in album" } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 49c9c0d..f67f8c2 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -120,8 +120,14 @@ "contact_tips":"連絡先はこのデバイスにのみ保存されます。アプリを削除すると、連絡先は永久に失われ、回復できません。", "no_contacts":"連絡先がありません", "tips":"ヒント", - "wallet_tips":"ウォレットを削除するには、アイテムを右にスワイプしてください。", + "wallet_tips":"財布を削除するには、アイテムを左にスワイプしてください。", "hide_balance":"残高を非表示", "contact_address_repeat": "連絡先がすでに存在しています", - "no_wallets":"ウォレットがありません" + "no_wallets":"ウォレットがありません", + "view_in_explorer":"エクスプローラーで表示", + "details":"詳細", + "sent":"送信", + "received":"受け取る", + "qr_code":"QRコード", + "save_to_album":"アルバムに保存" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index fa8d18e..1390443 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -120,8 +120,14 @@ "contact_tips":"Обратите внимание, что контакты хранятся только локально на этом устройстве. Если вы удалите приложение, ваши контакты будут навсегда потеряны и не могут быть восстановлены.", "no_contacts":"Нет контактов", "tips":"Советы", - "wallet_tips":"Чтобы удалить кошелек, проведите элемент вправо.", + "wallet_tips":"Чтобы удалить кошелек, проведите элемент влево.", "hide_balance":"Скрыть баланс", "contact_address_repeat": "Контактный адрес уже существует", - "no_wallets":"Нет кошельков" + "no_wallets":"Нет кошельков", + "view_in_explorer":"Посмотреть в исследователе", + "details":"Детали", + "sent":"Отправлено", + "received":"Получено", + "qr_code":"QR-код", + "save_to_album":"Сохранить в альбом" } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 01d1f2e..46109e2 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -120,8 +120,14 @@ "contact_tips":"请注意,联系人仅存储在本地设备上。如果您删除应用程序,您的联系人将永久丢失,无法找回。", "no_contacts":"没有联系人", "tips":"提示", - "wallet_tips":"向右滑动该项以删除钱包。", + "wallet_tips":"向左滑动该项以删除钱包。", "hide_balance":"隐藏余额", "contact_address_repeat": "联系地址已存在", - "no_wallets":"没有钱包" + "no_wallets":"没有钱包", + "view_in_explorer":"在浏览器中查看", + "details":"详情", + "sent":"发送", + "received":"接收", + "qr_code":"二维码", + "save_to_album":"保存到相册" } \ No newline at end of file diff --git a/lib/model/config_modal.dart b/lib/model/config_modal.dart index 5d79459..b6db261 100644 --- a/lib/model/config_modal.dart +++ b/lib/model/config_modal.dart @@ -21,8 +21,8 @@ class ConfigModal extends ChangeNotifier { LangItem('Français', const Locale('fr', 'FR')), LangItem('Русский', const Locale('ru', 'RU')), LangItem('Deutsch', const Locale('de', 'DE')), - LangItem('Spanish', const Locale('es', 'ES')), - LangItem('Italy', const Locale('it', 'IT')), + LangItem('Español', const Locale('es', 'ES')), + LangItem('Italiano', const Locale('it', 'IT')), ]; static final List netWorks = ["MainNet", "TestNet"]; @@ -37,8 +37,9 @@ class ConfigModal extends ChangeNotifier { return walletConfig.network == 0 ? Global.mainRpcURL : Global.rpcURL; } - String getCurrentExplorer() { - return walletConfig.network == 0 ? Global.mainExplorURL : Global.explorURL; + String getCurrentExplorer({isApi = true}) { + var url = walletConfig.network == 0 ? Global.mainExplorURL : Global.explorURL; + return isApi ? '$url/api' : url; } changeNetwork(int pos) async { diff --git a/lib/page/common/check_page.dart b/lib/page/common/check_page.dart index cdc6973..6a7099c 100644 --- a/lib/page/common/check_page.dart +++ b/lib/page/common/check_page.dart @@ -47,9 +47,13 @@ class _CheckPageState extends State { Widget build(BuildContext context) { ConfigModal config = Provider.of(context); String tipsText = type == 0 ? AppLocalizations.of(context).use_biometrics_tips_1 : AppLocalizations.of(context).use_biometrics_tips_2; + String btnTex = type == 0 ? AppLocalizations.of(context).use_biometrics_1 : AppLocalizations.of(context).use_biometrics_2; if (type > 0 && Platform.isAndroid) { tipsText = AppLocalizations.of(context).use_biometrics_tips_3; } + if (Platform.isAndroid) { + btnTex = AppLocalizations.of(context).use_biometrics_3; + } var padding = Helper.isDesktop ? 10.0 : ScreenHelper.topPadding; return Scaffold( backgroundColor: DarkColors.bgColor, @@ -95,12 +99,15 @@ class _CheckPageState extends State { setState(() { type = type == -1 ? Global.devBiometricsType : -1; }); + if (type != -1) { + check(); + } }, child: Container( height: 40, padding: const EdgeInsets.symmetric(horizontal: 20), child: Center( - child: Text(AppLocalizations.of(context).use_password, style: Helper.fitChineseFont(context, const TextStyle(fontSize: 16, fontWeight: FontWeight.w700, color: Colors.white))), + child: Text(type == -1 ? btnTex : AppLocalizations.of(context).use_password, style: Helper.fitChineseFont(context, const TextStyle(fontSize: 16, fontWeight: FontWeight.w700, color: Colors.white))), ), ), ) diff --git a/lib/page/common/langs_select.dart b/lib/page/common/langs_select.dart index 34760a2..1230345 100644 --- a/lib/page/common/langs_select.dart +++ b/lib/page/common/langs_select.dart @@ -73,7 +73,7 @@ class NetWorkSelectPage extends StatelessWidget { ConfigModal config = Provider.of(context); double bottomPadding = ScreenHelper.bottomPadding; List netWorks = ConfigModal.netWorks; - double height = 60 + (bottomPadding > 0 ? bottomPadding : 20) + 70 * netWorks.length + 10; + double height = 60 + (bottomPadding > 0 ? bottomPadding : 20) + 70 * netWorks.length + 10 + 30; return ModalFrame( height: height, title: AppLocalizations.of(context).select_network, diff --git a/lib/page/common/webview.dart b/lib/page/common/webview.dart index 9d50c03..7cd1aa2 100644 --- a/lib/page/common/webview.dart +++ b/lib/page/common/webview.dart @@ -32,6 +32,9 @@ class _WebViewPageState extends State { onPageStarted: (String url) {}, onPageFinished: (String url) {}, onWebResourceError: (WebResourceError error) {}, + onNavigationRequest: (NavigationRequest request) { + return NavigationDecision.navigate; + }, ), ); diff --git a/lib/page/detail/receive_page.dart b/lib/page/detail/receive_page.dart index 6dc769a..b9c7a0b 100644 --- a/lib/page/detail/receive_page.dart +++ b/lib/page/detail/receive_page.dart @@ -21,81 +21,70 @@ class ReceivePage extends StatelessWidget { double marginH = 20; double paddingH = 15; TextStyle titleStyle = Helper.fitChineseFont(context, const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w400)); - TextStyle addressStyle = Helper.fitChineseFont(context, const TextStyle(color: Colors.white54, fontSize: 16, fontWeight: FontWeight.w700)); + // TextStyle addressStyle = Helper.fitChineseFont(context, const TextStyle(color: Colors.white54, fontSize: 16, fontWeight: FontWeight.w700)); return ModalFrame( - title: '${AppLocalizations.of(context).receive} XDAG', + title: AppLocalizations.of(context).qr_code, + child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - ContentBox( - marginH: marginH, - child: Padding( - padding: const EdgeInsets.all(15.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(AppLocalizations.of(context).show_QR, style: titleStyle), - const SizedBox(height: 15), - Center( - child: Container( - width: 250, - height: 250, - decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10)), - child: Center( - child: QrImage(data: wallet.address, version: QrVersions.auto), - ), - ), - ), - ], - ), - ), - ), ContentBox( marginH: marginH, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.fromLTRB(paddingH, 15, paddingH, 15), + padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(AppLocalizations.of(context).share_wallet_address, style: titleStyle), - const SizedBox(height: 8), - Text(wallet.address, style: addressStyle), + Text(AppLocalizations.of(context).show_QR, style: titleStyle), + const SizedBox(height: 15), + Center( + child: Container( + width: 250, + height: 250, + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10)), + child: Center( + child: QrImage( + data: wallet.address, + version: QrVersions.auto, + embeddedImage: const AssetImage('images/logo_b_40.png'), + embeddedImageStyle: QrEmbeddedImageStyle( + size: const Size(40, 40), + ), + ), + ), + ), + ), ], ), ), Container(height: 1, color: DarkColors.bgColor), - SizedBox( - height: 50, - child: Row( - children: [ - Expanded( - child: Button( - icon: Icons.copy_rounded, - onPressed: () { - Clipboard.setData(ClipboardData(text: wallet.address)); - Helper.showToast(context, AppLocalizations.of(context).copied_to_clipboard); - }, - title: AppLocalizations.of(context).copy, - )), - // Container(width: 1, color: DarkColors.bgColor), - // Expanded( - // child: Button( - // icon: Icons.share_rounded, - // onPressed: () {}, - // title: AppLocalizations.of(context).share, - // )), - ], - ), - ), + // SizedBox( + // height: 50, + // child: Row( + // children: [ + // Expanded( + // child: Button( + // icon: Icons.download, + // onPressed: () { + // Clipboard.setData(ClipboardData(text: wallet.address)); + // Helper.showToast(context, AppLocalizations.of(context).copied_to_clipboard); + // }, + // title: AppLocalizations.of(context).save_to_album, + // )), + // ], + // ), + // ), ], ), ), ], - )); + ), + ), + ); } } @@ -126,14 +115,6 @@ class Button extends StatelessWidget { @override Widget build(BuildContext context) { TextStyle btnStyle = Helper.fitChineseFont(context, const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w400)); - return MyCupertinoButton( - padding: EdgeInsets.zero, - onPressed: onPressed, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [Icon(icon, color: Colors.white, size: 20), const SizedBox(width: 10), Text(title, style: btnStyle)], - ), - ); + return MyCupertinoButton(padding: EdgeInsets.zero, onPressed: onPressed, child: Text(title, style: btnStyle)); } } diff --git a/lib/page/detail/transaction_page.dart b/lib/page/detail/transaction_page.dart index a6c40d3..8b76bf6 100644 --- a/lib/page/detail/transaction_page.dart +++ b/lib/page/detail/transaction_page.dart @@ -1,13 +1,16 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; -import 'package:extended_text/extended_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher_string.dart'; import 'package:xdag/common/color.dart'; import 'package:xdag/common/helper.dart'; import 'package:xdag/model/config_modal.dart'; import 'package:xdag/model/contacts_modal.dart'; import 'package:xdag/model/wallet_modal.dart'; +import 'package:xdag/page/common/webview.dart'; import 'package:xdag/widget/button.dart'; import 'package:xdag/widget/desktop.dart'; import 'package:xdag/widget/modal_frame.dart'; @@ -28,7 +31,7 @@ class _TransactionPageState extends State { String fee = ""; String hash = ""; String transactionState = 'Pending'; - double height = 430; + // double height = 430; final dio = Dio(); CancelToken cancelToken = CancelToken(); @@ -98,10 +101,23 @@ class _TransactionPageState extends State { // 查询 otherAddress 是否在 contacts.contactsList 中 ContactsItem otherContact = contacts.contactsList.firstWhere((element) => element.address == otherAddress, orElse: () => ContactsItem("", otherAddress)); - // if(transaction.amount) + ConfigModal config = Provider.of(context); return ModalFrame( - height: height, - title: isSend ? AppLocalizations.of(context).send : AppLocalizations.of(context).receive, + // height: height, + title: '', + titleWidget: Center( + child: Container( + padding: const EdgeInsets.fromLTRB(10, 5, 10, 5), + decoration: BoxDecoration( + color: config.walletConfig.network == 1 ? DarkColors.redColorMask2 : DarkColors.greenColorMask, + borderRadius: BorderRadius.circular(5), + ), + child: Text( + config.walletConfig.network == 1 ? "TestNet" : "MainNet", + style: Helper.fitChineseFont(context, const TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: Colors.white70)), + ), + ), + ), rightBtn: CircleButton( icon: Icons.refresh, onPressed: () { @@ -114,82 +130,112 @@ class _TransactionPageState extends State { isShowRightCloseButton: true, child: Column( children: [ - Text(isSend ? '-${transaction.amount} XDAG' : '+${transaction.amount} XDAG', style: Helper.fitChineseFont(context, TextStyle(decoration: TextDecoration.none, fontSize: 22, fontWeight: FontWeight.w700, color: isSend ? DarkColors.bottomNavColor : DarkColors.greenColor))), - const SizedBox(height: 5), - if (transaction.status == 'pending') - Text( - "${AppLocalizations.of(context).state}: $transactionState", - style: Helper.fitChineseFont(context, TextStyle(decoration: TextDecoration.none, fontSize: 14, fontWeight: FontWeight.w400, color: transactionState == 'Accepted' ? DarkColors.greenColor : DarkColors.redColor)), - ) - else - const SizedBox(), - if (transaction.time.isEmpty) - const SizedBox() - else - Text( - "${isSend ? AppLocalizations.of(context).send_on : AppLocalizations.of(context).receive_on} ${Helper.formatFullTime(transaction.time)} UTC", - style: Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 14, fontWeight: FontWeight.w400, color: Colors.white54)), - ), - const SizedBox(height: 25), - if (isLoading) - const SizedBox( - height: 152, - child: Center( - child: SizedBox( - width: 50, - height: 50, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(DarkColors.mainColor), - ), - ), - ), - ) - else - Column( + Expanded( + child: SingleChildScrollView( + child: Column( children: [ - MyCupertinoButton( - padding: EdgeInsets.zero, - child: TransactionButton( - showCopy: true, - borderRadius: const BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8)), - title: isSend ? AppLocalizations.of(context).receiver : AppLocalizations.of(context).sender, - value: otherContact.name.isEmpty ? otherContact.address : otherContact.name, - leftIcon: otherContact.name.isEmpty ? const Icon(Icons.add, color: Colors.white, size: 10) : const Icon(Icons.person, color: Colors.white, size: 10), + const SizedBox(height: 10), + Text(isSend ? '-${transaction.amount} XDAG' : '+${transaction.amount} XDAG', style: Helper.fitChineseFont(context, TextStyle(decoration: TextDecoration.none, fontSize: 24, fontWeight: FontWeight.w700, color: isSend ? DarkColors.bottomNavColor : DarkColors.greenColor))), + const SizedBox(height: 5), + if (transaction.status == 'pending') + Text( + "${AppLocalizations.of(context).state}: $transactionState", + style: Helper.fitChineseFont(context, TextStyle(decoration: TextDecoration.none, fontSize: 14, fontWeight: FontWeight.w400, color: transactionState == 'Accepted' ? DarkColors.greenColor : DarkColors.redColor)), + ) + else + const SizedBox(), + if (transaction.time.isEmpty) + const SizedBox() + else + Text( + "${isSend ? AppLocalizations.of(context).send_on : AppLocalizations.of(context).receive_on} ${Helper.formatFullTime(transaction.time)} UTC", + style: Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 14, fontWeight: FontWeight.w400, color: Colors.white54)), + ), + const SizedBox(height: 25), + if (isLoading) + const SizedBox( + height: 152, + child: Center( + child: SizedBox( + width: 50, + height: 50, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(DarkColors.mainColor), + ), + ), ), - onPressed: () { - Navigator.of(context).pop(otherContact); - }), - const SizedBox(height: 1), - MyCupertinoButton( - padding: EdgeInsets.zero, - child: TransactionButton(showCopy: true, title: "Hash", value: hash), - onPressed: () { - Clipboard.setData(ClipboardData(text: hash)); - Helper.showToast(context, AppLocalizations.of(context).copied_to_clipboard); - }), - const SizedBox(height: 1), - MyCupertinoButton( - padding: EdgeInsets.zero, - child: TransactionButton(showCopy: true, title: AppLocalizations.of(context).block_address, value: transaction.blockAddress), - onPressed: () { - Clipboard.setData(ClipboardData(text: transaction.blockAddress)); - Helper.showToast(context, AppLocalizations.of(context).copied_to_clipboard); - }), - const SizedBox(height: 1), - TransactionButton( - showCopy: false, - title: AppLocalizations.of(context).fee, - value: '$fee XDAG', - ), - const SizedBox(height: 1), - TransactionButton( - showCopy: false, - title: AppLocalizations.of(context).remark, - value: transaction.remark, - borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8)), + ) + else + Column( + children: [ + MyCupertinoButton( + padding: EdgeInsets.zero, + child: TransactionButton( + showCopy: true, + borderRadius: const BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8)), + title: isSend ? AppLocalizations.of(context).receiver : AppLocalizations.of(context).sender, + value: otherContact.name.isEmpty ? otherContact.address : otherContact.name, + leftIcon: otherContact.name.isEmpty ? const Icon(Icons.person_add, color: Colors.white, size: 10) : const Icon(Icons.person, color: Colors.white, size: 10), + ), + onPressed: () { + Navigator.of(context).pop(otherContact); + }), + const SizedBox(height: 1), + MyCupertinoButton( + padding: EdgeInsets.zero, + child: TransactionButton(showCopy: true, title: "Hash", value: hash), + onPressed: () { + Clipboard.setData(ClipboardData(text: hash)); + Helper.showToast(context, AppLocalizations.of(context).copied_to_clipboard); + }), + const SizedBox(height: 1), + MyCupertinoButton( + padding: EdgeInsets.zero, + child: TransactionButton(showCopy: true, title: AppLocalizations.of(context).block_address, value: transaction.blockAddress), + onPressed: () { + Clipboard.setData(ClipboardData(text: transaction.blockAddress)); + Helper.showToast(context, AppLocalizations.of(context).copied_to_clipboard); + }), + const SizedBox(height: 1), + TransactionButton(showCopy: false, title: AppLocalizations.of(context).fee, value: '$fee XDAG', borderRadius: transaction.remark.isNotEmpty ? BorderRadius.zero : const BorderRadius.only(bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8))), + const SizedBox(height: 1), + if (transaction.remark.isNotEmpty) + TransactionButton( + showCopy: false, + title: AppLocalizations.of(context).remark, + value: transaction.remark, + borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8)), + ), + ], + ), + ], + ), + )), + Container( + margin: EdgeInsets.fromLTRB(15, 20, 15, ScreenHelper.bottomPadding > 0 ? ScreenHelper.bottomPadding : 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Button( + text: AppLocalizations.of(context).view_in_explorer, + width: ScreenHelper.screenWidth - 30, + bgColor: DarkColors.blockColor, + textColor: Colors.white, + onPressed: () async { + // Navigator.of(context).pop(true); + ConfigModal config = Provider.of(context, listen: false); + var url = '${config.getCurrentExplorer(isApi: false)}/block/${transaction.blockAddress}'; + if (Platform.isAndroid || Platform.isIOS) { + Navigator.pushNamed(context, '/webview', arguments: WebViewPageRouteParams(url: url, title: "")); + } else { + launchUrlString(url, mode: LaunchMode.externalApplication); + } + // print(transaction.blockAddress); + }, ), ], - ) + ), + ), ], ), ); @@ -203,47 +249,61 @@ class TransactionShowDetail extends StatelessWidget { @override Widget build(BuildContext context) { bool isSameAddress = transaction.from == transaction.to; + ConfigModal config = Provider.of(context); return ModalFrame( - height: 430, + height: transaction.remark.isEmpty ? 400 : 450, title: '', + titleWidget: Center( + child: Container( + padding: const EdgeInsets.fromLTRB(10, 5, 10, 5), + decoration: BoxDecoration( + color: config.walletConfig.network == 1 ? DarkColors.redColorMask2 : DarkColors.greenColorMask, + borderRadius: BorderRadius.circular(5), + ), + child: Text( + config.walletConfig.network == 1 ? "TestNet" : "MainNet", + style: Helper.fitChineseFont(context, const TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: Colors.white70)), + ), + ), + ), isHideLeftDownButton: true, isShowRightCloseButton: true, child: Column( children: [ Expanded( - child: Column( - children: [ - Text('${transaction.amount} XDAG', textAlign: TextAlign.center, style: Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 22, fontWeight: FontWeight.w700, color: DarkColors.greenColor))), - const SizedBox(height: 20), - TransactionButton( - showCopy: false, - readFont: isSameAddress, - borderRadius: const BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8)), - title: AppLocalizations.of(context).receiver, - value: transaction.to, - ), - const SizedBox(height: 1), - TransactionButton( - showCopy: false, - readFont: isSameAddress, - borderRadius: BorderRadius.zero, - title: AppLocalizations.of(context).sender, - value: transaction.from, - ), - const SizedBox(height: 1), - TransactionButton( - showCopy: false, - title: AppLocalizations.of(context).fee, - value: '0.00 XDAG', - ), - const SizedBox(height: 1), - TransactionButton( - showCopy: false, - title: AppLocalizations.of(context).remark, - value: transaction.remark, - borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8)), - ), - ], + child: SingleChildScrollView( + child: Column( + children: [ + const SizedBox(height: 10), + Text('${transaction.amount} XDAG', textAlign: TextAlign.center, style: Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 24, fontWeight: FontWeight.w700, color: DarkColors.greenColor))), + const SizedBox(height: 20), + TransactionButton( + showCopy: false, + readFont: isSameAddress, + borderRadius: const BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8)), + title: AppLocalizations.of(context).receiver, + value: transaction.to, + ), + const SizedBox(height: 1), + TransactionButton( + showCopy: false, + readFont: isSameAddress, + borderRadius: BorderRadius.zero, + title: AppLocalizations.of(context).sender, + value: transaction.from, + ), + const SizedBox(height: 1), + TransactionButton(showCopy: false, title: AppLocalizations.of(context).fee, value: '0.00 XDAG', borderRadius: transaction.remark.isNotEmpty ? BorderRadius.zero : const BorderRadius.only(bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8))), + const SizedBox(height: 1), + if (transaction.remark.isNotEmpty) + TransactionButton( + showCopy: false, + title: AppLocalizations.of(context).remark, + value: transaction.remark, + borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8)), + ), + ], + ), )), Container( margin: EdgeInsets.fromLTRB(15, 20, 15, ScreenHelper.bottomPadding > 0 ? ScreenHelper.bottomPadding : 20), @@ -279,49 +339,35 @@ class TransactionButton extends StatelessWidget { @override Widget build(BuildContext context) { - TextStyle titleStyle = Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 16, fontWeight: FontWeight.w400, color: Colors.white54)); - TextStyle valueStyle = Helper.fitChineseFont(context, TextStyle(decoration: TextDecoration.none, fontSize: 12, fontWeight: FontWeight.w700, color: readFont ? DarkColors.redColor : Colors.white)); - Widget icon = showCopy == true - ? Container( - margin: const EdgeInsets.only(left: 5), - width: 20, - height: 20, - decoration: const BoxDecoration( - color: DarkColors.bgColor, - borderRadius: BorderRadius.all(Radius.circular(14)), - ), - child: leftIcon ?? const Icon(Icons.copy_rounded, size: 10, color: Colors.white)) - : const SizedBox(width: 0); + TextStyle titleStyle = Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 16, fontWeight: FontWeight.w700, color: Colors.white54)); + TextStyle valueStyle = Helper.fitChineseFont(context, TextStyle(decoration: TextDecoration.none, fontSize: 14, fontWeight: FontWeight.w400, color: readFont ? DarkColors.redColor : Colors.white)); return Container( - height: 50, + constraints: const BoxConstraints(minHeight: 50.0), margin: const EdgeInsets.fromLTRB(15, 0, 15, 0), + padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: DarkColors.blockColor, borderRadius: borderRadius, ), child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const SizedBox(width: 10), Text(title, style: titleStyle), - // const Spacer(), - const SizedBox(width: 10), - // Text(value, style: valueStyle, maxLines: 2), - Expanded( - child: ExtendedText( - value, - textAlign: TextAlign.right, - maxLines: 1, - style: valueStyle, - overflowWidget: TextOverflowWidget( - position: TextOverflowPosition.middle, - align: TextOverflowAlign.center, - child: Text('...', style: valueStyle), - ), - ), + const SizedBox(width: 20), + Flexible( + fit: FlexFit.tight, + child: Text(value, textAlign: TextAlign.right, maxLines: 5, style: valueStyle), ), - - icon, - const SizedBox(width: 10), + if (showCopy == true) + Container( + margin: const EdgeInsets.only(left: 5), + width: 24, + height: 24, + decoration: const BoxDecoration( + color: DarkColors.bgColor, + borderRadius: BorderRadius.all(Radius.circular(15)), + ), + child: leftIcon ?? const Icon(Icons.copy_rounded, size: 12, color: Colors.white)) ], ), ); diff --git a/lib/page/wallet/wallet_page.dart b/lib/page/wallet/wallet_page.dart index 38dfbdf..76107c3 100644 --- a/lib/page/wallet/wallet_page.dart +++ b/lib/page/wallet/wallet_page.dart @@ -21,7 +21,6 @@ class WalletPageState extends State { final _refreshIndicatorKey = GlobalKey(); String _crurrentAddress = ""; int _network = 0; - // String lastTime = ""; List list = []; final dio = Dio(); CancelToken cancelToken = CancelToken(); @@ -56,8 +55,10 @@ class WalletPageState extends State { _onConfigModalChange() { WalletModal walletModal = Provider.of(context, listen: false); - if (_network != Provider.of(context, listen: false).walletConfig.network) { + var newNetwork = Provider.of(context, listen: false).walletConfig.network; + if (_network != newNetwork) { _refreshIndicatorKey.currentState?.deactivate(); + _network = newNetwork; setState(() { list = []; }); diff --git a/lib/widget/home_button.dart b/lib/widget/home_button.dart index 8d3e18f..ef5754c 100644 --- a/lib/widget/home_button.dart +++ b/lib/widget/home_button.dart @@ -7,7 +7,8 @@ class HomeHeaderButton extends StatelessWidget { final VoidCallback? onPressed; final String title; final String icon; - const HomeHeaderButton({super.key, required this.title, required this.icon, this.onPressed}); + final Widget? iconWidget; + const HomeHeaderButton({super.key, this.iconWidget, required this.title, required this.icon, this.onPressed}); @override Widget build(BuildContext context) { @@ -27,7 +28,7 @@ class HomeHeaderButton extends StatelessWidget { children: [ Row( children: [ - Image.asset(icon, width: 20, height: 20), + iconWidget ?? Image.asset(icon, width: 20, height: 20), const Spacer(), ], ), diff --git a/lib/widget/home_transaction_item.dart b/lib/widget/home_transaction_item.dart index 0b155f3..ae75082 100644 --- a/lib/widget/home_transaction_item.dart +++ b/lib/widget/home_transaction_item.dart @@ -69,8 +69,8 @@ class WalletTransactionItem extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(isSnapshot ? AppLocalizations.of(context).snapshot : (isSend ? AppLocalizations.of(context).send : AppLocalizations.of(context).receive), style: Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white))), - const SizedBox(height: 3), + Text(isSnapshot ? AppLocalizations.of(context).snapshot : (isSend ? AppLocalizations.of(context).sent : AppLocalizations.of(context).received), style: Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white))), + const SizedBox(height: 5), Text('${Helper.formatTime(transaction.time)} UTC', style: Helper.fitChineseFont(context, const TextStyle(decoration: TextDecoration.none, fontSize: 12, fontWeight: FontWeight.w400, color: Colors.white54))), ], ), diff --git a/lib/widget/home_widget.dart b/lib/widget/home_widget.dart index 231a547..0825104 100644 --- a/lib/widget/home_widget.dart +++ b/lib/widget/home_widget.dart @@ -86,7 +86,6 @@ class _HomeMainState extends State { double screenHeight = MediaQuery.of(context).size.height; double contentHeight = ScreenHelper.topPadding + 55 + 20 + (ScreenHelper.bottomPadding > 0 ? ScreenHelper.bottomPadding : 20) + 50 + 20 + 50; double h = (screenHeight - contentHeight) / 2; - print(screenHeight); return Stack( fit: StackFit.expand, children: [ diff --git a/lib/widget/modal_frame.dart b/lib/widget/modal_frame.dart index 92d4a83..26a730e 100644 --- a/lib/widget/modal_frame.dart +++ b/lib/widget/modal_frame.dart @@ -27,11 +27,12 @@ class CircleButton extends StatelessWidget { class ModalFrame extends StatelessWidget { final Widget child; final String title; + final Widget? titleWidget; final double? height; final bool? isHideLeftDownButton; final bool? isShowRightCloseButton; final Widget? rightBtn; - const ModalFrame({super.key, required this.child, required this.title, this.height, this.isHideLeftDownButton, this.isShowRightCloseButton, this.rightBtn}); + const ModalFrame({super.key, this.titleWidget, required this.child, required this.title, this.height, this.isHideLeftDownButton, this.isShowRightCloseButton, this.rightBtn}); @override Widget build(BuildContext context) { @@ -62,7 +63,7 @@ class ModalFrame extends StatelessWidget { children: [ leftButton, const SizedBox(width: 10), - Expanded(child: Text(title, textAlign: TextAlign.center, style: Helper.fitChineseFont(context, const TextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.w700)))), + Expanded(child: titleWidget ?? Text(title, textAlign: TextAlign.center, style: Helper.fitChineseFont(context, const TextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.w700)))), const SizedBox(width: 10), rightButton, ], diff --git a/lib/widget/wallet_header.dart b/lib/widget/wallet_header.dart index dc92c70..eb29788 100644 --- a/lib/widget/wallet_header.dart +++ b/lib/widget/wallet_header.dart @@ -71,25 +71,23 @@ class WalletHeader extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - if (config.walletConfig.network == 1) - Column( - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 3, 10, 3), - decoration: BoxDecoration( - color: DarkColors.redColorMask, - borderRadius: BorderRadius.circular(5), - ), - child: Text( - "TEST", - style: Helper.fitChineseFont(context, const TextStyle(fontSize: 10, fontWeight: FontWeight.w400, color: Colors.white70)), - ), + // if (config.walletConfig.network == 1) + Column( + children: [ + Container( + padding: const EdgeInsets.fromLTRB(10, 3, 10, 3), + decoration: BoxDecoration( + color: config.walletConfig.network == 1 ? DarkColors.redColorMask2 : DarkColors.greenColorMask, + borderRadius: BorderRadius.circular(5), ), - const SizedBox(height: 8), - ], - ) - else - const SizedBox(), + child: Text( + config.walletConfig.network == 1 ? "TestNet" : "MainNet", + style: Helper.fitChineseFont(context, const TextStyle(fontSize: 10, fontWeight: FontWeight.w400, color: Colors.white70)), + ), + ), + const SizedBox(height: 8), + ], + ), Text( wallet.hideBalance == true ? "****" : "${wallet.amount} XDAG", style: Helper.fitChineseFont(context, const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.white)), @@ -156,8 +154,8 @@ class WalletHeader extends StatelessWidget { const SizedBox(width: 15), Expanded( child: HomeHeaderButton( - title: AppLocalizations.of(context).receive, - icon: 'images/receive.png', + title: AppLocalizations.of(context).qr_code, + icon: 'images/qr.png', onPressed: () async { Helper.changeAndroidStatusBar(true); await Helper.showBottomSheet(context, const ReceivePage()); diff --git a/pubspec.lock b/pubspec.lock index 3b58e20..28f7e7c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1096,10 +1096,10 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: "47663d51a9061451aa3880a214ee9a65dcbb933b77bc44388e194279ab3ccaf6" + sha256: "1a37bdbaaf5fbe09ad8579ab09ecfd473284ce482f900b5aea27cf834386a567" url: "https://pub.dev" source: hosted - version: "4.0.7" + version: "4.2.0" webview_flutter_android: dependency: transitive description: @@ -1112,10 +1112,10 @@ packages: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "1939c39e2150fb4d30fd3cc59a891a49fed9935db53007df633ed83581b6117b" + sha256: "78715dc442b7849dbde74e92bb67de1cecf5addf95531c5fb474e72f5fe9a507" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.0" webview_flutter_wkwebview: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 75b0a07..f017caf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.13+14 +version: 1.0.14+15 environment: sdk: '>=2.19.2 <3.0.0' @@ -51,7 +51,7 @@ dependencies: easy_refresh: ^3.3.1 bip39: ^1.0.6 bip32: ^2.0.0 - webview_flutter: ^4.0.7 + webview_flutter: ^4.2.0 crypto: ^3.0.2 fast_base58: ^0.2.1 secp256k1: ^0.3.0 @@ -218,6 +218,16 @@ flutter: - images/2.0x/contacts1.png - images/3.0x/contacts1.png + - images/logo_b_40.png + - images/2.0x/logo_b_40.png + - images/3.0x/logo_b_40.png + + - images/qr.png + - images/2.0x/qr.png + - images/3.0x/qr.png + + + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware