From 0aee6e1b8dcf9926a1b455bf5eebb6256900e277 Mon Sep 17 00:00:00 2001 From: Serhii Date: Fri, 2 Sep 2022 16:10:54 +0300 Subject: [PATCH] rework trade details screen (#449) * create standart list card item * create standart list status item * update localization * fix date format * fix theme gradient * PR comments * fix issues from code review --- lib/di.dart | 3 +- .../widgets/sync_indicator_icon.dart | 54 ++++++++++--- .../trade_details_list_card.dart | 35 +++++++++ .../trade_details/trade_details_page.dart | 23 +++++- .../trade_details_status_item.dart | 7 ++ lib/src/widgets/standard_list.dart | 6 ++ lib/src/widgets/standart_list_card.dart | 77 +++++++++++++++++++ lib/src/widgets/standart_list_status_row.dart | 66 ++++++++++++++++ lib/utils/date_formatter.dart | 16 ++-- lib/view_model/trade_details_view_model.dart | 30 ++++++-- res/values/strings_en.arb | 2 +- res/values/strings_fr.arb | 2 +- res/values/strings_hi.arb | 2 +- res/values/strings_hr.arb | 2 +- res/values/strings_nl.arb | 2 +- 15 files changed, 296 insertions(+), 31 deletions(-) create mode 100644 lib/src/screens/trade_details/trade_details_list_card.dart create mode 100644 lib/src/screens/trade_details/trade_details_status_item.dart create mode 100644 lib/src/widgets/standart_list_card.dart create mode 100644 lib/src/widgets/standart_list_status_row.dart diff --git a/lib/di.dart b/lib/di.dart index 94045e913..b43e8a86a 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -574,7 +574,8 @@ Future setup( (WalletType type, _) => PreSeedPage(type)); getIt.registerFactoryParam((trade, _) => - TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource)); + TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource, + settingsStore: getIt.get())); getIt.registerFactory(() => BackupService( getIt.get(), diff --git a/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart b/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart index a9baed3c6..c11920bb7 100644 --- a/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart +++ b/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart @@ -2,20 +2,56 @@ import 'package:flutter/material.dart'; import 'package:cake_wallet/palette.dart'; class SyncIndicatorIcon extends StatelessWidget { - SyncIndicatorIcon({this.isSynced}); + SyncIndicatorIcon( + {this.boolMode = true, + this.isSynced = false, + this.value = waiting, + this.size = 4.0}); + final bool boolMode; final bool isSynced; + final String value; + final double size; + + static const String waiting = 'waiting'; + static const String actionRequired = 'action required'; + static const String created = 'created'; + static const String fetching = 'fetching'; + static const String finished = 'finished'; @override Widget build(BuildContext context) { + Color indicatorColor; + + if (boolMode) { + indicatorColor = isSynced + ? PaletteDark.brightGreen + : Theme.of(context).textTheme.caption.color; + } else { + switch (value.toLowerCase()) { + case waiting: + indicatorColor = Colors.red; + break; + case actionRequired: + indicatorColor = Theme.of(context).textTheme.display3.decorationColor; + break; + case created: + indicatorColor = PaletteDark.brightGreen; + break; + case fetching: + indicatorColor = Colors.red; + break; + case finished: + indicatorColor = PaletteDark.brightGreen; + break; + default: + indicatorColor = Colors.red; + } + } return Container( - height: 4, - width: 4, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: isSynced - ? PaletteDark.brightGreen - : Theme.of(context).textTheme.caption.color), - ); + height: size, + width: size, + decoration: + BoxDecoration(shape: BoxShape.circle, color: indicatorColor)); } } diff --git a/lib/src/screens/trade_details/trade_details_list_card.dart b/lib/src/screens/trade_details/trade_details_list_card.dart new file mode 100644 index 000000000..9df8f1011 --- /dev/null +++ b/lib/src/screens/trade_details/trade_details_list_card.dart @@ -0,0 +1,35 @@ +import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; +import 'package:cw_core/crypto_currency.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +class TradeDetailsListCardItem extends StandartListItem { + TradeDetailsListCardItem( + {String title, + String value, + this.id, + this.createdAt, + this.pair, + this.onTap}) + : super(title: title, value: value); + + factory TradeDetailsListCardItem.tradeDetails( + {@required String id, + @required String createdAt, + @required CryptoCurrency from, + @required CryptoCurrency to, + @required Function onTap}) { + return TradeDetailsListCardItem( + id: '${S.current.trade_details_id} ${formatAsText(id)}', + createdAt: formatAsText(createdAt), + pair: '${formatAsText(from)} → ${formatAsText(to)}', + onTap: onTap); + } + + final String id; + final String createdAt; + final String pair; + final Function onTap; + + static String formatAsText(T value) => value?.toString() ?? ''; +} diff --git a/lib/src/screens/trade_details/trade_details_page.dart b/lib/src/screens/trade_details/trade_details_page.dart index abf8e2873..b46db87fa 100644 --- a/lib/src/screens/trade_details/trade_details_page.dart +++ b/lib/src/screens/trade_details/trade_details_page.dart @@ -1,4 +1,6 @@ import 'package:cake_wallet/src/widgets/standard_list.dart'; +import 'package:cake_wallet/src/widgets/standart_list_card.dart'; +import 'package:cake_wallet/src/widgets/standart_list_status_row.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/view_model/trade_details_view_model.dart'; import 'package:flutter/material.dart'; @@ -9,6 +11,8 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/standart_list_row.dart'; import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart'; +import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart'; +import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart'; class TradeDetailsPage extends BasePage { TradeDetailsPage(this.tradeDetailsViewModel); @@ -58,7 +62,23 @@ class TradeDetailsPageBodyState extends State { onTap: item.onTap, child: StandartListRow( title: '${item.title}', value: '${item.value}')); - } else { + } + + if (item is DetailsListStatusItem) { + return StandartListStatusRow( + title: item.title, + value: item.value); + } + + if (item is TradeDetailsListCardItem) { + return TradeDatailsStandartListCard( + id: item.id, + create: item.createdAt, + pair: item.pair, + currentTheme: tradeDetailsViewModel.settingsStore.currentTheme.type, + onTap: item.onTap,); + } + return GestureDetector( onTap: () { Clipboard.setData(ClipboardData(text: '${item.value}')); @@ -66,7 +86,6 @@ class TradeDetailsPageBodyState extends State { }, child: StandartListRow( title: '${item.title}', value: '${item.value}')); - } }); }); } diff --git a/lib/src/screens/trade_details/trade_details_status_item.dart b/lib/src/screens/trade_details/trade_details_status_item.dart new file mode 100644 index 000000000..eea7ccdf4 --- /dev/null +++ b/lib/src/screens/trade_details/trade_details_status_item.dart @@ -0,0 +1,7 @@ +import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; + +class DetailsListStatusItem extends StandartListItem { + DetailsListStatusItem( + {String title, String value}) + : super(title: title, value: value); +} diff --git a/lib/src/widgets/standard_list.dart b/lib/src/widgets/standard_list.dart index 572f03791..26bee8ada 100644 --- a/lib/src/widgets/standard_list.dart +++ b/lib/src/widgets/standard_list.dart @@ -1,4 +1,6 @@ import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/src/widgets/standart_list_card.dart'; +import 'package:cake_wallet/src/widgets/standart_list_status_row.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -212,6 +214,10 @@ class SectionStandardList extends StatelessWidget { return Container(); } + if (row is StandartListStatusRow || row is TradeDatailsStandartListCard) { + return Container(); + } + final nextRow = totalRows[index + 1]; // If current row is pre last and last row is separator. diff --git a/lib/src/widgets/standart_list_card.dart b/lib/src/widgets/standart_list_card.dart new file mode 100644 index 000000000..f3bc89b99 --- /dev/null +++ b/lib/src/widgets/standart_list_card.dart @@ -0,0 +1,77 @@ +import 'package:cake_wallet/palette.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/themes/theme_base.dart'; + +class TradeDatailsStandartListCard extends StatelessWidget { + TradeDatailsStandartListCard( + {this.id, this.create, this.pair, this.onTap, this.currentTheme}); + + final String id; + final String create; + final String pair; + final ThemeType currentTheme; + final Function onTap; + + @override + Widget build(BuildContext context) { + final darkTheme = currentTheme == ThemeType.dark; + + final baseGradient = LinearGradient(colors: [ + Theme.of(context).primaryTextTheme.subtitle.color, + Theme.of(context).primaryTextTheme.subtitle.decorationColor, + ], begin: Alignment.centerLeft, end: Alignment.centerRight); + + final gradient = LinearGradient(colors: [ + PaletteDark.wildNightBlue, + PaletteDark.oceanBlue, + ], begin: Alignment.bottomCenter, end: Alignment.topCenter); + + final textColor = Colors.white; + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0), + child: GestureDetector( + onTap: () => onTap(context), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15.0), + gradient: darkTheme ? gradient : baseGradient), + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20.0, vertical: 16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(id, + style: TextStyle( + fontSize: 16, + fontFamily: 'Lato', + fontWeight: FontWeight.w400, + color: textColor)), + SizedBox( + height: 8, + ), + Text(create, + style: TextStyle( + fontSize: 12, + fontFamily: 'Lato', + fontWeight: FontWeight.w400, + color: textColor)), + SizedBox( + height: 35, + ), + Text(pair, + style: TextStyle( + fontSize: 24, + fontFamily: 'Lato', + fontWeight: FontWeight.bold, + color: textColor)), + ]), + ), + ), + ), + ); + } +} diff --git a/lib/src/widgets/standart_list_status_row.dart b/lib/src/widgets/standart_list_status_row.dart new file mode 100644 index 000000000..a096dcc8d --- /dev/null +++ b/lib/src/widgets/standart_list_status_row.dart @@ -0,0 +1,66 @@ +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class StandartListStatusRow extends StatelessWidget { + StandartListStatusRow({this.title, this.value}); + + final String title; + final String value; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + color: Theme.of(context).backgroundColor, + child: Padding( + padding: + const EdgeInsets.only(left: 24, top: 16, bottom: 16, right: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Theme.of(context).primaryTextTheme.overline.color), + textAlign: TextAlign.left), + Padding( + padding: const EdgeInsets.only(top: 12), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).accentTextTheme.display2.color, + borderRadius: BorderRadius.circular(30.0), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SyncIndicatorIcon( + boolMode: false, + value: value, + size: 6, + ), + SizedBox( + width: 5, + ), + Text(value, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context) + .primaryTextTheme + .title + .color)) + ], + ), + ), + ), + ) + ]), + ), + ); + } +} diff --git a/lib/utils/date_formatter.dart b/lib/utils/date_formatter.dart index f75c4d729..9cff68614 100644 --- a/lib/utils/date_formatter.dart +++ b/lib/utils/date_formatter.dart @@ -3,21 +3,21 @@ import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/store/settings_store.dart'; class DateFormatter { - static String currentLocalFormat({bool hasTime = true}) { + static String currentLocalFormat({bool hasTime = true, bool reverse = false}) { final isUSA = getIt.get().languageCode.toLowerCase() == 'en'; final format = - isUSA ? usaStyleFormat(hasTime) : regularStyleFormat(hasTime); + isUSA ? usaStyleFormat(hasTime, reverse) : regularStyleFormat(hasTime, reverse); return format; } - static DateFormat withCurrentLocal({bool hasTime = true}) => DateFormat( - currentLocalFormat(hasTime: hasTime), + static DateFormat withCurrentLocal({bool hasTime = true, bool reverse = false}) => DateFormat( + currentLocalFormat(hasTime: hasTime, reverse: reverse), getIt.get().languageCode); - static String usaStyleFormat(bool hasTime) => - hasTime ? 'yyyy.MM.dd, HH:mm' : 'yyyy.MM.dd'; + static String usaStyleFormat(bool hasTime, bool reverse) => + hasTime ? (reverse ? 'HH:mm yyyy.MM.dd' : 'yyyy.MM.dd, HH:mm') : 'yyyy.MM.dd'; - static String regularStyleFormat(bool hasTime) => - hasTime ? 'dd.MM.yyyy, HH:mm' : 'dd.MM.yyyy'; + static String regularStyleFormat(bool hasTime, bool reverse) => + hasTime ? (reverse ? 'HH:mm dd.MM.yyyy' : 'dd.MM.yyyy, HH:mm') : 'dd.MM.yyyy'; } diff --git a/lib/view_model/trade_details_view_model.dart b/lib/view_model/trade_details_view_model.dart index 00aabdebd..59b52463b 100644 --- a/lib/view_model/trade_details_view_model.dart +++ b/lib/view_model/trade_details_view_model.dart @@ -7,12 +7,18 @@ import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart' import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart'; +import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; +import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart'; +import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart'; +import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart'; import 'package:url_launcher/url_launcher.dart'; part 'trade_details_view_model.g.dart'; @@ -20,7 +26,7 @@ class TradeDetailsViewModel = TradeDetailsViewModelBase with _$TradeDetailsViewModel; abstract class TradeDetailsViewModelBase with Store { - TradeDetailsViewModelBase({Trade tradeForDetails, this.trades}) { + TradeDetailsViewModelBase({Trade tradeForDetails, this.trades, this.settingsStore}) { trade = tradeForDetails; switch (trade.provider) { @@ -62,6 +68,8 @@ abstract class TradeDetailsViewModelBase with Store { Timer timer; + final SettingsStore settingsStore; + @action Future _updateTrade() async { try { @@ -80,18 +88,28 @@ abstract class TradeDetailsViewModelBase with Store { } void _updateItems() { - final dateFormat = DateFormatter.withCurrentLocal(); + final dateFormat = DateFormatter.withCurrentLocal(reverse: true); items?.clear(); - items.addAll([ - StandartListItem(title: S.current.trade_details_id, value: trade.id), - StandartListItem( + items.add( + DetailsListStatusItem( title: S.current.trade_details_state, value: trade.state != null ? trade.state.toString() : S.current.trade_details_fetching) - ]); + ); + + items.add(TradeDetailsListCardItem.tradeDetails( + id: trade.id, + createdAt: dateFormat.format(trade.createdAt), + from: trade.from, + to: trade.to, + onTap: (BuildContext context) { + Clipboard.setData(ClipboardData(text: '${trade.id}')); + showBar(context, S.of(context).copied_to_clipboard); + }, + )); if (trade.provider != null) { items.add(StandartListItem( diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 958e777f5..f66eee460 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -276,7 +276,7 @@ "trade_details_title" : "Trade Details", "trade_details_id" : "ID", - "trade_details_state" : "State", + "trade_details_state" : "Status", "trade_details_fetching" : "Fetching", "trade_details_provider" : "Provider", "trade_details_created_at" : "Created at", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index ec6782cac..4737d6a0f 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -274,7 +274,7 @@ "trade_details_title" : "Détails de l'échange", "trade_details_id" : "ID", - "trade_details_state" : "État", + "trade_details_state" : "Statut", "trade_details_fetching" : "Récupération", "trade_details_provider" : "Fournisseur", "trade_details_created_at" : "Créé le", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 50fd5a2d2..0e5bd72bc 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -276,7 +276,7 @@ "trade_details_title" : "व्यापार विवरण", "trade_details_id" : "आईडी", - "trade_details_state" : "राज्य", + "trade_details_state" : "दर्जा", "trade_details_fetching" : "ला रहा है", "trade_details_provider" : "प्रदाता", "trade_details_created_at" : "पर बनाया गया", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 3dbbc03be..6ddd2ef51 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -276,7 +276,7 @@ "trade_details_title" : "Detalji razmjene", "trade_details_id" : "ID", - "trade_details_state" : "Stanje", + "trade_details_state" : "Status", "trade_details_fetching" : "Dohvaćanje", "trade_details_provider" : "Pružatelj", "trade_details_created_at" : "Stvoreno u", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 72b69dfab..416479bab 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -276,7 +276,7 @@ "trade_details_title" : "Handelsgegevens", "trade_details_id" : "ID", - "trade_details_state" : "Staat", + "trade_details_state" : "Toestand", "trade_details_fetching" : "Ophalen", "trade_details_provider" : "Leverancier", "trade_details_created_at" : "Gemaakt bij",