CAKE-15 | created header row, transaction page, balance view model, formatted item list, wallet balance; applied new design to trade and transaction rows; applied transaction page to dashboard page; applied balance view model, trade store, trade filter store and transaction filter store to dashboard view model; changed trade list item and transaction list item

This commit is contained in:
Oleksandr Sobol
2020-07-23 15:20:52 +03:00
parent 25436d9b94
commit bdfe208d20
27 changed files with 938 additions and 1312 deletions
@@ -8,4 +8,5 @@ abstract class TransactionInfo extends Object {
int height;
String amountFormatted();
String fiatAmount();
void changeFiatAmount(String amount);
}
+9 -12
View File
@@ -2,13 +2,14 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/view_model/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
import 'package:cake_wallet/palette.dart';
import 'package:dots_indicator/dots_indicator.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/action_button.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
@@ -35,8 +36,11 @@ class DashboardPage extends BasePage {
return Container(
alignment: Alignment.centerRight,
width: 40,
child: InkWell(
onTap: () async {
child: FlatButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
padding: EdgeInsets.all(0),
onPressed: () async {
await showDialog<void>(
builder: (_) => MenuWidget(
name: walletViewModel.name,
@@ -45,7 +49,7 @@ class DashboardPage extends BasePage {
context: context);
},
child: menuButton
),
)
);
}
@@ -141,14 +145,7 @@ class DashboardPage extends BasePage {
}
pages.add(BalancePage(dashboardViewModel: walletViewModel));
pages.add(Center(
child: Text(
'SECOND PAGE',
style: TextStyle(
color: Colors.white
),
),
));
pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
controller.addListener(() {
walletViewModel.currentPage = controller.page;
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/palette.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -35,7 +35,7 @@ class BalancePage extends StatelessWidget {
Observer(
builder: (_) {
return Text(
dashboardViewModel.balance.totalBalance,
dashboardViewModel.balanceViewModel.cryptoBalance,
style: TextStyle(
fontSize: 54,
fontWeight: FontWeight.bold,
@@ -48,7 +48,7 @@ class BalancePage extends StatelessWidget {
Observer(
builder: (_) {
return Text(
'\$ 0.00',
dashboardViewModel.balanceViewModel.fiatBalance,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
@@ -1,255 +0,0 @@
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/routes.dart';
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
import 'package:cake_wallet/themes.dart';
import 'package:cake_wallet/theme_changer.dart';
class ButtonHeader extends SliverPersistentHeaderDelegate {
final sendImage = Image.asset('assets/images/send.png');
final exchangeImage = Image.asset('assets/images/exchange.png');
final buyImage = Image.asset('assets/images/coins.png');
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
final _themeChanger = Provider.of<ThemeChanger>(context);
Image filterButton;
if (_themeChanger.getTheme() == Themes.darkTheme) {
filterButton = Image.asset('assets/images/filter_button.png');
} else {
filterButton = Image.asset('assets/images/filter_light_button.png');
}
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24), topRight: Radius.circular(24)),
child: Container(
color: Colors.red,
// height: 75,
padding: EdgeInsets.only(top: 26, left: 20, right: 20, bottom: 10),
// color: Theme.of(context).backgroundColor,
child: Stack(
children: <Widget>[
Center(
child: Text(
S.of(context).transactions,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color),
)),
Positioned(
right: 0,
height: 36,
child: PopupMenuButton<int>(
itemBuilder: (context) => [
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).transactions,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
// PopupMenuItem(
// value: 0,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).incoming),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayIncoming,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleIncoming(),
// )
// ]))),
// PopupMenuItem(
// value: 1,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).outgoing),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayOutgoing,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleOutgoing(),
// )
// ]))),
PopupMenuItem(
value: 2,
child: Text(S.of(context).transactions_by_date)),
PopupMenuDivider(),
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).trades,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
PopupMenuItem(
value: 3,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('XMR.TO'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayXMRTO,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .xmrto),
// )
]))),
PopupMenuItem(
value: 4,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('Change.NOW'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayChangeNow,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .changeNow),
// )
]))),
PopupMenuItem(
value: 5,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('MorphToken'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayMorphToken,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .morphToken),
// )
])))
],
child: filterButton,
onSelected: (item) async {
if (item == 2) {
final List<DateTime> picked =
await date_rage_picker.showDatePicker(
context: context,
initialFirstDate:
DateTime.now().subtract(Duration(days: 1)),
initialLastDate: (DateTime.now()),
firstDate: DateTime(2015),
lastDate: DateTime.now().add(Duration(days: 1)));
if (picked != null && picked.length == 2) {
// actionListStore.transactionFilterStore
// .changeStartDate(picked.first);
// actionListStore.transactionFilterStore
// .changeEndDate(picked.last);
}
}
},
)),
],
),
),
);
}
@override
double get maxExtent => 164;
@override
double get minExtent => 66;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
Widget actionButton(
{BuildContext context,
@required Image image,
@required String title,
@required String route}) {
return Container(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
if (route.isNotEmpty) {
Navigator.of(context, rootNavigator: true).pushNamed(route);
}
},
child: Container(
height: 48,
width: 48,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).primaryTextTheme.subhead.color,
shape: BoxShape.circle),
child: image,
),
),
Padding(
padding: EdgeInsets.only(top: 12),
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color.fromRGBO(140, 153, 201,
0.8) // Theme.of(context).primaryTextTheme.caption.color
),
),
)
],
),
);
}
}
@@ -0,0 +1,187 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
import 'package:flutter_mobx/flutter_mobx.dart';
class HeaderRow extends StatelessWidget {
HeaderRow({this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
final filterIcon = Image.asset('assets/images/filter_icon.png',
color: PaletteDark.wildBlue);
@override
Widget build(BuildContext context) {
return Container(
height: 52,
color: Colors.transparent,
padding: EdgeInsets.only(left: 24, right: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
S.of(context).transactions,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Colors.white
),
),
PopupMenuButton<int>(
itemBuilder: (context) => [
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).transactions,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryTextTheme.caption.color))),
PopupMenuItem(
value: 0,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(S.of(context).incoming),
Checkbox(
value: dashboardViewModel
.transactionFilterStore
.displayIncoming,
onChanged: (value) => dashboardViewModel
.transactionFilterStore
.toggleIncoming()
)
]))),
PopupMenuItem(
value: 1,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(S.of(context).outgoing),
Checkbox(
value: dashboardViewModel
.transactionFilterStore
.displayOutgoing,
onChanged: (value) => dashboardViewModel
.transactionFilterStore
.toggleOutgoing(),
)
]))),
PopupMenuItem(
value: 2,
child:
Text(S.of(context).transactions_by_date)),
PopupMenuDivider(),
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).trades,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryTextTheme.caption.color))),
PopupMenuItem(
value: 3,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text('XMR.TO'),
Checkbox(
value: dashboardViewModel
.tradeFilterStore
.displayXMRTO,
onChanged: (value) => dashboardViewModel
.tradeFilterStore
.toggleDisplayExchange(
ExchangeProviderDescription
.xmrto),
)
]))),
PopupMenuItem(
value: 4,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text('Change.NOW'),
Checkbox(
value: dashboardViewModel
.tradeFilterStore
.displayChangeNow,
onChanged: (value) => dashboardViewModel
.tradeFilterStore
.toggleDisplayExchange(
ExchangeProviderDescription
.changeNow),
)
]))),
PopupMenuItem(
value: 5,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text('MorphToken'),
Checkbox(
value: dashboardViewModel
.tradeFilterStore
.displayMorphToken,
onChanged: (value) => dashboardViewModel
.tradeFilterStore
.toggleDisplayExchange(
ExchangeProviderDescription
.morphToken),
)
])))
],
child: Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: PaletteDark.oceanBlue
),
child: filterIcon,
),
onSelected: (item) async {
if (item == 2) {
final picked =
await date_rage_picker.showDatePicker(
context: context,
initialFirstDate: DateTime.now()
.subtract(Duration(days: 1)),
initialLastDate: (DateTime.now()),
firstDate: DateTime(2015),
lastDate: DateTime.now()
.add(Duration(days: 1)));
if (picked != null && picked.length == 2) {
dashboardViewModel.transactionFilterStore
.changeStartDate(picked.first);
dashboardViewModel.transactionFilterStore
.changeEndDate(picked.last);
}
}
},
),
],
),
);
}
}
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/palette.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
@@ -1,322 +0,0 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/theme_changer.dart';
import 'package:cake_wallet/themes.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/view_model/dashboard_view_model.dart';
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
import 'package:cake_wallet/src/stores/action_list/date_section_item.dart';
import 'package:cake_wallet/src/stores/action_list/trade_list_item.dart';
import 'package:cake_wallet/src/stores/action_list/transaction_list_item.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'date_section_raw.dart';
import 'trade_row.dart';
import 'transaction_raw.dart';
import 'button_header.dart';
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
class TradeHistoryPanel extends StatefulWidget {
TradeHistoryPanel({this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
@override
TradeHistoryPanelState createState() => TradeHistoryPanelState();
}
class TradeHistoryPanelState extends State<TradeHistoryPanel> {
final _listObserverKey = GlobalKey();
final _listKey = GlobalKey();
double panelHeight;
double screenHeight;
@override
void initState() {
panelHeight = 0;
screenHeight = 0;
super.initState();
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
}
void afterLayout(dynamic _) {
screenHeight = MediaQuery.of(context).size.height;
setState(() {
panelHeight = screenHeight;
});
}
@override
Widget build(BuildContext context) {
// AnimatedContainer(
// width: MediaQuery.of(context).size.width,
// height: panelHeight,
// duration: Duration(milliseconds: 1000),
// curve: Curves.fastOutSlowIn,
// child: )
final transactionDateFormat = DateFormat('HH:mm');
final _themeChanger = Provider.of<ThemeChanger>(context);
final filterButton = Image.asset(
_themeChanger.getTheme() == Themes.darkTheme
? 'assets/images/filter_button.png'
: 'assets/images/filter_light_button.png',
height: 36);
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
child: Container(
color: Colors.white,
child: Column(children: [
Container(
padding:
EdgeInsets.only(top: 32, left: 20, right: 20, bottom: 20),
color: Theme.of(context).backgroundColor,
child: Stack(
children: <Widget>[
SizedBox(height: 37), // Force stack height
Center(
child: Text(S.of(context).transactions,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color))),
Positioned(
right: 0,
child: PopupMenuButton<int>(
itemBuilder: (context) => [
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).transactions,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
// PopupMenuItem(
// value: 0,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).incoming),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayIncoming,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleIncoming(),
// )
// ]))),
// PopupMenuItem(
// value: 1,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).outgoing),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayOutgoing,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleOutgoing(),
// )
// ]))),
PopupMenuItem(
value: 2,
child:
Text(S.of(context).transactions_by_date)),
PopupMenuDivider(),
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).trades,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
PopupMenuItem(
value: 3,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('XMR.TO'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayXMRTO,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .xmrto),
// )
]))),
PopupMenuItem(
value: 4,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('Change.NOW'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayChangeNow,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .changeNow),
// )
]))),
PopupMenuItem(
value: 5,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('MorphToken'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayMorphToken,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .morphToken),
// )
])))
],
child: filterButton,
onSelected: (item) async {
if (item == 2) {
final picked =
await date_rage_picker.showDatePicker(
context: context,
initialFirstDate: DateTime.now()
.subtract(Duration(days: 1)),
initialLastDate: (DateTime.now()),
firstDate: DateTime(2015),
lastDate: DateTime.now()
.add(Duration(days: 1)));
if (picked != null && picked.length == 2) {
// actionListStore.transactionFilterStore
// .changeStartDate(picked.first);
// actionListStore.transactionFilterStore
// .changeEndDate(picked.last);
}
}
},
)),
],
),
),
widget.dashboardViewModel.transactions?.isNotEmpty ?? false
? ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.dashboardViewModel.transactions.length,
itemBuilder: (_, index) {
final item =
widget.dashboardViewModel.transactions[index];
if (item is DateSectionItem) {
return DateSectionRaw(date: item.date);
}
if (item is TransactionListItem) {
final transaction = item.transaction;
final savedDisplayMode = BalanceDisplayMode.all;
//settingsStore
// .balanceDisplayMode;
final formattedAmount = savedDisplayMode ==
BalanceDisplayMode.hiddenBalance
? '---'
: transaction.amountFormatted();
final formattedFiatAmount = savedDisplayMode ==
BalanceDisplayMode.hiddenBalance
? '---'
: transaction.fiatAmount(); // symbol ???
return TransactionRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.transactionDetails,
arguments: transaction),
direction: transaction.direction,
formattedDate: transactionDateFormat
.format(transaction.date),
formattedAmount: formattedAmount,
formattedFiatAmount: formattedFiatAmount,
isPending: transaction.isPending);
}
if (item is TradeListItem) {
final trade = item.trade;
final savedDisplayMode = BalanceDisplayMode.all;
//settingsStore
// .balanceDisplayMode;
final formattedAmount = trade.amount != null
? savedDisplayMode ==
BalanceDisplayMode.hiddenBalance
? '---'
: trade.amountFormatted()
: trade.amount;
return TradeRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.tradeDetails,
arguments: trade),
provider: trade.provider,
from: trade.from,
to: trade.to,
createdAtFormattedDate:
transactionDateFormat.format(trade.createdAt),
formattedAmount: formattedAmount);
}
return Container(
color: Theme.of(context).backgroundColor,
height: 1);
},
separatorBuilder: (_, __) =>
Container(height: 14, color: Colors.white),
)
: Padding(
padding: EdgeInsets.all(20),
child: Text('Your transactions will be displayed here!',
style: TextStyle(color: Colors.grey)))
]))); //,
}
}
@@ -37,7 +37,7 @@ class TradeRow extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(left: 12),
child: Container(
height: 42,
height: 46,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
@@ -46,7 +46,7 @@ class TransactionRow extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(left: 12),
child: Container(
height: 42,
height: 46,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
@@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/header_row.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/date_section_raw.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/trade_row.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/transaction_raw.dart';
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/date_section_item.dart';
import 'package:intl/intl.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
class TransactionsPage extends StatelessWidget {
TransactionsPage({@required this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: 24,
bottom: 24
),
child: Column(
children: <Widget>[
HeaderRow(dashboardViewModel: dashboardViewModel),
Expanded(
child: Observer(
builder: (_) {
final items = dashboardViewModel.items;
return items?.isNotEmpty ?? false
? ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
if (item is DateSectionItem) {
return DateSectionRaw(date: item.date);
}
if (item is TransactionListItem) {
final transaction = item.transaction;
return TransactionRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.transactionDetails,
arguments: transaction),
direction: transaction.direction,
formattedDate: DateFormat('HH:mm')
.format(transaction.date),
formattedAmount: item.formattedCryptoAmount,
formattedFiatAmount: item.formattedFiatAmount,
isPending: transaction.isPending);
}
if (item is TradeListItem) {
final trade = item.trade;
return TradeRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.tradeDetails,
arguments: trade),
provider: trade.provider,
from: trade.from,
to: trade.to,
createdAtFormattedDate:
DateFormat('HH:mm').format(trade.createdAt),
formattedAmount: item.tradeFormattedAmount
);
}
return Container(
color: Theme.of(context).backgroundColor,
height: 1);
}
)
: Center(
child: Text(
S.of(context).placeholder_transactions,
style: TextStyle(
fontSize: 14,
color: Colors.grey
),
),
);
}
)
)
],
),
);
}
}
@@ -1,508 +0,0 @@
import 'dart:async';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/view_model/dashboard_view_model.dart';
class WalletCard extends StatefulWidget {
WalletCard({this.walletVM});
final DashboardViewModel walletVM;
@override
WalletCardState createState() => WalletCardState();
}
class WalletCardState extends State<WalletCard> {
final _syncingObserverKey = GlobalKey();
final _balanceObserverKey = GlobalKey();
final _addressObserverKey = GlobalKey();
double cardWidth;
double cardHeight;
double screenWidth;
double opacity;
bool isDraw;
bool isFrontSide;
@override
void initState() {
cardWidth = 0;
cardHeight = 220;
screenWidth = 0;
opacity = 0;
isDraw = false;
isFrontSide = true;
super.initState();
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
}
void afterLayout(dynamic _) {
screenWidth = MediaQuery.of(context).size.width - 20;
setState(() {
cardWidth = screenWidth;
opacity = 1;
});
Timer(Duration(milliseconds: 500), () => setState(() => isDraw = true));
}
@override
Widget build(BuildContext context) {
final colorsSync = [
Theme.of(context).cardTheme.color,
Theme.of(context).hoverColor
];
return Container(
width: double.infinity,
height: cardHeight,
alignment: Alignment.centerRight,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(14), bottomLeft: Radius.circular(14))),
child: AnimatedContainer(
alignment: Alignment.centerLeft,
width: cardWidth,
height: cardHeight,
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(14),
bottomLeft: Radius.circular(14)),
color: Theme.of(context).focusColor),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
child: Container(
width: cardWidth,
height: cardHeight,
color: Theme.of(context).cardColor,
child: isFrontSide
? frontSide(colorsSync)
: InkWell(
onTap: () => setState(() => isFrontSide = true),
child: backSide(colorsSync)),
),
)),
);
}
Widget frontSide(List<Color> colorsSync) {
final settingsStore = Provider.of<SettingsStore>(context);
final triangleButton = Image.asset(
'assets/images/triangle.png',
color: Theme.of(context).primaryTextTheme.title.color,
);
return Observer(
key: _syncingObserverKey,
builder: (_) {
final status = widget.walletVM.status;
final statusText = status.title();
final progress = status.progress();
final indicatorOffset = progress * cardWidth;
final indicatorWidth =
progress <= 1 ? cardWidth - indicatorOffset : 0.0;
var descriptionText = '';
if (status is SyncingSyncStatus) {
descriptionText = S.of(context).Blocks_remaining(status.toString());
}
if (status is FailedSyncStatus) {
descriptionText = S.of(context).please_try_to_connect_to_another_node;
}
return Container(
width: cardWidth,
height: cardHeight,
color: Colors.white,
child: Stack(
children: <Widget>[
progress <= 1
? Positioned(
left: indicatorOffset,
top: 0,
bottom: 0,
child: Container(
width: indicatorWidth,
height: cardHeight,
color: Color.fromRGBO(227, 238, 249, 1),
))
: Offstage(),
isDraw
? Positioned(
left: 24,
right: 24,
top: 32,
bottom: 24,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
onTap: () => Navigator.of(context)
.pushNamed(Routes.walletList),
child: Row(
children: <Widget>[
Text(
widget.walletVM.name,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
SizedBox(width: 10),
triangleButton
],
),
),
SizedBox(height: 5),
if (widget.walletVM.subname?.isNotEmpty ??
false)
Text(
widget.walletVM.subname,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
)
],
),
InkWell(
onTap: () =>
setState(() => isFrontSide = false),
child: Container(
width: 98,
height: 32,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context)
.accentTextTheme
.subtitle
.backgroundColor,
border: Border.all(
color: Color.fromRGBO(
219, 231, 237, 1)),
// FIXME
borderRadius: BorderRadius.all(
Radius.circular(16))),
child: Text(
'Receive',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
)),
)
],
),
status is SyncedSyncStatus
? Observer(
key: _balanceObserverKey,
builder: (_) {
final balanceDisplayMode =
BalanceDisplayMode.availableBalance;
// settingsStore.balanceDisplayMode;
final symbol =
settingsStore.fiatCurrency.toString();
var balance = '---';
var fiatBalance = '---';
if (balanceDisplayMode ==
BalanceDisplayMode.availableBalance) {
balance = widget.walletVM.balance
.unlockedBalance ??
'0.0';
fiatBalance = '\$ 0.00';
// '$symbol ${balanceStore.fiatUnlockedBalance}';
}
if (balanceDisplayMode ==
BalanceDisplayMode.fullBalance) {
balance = widget.walletVM.balance
.totalBalance ??
'0.0';
fiatBalance = '\$ 0.00';
// '$symbol ${balanceStore.fiatFullBalance}';
}
return Row(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
balanceDisplayMode.toString(),
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
),
SizedBox(height: 5),
Container(
height: 36,
child: Text(
balance,
style: TextStyle(
fontSize: 32,
color: Theme.of(context)
.primaryTextTheme
.title
.color,
fontWeight:
FontWeight.bold),
))
],
),
Text(
fiatBalance,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
// FIXME
// color: Theme.of(context)
// .primaryTextTheme
// .title
// .color,
color: Color.fromRGBO(
72, 89, 109, 1)),
)
],
);
})
: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
statusText,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
),
SizedBox(height: 5),
Text(
descriptionText,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
)
],
)
],
)
],
),
))
: Offstage()
],
),
);
},
);
}
Widget backSide(List<Color> colorsSync) {
final rightArrow = Image.asset('assets/images/right_arrow.png',
color: Theme.of(context).primaryTextTheme.title.color);
var messageBoxHeight = 0.0;
var messageBoxWidth = cardWidth - 10;
return Observer(
key: _addressObserverKey,
builder: (_) {
return Container(
width: cardWidth,
height: cardHeight,
alignment: Alignment.topCenter,
child: Stack(
alignment: Alignment.topRight,
children: <Widget>[
Container(
width: cardWidth,
height: cardHeight,
padding:
EdgeInsets.only(left: 24, right: 24, top: 32, bottom: 32),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10)),
gradient: LinearGradient(
colors: colorsSync,
begin: Alignment.topCenter,
end: Alignment.bottomCenter)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
S.current.card_address,
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
),
SizedBox(height: 10),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: widget.walletVM.address));
_addressObserverKey.currentState
.setState(() {
messageBoxHeight = 20;
messageBoxWidth = cardWidth;
});
Timer(Duration(milliseconds: 1000), () {
try {
_addressObserverKey.currentState
.setState(() {
messageBoxHeight = 0;
messageBoxWidth = cardWidth - 10;
});
} catch (e) {
print('${e.toString()}');
}
});
},
child: Text(
widget.walletVM.address,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
)
],
),
)),
SizedBox(width: 10),
Container(
width: 90,
height: 90,
child: QrImage(
data: widget.walletVM.address,
backgroundColor: Colors.transparent,
foregroundColor: Theme.of(context)
.primaryTextTheme
.caption
.color),
)
],
),
Container(
height: 44,
padding: EdgeInsets.only(left: 20, right: 20),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(22)),
color: Theme.of(context)
.primaryTextTheme
.overline
.color),
child: InkWell(
onTap: () =>
Navigator.of(context, rootNavigator: true)
.pushNamed(Routes.receive),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
S.of(context).addresses,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
rightArrow
],
),
),
)
],
),
),
AnimatedContainer(
width: messageBoxWidth,
height: messageBoxHeight,
alignment: Alignment.center,
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(topLeft: Radius.circular(10)),
color: Colors.green),
child: Text(
S.of(context).copied_to_clipboard,
style: TextStyle(fontSize: 10, color: Colors.white),
),
)
],
),
);
});
}
}