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
This commit is contained in:
Serhii 2022-09-02 16:10:54 +03:00 committed by GitHub
parent 04be884357
commit 0aee6e1b8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 296 additions and 31 deletions

View file

@ -574,7 +574,8 @@ Future setup(
(WalletType type, _) => PreSeedPage(type));
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource));
TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource,
settingsStore: getIt.get<SettingsStore>()));
getIt.registerFactory(() => BackupService(
getIt.get<FlutterSecureStorage>(),

View file

@ -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) {
return Container(
height: 4,
width: 4,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isSynced
Color indicatorColor;
if (boolMode) {
indicatorColor = isSynced
? PaletteDark.brightGreen
: Theme.of(context).textTheme.caption.color),
);
: 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: size,
width: size,
decoration:
BoxDecoration(shape: BoxShape.circle, color: indicatorColor));
}
}

View file

@ -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>(T value) => value?.toString() ?? '';
}

View file

@ -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<TradeDetailsPageBody> {
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<TradeDetailsPageBody> {
},
child: StandartListRow(
title: '${item.title}', value: '${item.value}'));
}
});
});
}

View file

@ -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);
}

View file

@ -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.

View file

@ -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)),
]),
),
),
),
);
}
}

View file

@ -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: <Widget>[
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: <Widget>[
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))
],
),
),
),
)
]),
),
);
}
}

View file

@ -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<SettingsStore>().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<SettingsStore>().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';
}

View file

@ -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<void> _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<void>(context, S.of(context).copied_to_clipboard);
},
));
if (trade.provider != null) {
items.add(StandartListItem(

View file

@ -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",

View file

@ -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",

View file

@ -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" : "पर बनाया गया",

View file

@ -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",

View file

@ -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",