diff --git a/lib/bitcoin/bitcoin_transaction_info.dart b/lib/bitcoin/bitcoin_transaction_info.dart index 5850f19d2..583d1615c 100644 --- a/lib/bitcoin/bitcoin_transaction_info.dart +++ b/lib/bitcoin/bitcoin_transaction_info.dart @@ -4,6 +4,7 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData; import 'package:cake_wallet/src/domain/common/transaction_direction.dart'; import 'package:cake_wallet/src/domain/common/transaction_info.dart'; +import 'package:cake_wallet/src/domain/common/format_amount.dart'; class BitcoinTransactionInfo extends TransactionInfo { BitcoinTransactionInfo( @@ -62,11 +63,16 @@ class BitcoinTransactionInfo extends TransactionInfo { final String id; - @override - String amountFormatted() => bitcoinAmountToString(amount: amount); + String _fiatAmount; @override - String fiatAmount() => '\$ 24.5'; + String amountFormatted() => '${formatAmount(bitcoinAmountToString(amount: amount))} BTC'; + + @override + String fiatAmount() => _fiatAmount ?? ''; + + @override + void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); Map toJson() { final m = Map(); diff --git a/lib/di.dart b/lib/di.dart index 19a8bc357..99188a2c8 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/core/contact_service.dart'; import 'package:cake_wallet/src/domain/common/contact.dart'; import 'package:cake_wallet/src/domain/common/node.dart'; +import 'package:cake_wallet/src/domain/exchange/trade.dart'; import 'package:cake_wallet/src/screens/contact/contact_list_page.dart'; import 'package:cake_wallet/src/screens/contact/contact_page.dart'; import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart'; @@ -11,7 +12,7 @@ import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart'; import 'package:cake_wallet/store/contact_list_store.dart'; import 'package:cake_wallet/store/node_list_store.dart'; import 'package:cake_wallet/store/settings_store.dart'; -import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/src/stores/price/price_store.dart'; import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/monero/monero_wallet.dart'; @@ -31,7 +32,8 @@ import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart'; import 'package:cake_wallet/view_model/auth_view_model.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/view_model/dashboard/balance_view_model.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart'; @@ -52,6 +54,9 @@ import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; import 'package:cake_wallet/view_model/wallet_new_vm.dart'; import 'package:cake_wallet/store/authentication_store.dart'; +import 'package:cake_wallet/store/dashboard/trades_store.dart'; +import 'package:cake_wallet/store/dashboard/trade_filter_store.dart'; +import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart'; final getIt = GetIt.instance; @@ -77,7 +82,9 @@ NodeListStore setupNodeListStore(Box nodeSource) { Future setup( {Box walletInfoSource, Box nodeSource, - Box contactSource}) async { + Box contactSource, + Box tradesSource, + PriceStore priceStore}) async { getIt.registerSingletonAsync( () => SharedPreferences.getInstance()); @@ -97,6 +104,13 @@ Future setup( nodeListStore: getIt.get())); getIt.registerSingleton( ContactService(contactSource, getIt.get().contactListStore)); + getIt.registerSingleton(TradesStore( + tradesSource: tradesSource, + settingsStore: getIt.get())); + getIt.registerSingleton( + TradeFilterStore(wallet: getIt.get().wallet)); + getIt.registerSingleton(TransactionFilterStore()); + getIt.registerFactory( () => KeyService(getIt.get())); @@ -128,7 +142,19 @@ Future setup( () => WalletAddressListViewModel(wallet: getIt.get().wallet)); getIt.registerFactory( - () => DashboardViewModel(appStore: getIt.get())); + () => BalanceViewModel( + wallet: getIt.get().wallet, + settingsStore: getIt.get(), + priceStore: priceStore)); + + getIt.registerFactory( + () => DashboardViewModel( + balanceViewModel: getIt.get(), + appStore: getIt.get(), + tradesStore: getIt.get(), + tradeFilterStore: getIt.get(), + transactionFilterStore: getIt.get() + )); getIt.registerFactory(() => AuthService( secureStorage: getIt.get(), diff --git a/lib/main.dart b/lib/main.dart index d4e59fbe2..ce3739970 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -85,13 +85,6 @@ void main() async { final exchangeTemplates = await Hive.openBox(ExchangeTemplate.boxName); - await initialSetup( - sharedPreferences: await SharedPreferences.getInstance(), - nodes: nodes, - walletInfoSource: walletInfoSource, - contactSource: contacts, - initialMigrationVersion: 3); - final sharedPreferences = await SharedPreferences.getInstance(); final walletService = WalletService(); final walletListService = WalletListService( @@ -125,6 +118,15 @@ void main() async { final walletCreationService = WalletCreationService(); final authService = AuthService(); + await initialSetup( + sharedPreferences: await SharedPreferences.getInstance(), + nodes: nodes, + walletInfoSource: walletInfoSource, + contactSource: contacts, + tradesSource: trades, + priceStore: priceStore, + initialMigrationVersion: 3); + setReactions( settingsStore: settingsStore, priceStore: priceStore, @@ -163,6 +165,8 @@ Future initialSetup( @required Box nodes, @required Box walletInfoSource, @required Box contactSource, + @required Box tradesSource, + @required PriceStore priceStore, int initialMigrationVersion = 3}) async { await defaultSettingsMigration( version: initialMigrationVersion, @@ -171,7 +175,9 @@ Future initialSetup( await setup( walletInfoSource: walletInfoSource, nodeSource: nodes, - contactSource: contactSource); + contactSource: contactSource, + tradesSource: tradesSource, + priceStore: priceStore); await bootstrap(); monero_wallet.onStartup(); } diff --git a/lib/src/domain/common/transaction_info.dart b/lib/src/domain/common/transaction_info.dart index ebbb33777..d954fb72f 100644 --- a/lib/src/domain/common/transaction_info.dart +++ b/lib/src/domain/common/transaction_info.dart @@ -8,4 +8,5 @@ abstract class TransactionInfo extends Object { int height; String amountFormatted(); String fiatAmount(); + void changeFiatAmount(String amount); } \ No newline at end of file diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 9077f8d1a..f6e644171 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -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( 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; diff --git a/lib/src/screens/dashboard/widgets/balance_page.dart b/lib/src/screens/dashboard/widgets/balance_page.dart index 2905bf14a..9cca31a31 100644 --- a/lib/src/screens/dashboard/widgets/balance_page.dart +++ b/lib/src/screens/dashboard/widgets/balance_page.dart @@ -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, diff --git a/lib/src/screens/dashboard/widgets/button_header.dart b/lib/src/screens/dashboard/widgets/button_header.dart deleted file mode 100644 index 8292704b8..000000000 --- a/lib/src/screens/dashboard/widgets/button_header.dart +++ /dev/null @@ -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(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: [ - 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( - 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 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: [ - 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 - ), - ), - ) - ], - ), - ); - } -} diff --git a/lib/src/screens/dashboard/widgets/header_row.dart b/lib/src/screens/dashboard/widgets/header_row.dart new file mode 100644 index 000000000..837c23e6f --- /dev/null +++ b/lib/src/screens/dashboard/widgets/header_row.dart @@ -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: [ + Text( + S.of(context).transactions, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + color: Colors.white + ), + ), + PopupMenuButton( + 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); + } + } + }, + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/src/screens/dashboard/widgets/sync_indicator.dart b/lib/src/screens/dashboard/widgets/sync_indicator.dart index e36290e7c..64b8575c1 100644 --- a/lib/src/screens/dashboard/widgets/sync_indicator.dart +++ b/lib/src/screens/dashboard/widgets/sync_indicator.dart @@ -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'; diff --git a/lib/src/screens/dashboard/widgets/trade_history_panel.dart b/lib/src/screens/dashboard/widgets/trade_history_panel.dart deleted file mode 100644 index 174b9cd89..000000000 --- a/lib/src/screens/dashboard/widgets/trade_history_panel.dart +++ /dev/null @@ -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 { - 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(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: [ - 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( - 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))) - ]))); //, - } -} diff --git a/lib/src/screens/dashboard/widgets/trade_row.dart b/lib/src/screens/dashboard/widgets/trade_row.dart index 954064283..8a7bc7daf 100644 --- a/lib/src/screens/dashboard/widgets/trade_row.dart +++ b/lib/src/screens/dashboard/widgets/trade_row.dart @@ -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, diff --git a/lib/src/screens/dashboard/widgets/transaction_raw.dart b/lib/src/screens/dashboard/widgets/transaction_raw.dart index b9f6e146a..0d41b42a6 100644 --- a/lib/src/screens/dashboard/widgets/transaction_raw.dart +++ b/lib/src/screens/dashboard/widgets/transaction_raw.dart @@ -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, diff --git a/lib/src/screens/dashboard/widgets/transactions_page.dart b/lib/src/screens/dashboard/widgets/transactions_page.dart new file mode 100644 index 000000000..d6cbf0ae5 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/transactions_page.dart @@ -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: [ + 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 + ), + ), + ); + } + ) + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/src/screens/dashboard/widgets/wallet_card.dart b/lib/src/screens/dashboard/widgets/wallet_card.dart deleted file mode 100644 index 041f3e89f..000000000 --- a/lib/src/screens/dashboard/widgets/wallet_card.dart +++ /dev/null @@ -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 { - 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 colorsSync) { - final settingsStore = Provider.of(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: [ - 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: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InkWell( - onTap: () => Navigator.of(context) - .pushNamed(Routes.walletList), - child: Row( - children: [ - 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: [ - Column( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - 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: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - 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 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: [ - 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: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 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: [ - 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), - ), - ) - ], - ), - ); - }); - } -} diff --git a/lib/store/dashboard/trade_filter_store.dart b/lib/store/dashboard/trade_filter_store.dart new file mode 100644 index 000000000..2e1c7ed62 --- /dev/null +++ b/lib/store/dashboard/trade_filter_store.dart @@ -0,0 +1,62 @@ +import 'package:cake_wallet/core/wallet_base.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart'; +import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart'; + +part 'trade_filter_store.g.dart'; + +class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore; + +abstract class TradeFilterStoreBase with Store { + TradeFilterStoreBase( + {this.displayXMRTO = true, + this.displayChangeNow = true, + this.displayMorphToken = true, + this.wallet}); + + @observable + bool displayXMRTO; + + @observable + bool displayChangeNow; + + @observable + bool displayMorphToken; + + WalletBase wallet; + + @action + void toggleDisplayExchange(ExchangeProviderDescription provider) { + switch (provider) { + case ExchangeProviderDescription.changeNow: + displayChangeNow = !displayChangeNow; + break; + case ExchangeProviderDescription.xmrto: + displayXMRTO = !displayXMRTO; + break; + case ExchangeProviderDescription.morphToken: + displayMorphToken = !displayMorphToken; + break; + } + } + + List filtered({List trades}) { + final _trades = + trades.where((item) => item.trade.walletId == wallet.id).toList(); + final needToFilter = !displayChangeNow || !displayXMRTO || !displayMorphToken; + + return needToFilter + ? trades + .where((item) => + (displayXMRTO && + item.trade.provider == ExchangeProviderDescription.xmrto) || + (displayChangeNow && + item.trade.provider == + ExchangeProviderDescription.changeNow) || + (displayMorphToken && + item.trade.provider == + ExchangeProviderDescription.morphToken)) + .toList() + : _trades; + } +} \ No newline at end of file diff --git a/lib/store/dashboard/trades_store.dart b/lib/store/dashboard/trades_store.dart new file mode 100644 index 000000000..4f526c637 --- /dev/null +++ b/lib/store/dashboard/trades_store.dart @@ -0,0 +1,35 @@ +import 'dart:async'; +import 'package:cake_wallet/src/domain/exchange/trade.dart'; +import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:hive/hive.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/store/settings_store.dart'; + +part 'trades_store.g.dart'; + +class TradesStore = TradesStoreBase with _$TradesStore; + +abstract class TradesStoreBase with Store { + TradesStoreBase({this.tradesSource, this.settingsStore}) { + trades = []; + + _onTradesChanged = + tradesSource.watch().listen((_) async => await updateTradeList()); + + updateTradeList(); + } + + Box tradesSource; + StreamSubscription _onTradesChanged; + SettingsStore settingsStore; + + @observable + List trades; + + @action + Future updateTradeList() async => trades = + tradesSource.values.map((trade) => TradeListItem( + trade: trade, + displayMode: settingsStore.balanceDisplayMode)).toList(); +} \ No newline at end of file diff --git a/lib/store/dashboard/transaction_filter_store.dart b/lib/store/dashboard/transaction_filter_store.dart new file mode 100644 index 000000000..b55f51795 --- /dev/null +++ b/lib/store/dashboard/transaction_filter_store.dart @@ -0,0 +1,69 @@ +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/src/domain/common/transaction_direction.dart'; +import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart'; + +part 'transaction_filter_store.g.dart'; + +class TransactionFilterStore = TransactionFilterStoreBase + with _$TransactionFilterStore; + +abstract class TransactionFilterStoreBase with Store { + TransactionFilterStoreBase( + {this.displayIncoming = true, this.displayOutgoing = true}); + + @observable + bool displayIncoming; + + @observable + bool displayOutgoing; + + @observable + DateTime startDate; + + @observable + DateTime endDate; + + @action + void toggleIncoming() => displayIncoming = !displayIncoming; + + @action + void toggleOutgoing() => displayOutgoing = !displayOutgoing; + + @action + void changeStartDate(DateTime date) => startDate = date; + + @action + void changeEndDate(DateTime date) => endDate = date; + + List filtered({List transactions}) { + var _transactions = []; + final needToFilter = !displayOutgoing || + !displayIncoming || + (startDate != null && endDate != null); + + if (needToFilter) { + _transactions = transactions.where((item) { + var allowed = true; + + if (allowed && startDate != null && endDate != null) { + allowed = startDate.isBefore(item.transaction.date) && + endDate.isAfter(item.transaction.date); + } + + if (allowed && (!displayOutgoing || !displayIncoming)) { + allowed = (displayOutgoing && + item.transaction.direction == + TransactionDirection.outgoing) || + (displayIncoming && + item.transaction.direction == TransactionDirection.incoming); + } + + return allowed; + }).toList(); + } else { + _transactions = transactions; + } + + return _transactions; + } +} \ No newline at end of file diff --git a/lib/view_model/dashboard/action_list_display_mode.dart b/lib/view_model/dashboard/action_list_display_mode.dart new file mode 100644 index 000000000..1a0708a1d --- /dev/null +++ b/lib/view_model/dashboard/action_list_display_mode.dart @@ -0,0 +1,32 @@ +enum ActionListDisplayMode { transactions, trades } + +int serializeActionlistDisplayModes(List modes) { + var i = 0; + + for (final mode in modes) { + switch (mode) { + case ActionListDisplayMode.trades: + i += 1; + break; + case ActionListDisplayMode.transactions: + i += 10; + break; + } + } + + return i; +} + +List deserializeActionlistDisplayModes(int raw) { + final modes = List(); + + if (raw == 1 || raw - 10 == 1) { + modes.add(ActionListDisplayMode.trades); + } + + if (raw >= 10) { + modes.add(ActionListDisplayMode.transactions); + } + + return modes; +} diff --git a/lib/view_model/dashboard/action_list_item.dart b/lib/view_model/dashboard/action_list_item.dart new file mode 100644 index 000000000..b03bd1bdc --- /dev/null +++ b/lib/view_model/dashboard/action_list_item.dart @@ -0,0 +1,3 @@ +abstract class ActionListItem { + DateTime get date; +} \ No newline at end of file diff --git a/lib/view_model/dashboard/balance_view_model.dart b/lib/view_model/dashboard/balance_view_model.dart new file mode 100644 index 000000000..afb8eae62 --- /dev/null +++ b/lib/view_model/dashboard/balance_view_model.dart @@ -0,0 +1,115 @@ +import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; +import 'package:cake_wallet/core/wallet_base.dart'; +import 'package:cake_wallet/monero/monero_wallet.dart'; +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; +import 'package:cake_wallet/src/domain/common/calculate_fiat_amount.dart'; +import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; +import 'package:cake_wallet/view_model/dashboard/wallet_balance.dart'; +import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/src/stores/price/price_store.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:mobx/mobx.dart'; + +part 'balance_view_model.g.dart'; + +class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel; + +abstract class BalanceViewModelBase with Store { + BalanceViewModelBase({ + @required this.wallet, + @required this.settingsStore, + @required this.priceStore + }); + + final WalletBase wallet; + final SettingsStore settingsStore; + final PriceStore priceStore; + + WalletBalance _getWalletBalance() { + final _wallet = wallet; + + if (_wallet is MoneroWallet) { + return WalletBalance( + unlockedBalance: _wallet.balance.formattedUnlockedBalance, + totalBalance: _wallet.balance.formattedFullBalance); + } + + if (_wallet is BitcoinWallet) { + return WalletBalance( + unlockedBalance: _wallet.balance.confirmedFormatted, + totalBalance: _wallet.balance.unconfirmedFormatted); + } + } + + String _getFiatBalance({double price, String cryptoAmount}) { + if (cryptoAmount == null) { + return '0.00'; + } + + return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount); + } + + @computed + double get price { + String symbol; + final _wallet = wallet; + + if (_wallet is MoneroWallet) { + symbol = PriceStoreBase.generateSymbolForPair( + fiat: settingsStore.fiatCurrency, crypto: CryptoCurrency.xmr); + } + + if (_wallet is BitcoinWallet) { + symbol = PriceStoreBase.generateSymbolForPair( + fiat: settingsStore.fiatCurrency, crypto: CryptoCurrency.btc); + } + + return priceStore.prices[symbol]; + } + + @computed + String get cryptoBalance { + final walletBalance = _getWalletBalance(); + final displayMode = settingsStore.balanceDisplayMode; + var balance = '---'; + + if (displayMode == BalanceDisplayMode.availableBalance) { + balance = walletBalance.unlockedBalance ?? '0.0'; + } + + if (displayMode == BalanceDisplayMode.fullBalance) { + balance = walletBalance.totalBalance ?? '0.0'; + } + + return balance; + } + + @computed + String get fiatBalance { + final walletBalance = _getWalletBalance(); + final displayMode = settingsStore.balanceDisplayMode; + final fiatCurrency = settingsStore.fiatCurrency; + var balance = '---'; + + final totalBalance = _getFiatBalance( + price: price, + cryptoAmount: walletBalance.totalBalance + ); + + final unlockedBalance = _getFiatBalance( + price: price, + cryptoAmount: walletBalance.unlockedBalance + ); + + if (displayMode == BalanceDisplayMode.availableBalance) { + balance = fiatCurrency.toString() + ' ' + unlockedBalance ?? '0.00'; + } + + if (displayMode == BalanceDisplayMode.fullBalance) { + balance = fiatCurrency.toString() + ' ' + totalBalance ?? '0.00'; + } + + return balance; + } + +} \ No newline at end of file diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart new file mode 100644 index 000000000..fac416af8 --- /dev/null +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -0,0 +1,145 @@ +import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; +import 'package:cake_wallet/monero/monero_wallet.dart'; +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; +import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; +import 'package:cake_wallet/src/domain/common/transaction_direction.dart'; +import 'package:cake_wallet/src/domain/common/transaction_info.dart'; +import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart'; +import 'package:cake_wallet/src/domain/exchange/trade.dart'; +import 'package:cake_wallet/view_model/dashboard/balance_view_model.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/action_list_item.dart'; +import 'package:cake_wallet/view_model/dashboard/action_list_display_mode.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/core/wallet_base.dart'; +import 'package:cake_wallet/src/domain/common/sync_status.dart'; +import 'package:cake_wallet/src/domain/common/wallet_type.dart'; +import 'package:cake_wallet/store/app_store.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/store/dashboard/trades_store.dart'; +import 'package:cake_wallet/store/dashboard/trade_filter_store.dart'; +import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart'; +import 'package:cake_wallet/view_model/dashboard/formatted_item_list.dart'; + +part 'dashboard_view_model.g.dart'; + +class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel; + +abstract class DashboardViewModelBase with Store { + DashboardViewModelBase({ + this.balanceViewModel, + this.appStore, + this.tradesStore, + this.tradeFilterStore, + this.transactionFilterStore}) { + + name = appStore.wallet?.name; + wallet ??= appStore.wallet; + type = wallet.type; + + transactions = ObservableList.of(wallet.transactionHistory.transactions + .map((transaction) => TransactionListItem( + transaction: transaction, + price: price, + fiatCurrency: appStore.settingsStore.fiatCurrency, + displayMode: balanceDisplayMode))); + + _reaction = reaction((_) => appStore.wallet, _onWalletChange); + + final _wallet = wallet; + + if (_wallet is MoneroWallet) { + subname = _wallet.account?.label; + } + + currentPage = 0; + } + + @observable + WalletType type; + + @observable + String name; + + @observable + double currentPage; + + @observable + ObservableList transactions; + + @observable + String subname; + + @computed + String get address => wallet.address; + + @computed + SyncStatus get status => wallet.syncStatus; + + @computed + String get syncStatusText { + var statusText = ''; + + if (status is SyncingSyncStatus) { + statusText = S.current + .Blocks_remaining( + status.toString()); + } + + if (status is FailedSyncStatus) { + statusText = S + .current + .please_try_to_connect_to_another_node; + } + + return statusText; + } + + @computed + BalanceDisplayMode get balanceDisplayMode => + appStore.settingsStore.balanceDisplayMode; + + @computed + List get trades => tradesStore.trades; + + @computed + double get price => balanceViewModel.price; + + @computed + List get items { + final _items = []; + + _items + .addAll(transactionFilterStore.filtered(transactions: transactions)); + _items.addAll(tradeFilterStore.filtered(trades: trades)); + + return formattedItemsList(_items); + } + + WalletBase wallet; + + BalanceViewModel balanceViewModel; + + AppStore appStore; + + TradesStore tradesStore; + + TradeFilterStore tradeFilterStore; + + TransactionFilterStore transactionFilterStore; + + ReactionDisposer _reaction; + + void _onWalletChange(WalletBase wallet) { + name = wallet.name; + transactions.clear(); + transactions.addAll(wallet.transactionHistory.transactions + .map((transaction) => TransactionListItem( + transaction: transaction, + price: price, + fiatCurrency: appStore.settingsStore.fiatCurrency, + displayMode: balanceDisplayMode))); + } +} diff --git a/lib/view_model/dashboard/date_section_item.dart b/lib/view_model/dashboard/date_section_item.dart new file mode 100644 index 000000000..0b361ecce --- /dev/null +++ b/lib/view_model/dashboard/date_section_item.dart @@ -0,0 +1,8 @@ +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart'; + +class DateSectionItem extends ActionListItem { + DateSectionItem(this.date); + + @override + final DateTime date; +} \ No newline at end of file diff --git a/lib/view_model/dashboard/formatted_item_list.dart b/lib/view_model/dashboard/formatted_item_list.dart new file mode 100644 index 000000000..9e43cb95f --- /dev/null +++ b/lib/view_model/dashboard/formatted_item_list.dart @@ -0,0 +1,34 @@ +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart'; +import 'package:cake_wallet/view_model/dashboard/date_section_item.dart'; + +List formattedItemsList(List items) { + final formattedList = []; + DateTime lastDate; + items.sort((a, b) => b.date.compareTo(a.date)); + + for (var i = 0; i < items.length; i++) { + final transaction = items[i]; + + if (lastDate == null) { + lastDate = transaction.date; + formattedList.add(DateSectionItem(transaction.date)); + formattedList.add(transaction); + continue; + } + + final isCurrentDay = lastDate.year == transaction.date.year && + lastDate.month == transaction.date.month && + lastDate.day == transaction.date.day; + + if (isCurrentDay) { + formattedList.add(transaction); + continue; + } + + lastDate = transaction.date; + formattedList.add(DateSectionItem(transaction.date)); + formattedList.add(transaction); + } + + return formattedList; +} \ No newline at end of file diff --git a/lib/view_model/dashboard/trade_list_item.dart b/lib/view_model/dashboard/trade_list_item.dart new file mode 100644 index 000000000..a0fa24ca3 --- /dev/null +++ b/lib/view_model/dashboard/trade_list_item.dart @@ -0,0 +1,21 @@ +import 'package:cake_wallet/src/domain/exchange/trade.dart'; +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart'; +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; + +class TradeListItem extends ActionListItem { + TradeListItem({this.trade, this.displayMode}); + + final Trade trade; + final BalanceDisplayMode displayMode; + + String get tradeFormattedAmount { + return trade.amount != null + ? displayMode == BalanceDisplayMode.hiddenBalance + ? '---' + : trade.amountFormatted() + : trade.amount; + } + + @override + DateTime get date => trade.createdAt; +} diff --git a/lib/view_model/dashboard/transaction_list_item.dart b/lib/view_model/dashboard/transaction_list_item.dart new file mode 100644 index 000000000..6081ef8eb --- /dev/null +++ b/lib/view_model/dashboard/transaction_list_item.dart @@ -0,0 +1,54 @@ +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; +import 'package:cake_wallet/src/domain/common/fiat_currency.dart'; +import 'package:cake_wallet/src/domain/common/transaction_info.dart'; +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart'; +import 'package:cake_wallet/src/domain/monero/monero_transaction_info.dart'; +import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart'; +import 'package:cake_wallet/src/domain/common/calculate_fiat_amount_raw.dart'; + +class TransactionListItem extends ActionListItem { + TransactionListItem({ + this.transaction, + this.price, + this.fiatCurrency, + this.displayMode + }); + + final TransactionInfo transaction; + final double price; + final FiatCurrency fiatCurrency; + final BalanceDisplayMode displayMode; + + String get formattedCryptoAmount { + + return displayMode == BalanceDisplayMode.hiddenBalance + ? '---' + : transaction.amountFormatted(); + } + + String get formattedFiatAmount { + + if (transaction is MoneroTransactionInfo) { + final amount = calculateFiatAmountRaw( + cryptoAmount: moneroAmountToDouble(amount: transaction.amount), + price: price); + transaction.changeFiatAmount(amount); + } + + if (transaction is BitcoinTransactionInfo) { + final amount = calculateFiatAmountRaw( + cryptoAmount: bitcoinAmountToDouble(amount: transaction.amount), + price: price); + transaction.changeFiatAmount(amount); + } + + return displayMode == BalanceDisplayMode.hiddenBalance + ? '---' + : fiatCurrency.title + ' ' + transaction.fiatAmount(); + } + + @override + DateTime get date => transaction.date; +} \ No newline at end of file diff --git a/lib/view_model/dashboard/wallet_balance.dart b/lib/view_model/dashboard/wallet_balance.dart new file mode 100644 index 000000000..4a142dd30 --- /dev/null +++ b/lib/view_model/dashboard/wallet_balance.dart @@ -0,0 +1,6 @@ +class WalletBalance { + WalletBalance({this.unlockedBalance, this.totalBalance}); + + String unlockedBalance; + String totalBalance; +} \ No newline at end of file diff --git a/lib/view_model/dashboard_view_model.dart b/lib/view_model/dashboard_view_model.dart deleted file mode 100644 index f48cd3aad..000000000 --- a/lib/view_model/dashboard_view_model.dart +++ /dev/null @@ -1,194 +0,0 @@ -import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart'; -import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; -import 'package:cake_wallet/monero/monero_wallet.dart'; -import 'package:cake_wallet/src/domain/common/transaction_direction.dart'; -import 'package:cake_wallet/src/domain/common/transaction_info.dart'; -import 'package:cake_wallet/src/stores/action_list/transaction_list_item.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/core/wallet_base.dart'; -import 'package:cake_wallet/src/domain/common/sync_status.dart'; -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; -import 'package:cake_wallet/store/app_store.dart'; -import 'package:cake_wallet/generated/i18n.dart'; - -part 'dashboard_view_model.g.dart'; - -class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel; - -class WalletBalace { - WalletBalace({this.unlockedBalance, this.totalBalance}); - - final String unlockedBalance; - final String totalBalance; -} - -abstract class DashboardViewModelBase with Store { - DashboardViewModelBase({this.appStore}) { - name = appStore.wallet?.name; - wallet ??= appStore.wallet; - type = wallet.type; - transactions = ObservableList.of(wallet.transactionHistory.transactions - .map((transaction) => TransactionListItem(transaction: transaction))); - _reaction = reaction((_) => appStore.wallet, _onWalletChange); - - final _wallet = wallet; - - if (_wallet is MoneroWallet) { - subname = _wallet.account?.label; - } - - currentPage = 0; - } - - @observable - WalletType type; - - @observable - String name; - - @observable - double currentPage; - - @computed - String get address => wallet.address; - - @computed - SyncStatus get status => wallet.syncStatus; - - @computed - String get syncStatusText { - var statusText = ''; - - if (status is SyncingSyncStatus) { - statusText = S.current - .Blocks_remaining( - status.toString()); - } - - if (status is FailedSyncStatus) { - statusText = S - .current - .please_try_to_connect_to_another_node; - } - - return statusText; - } - - @computed - WalletBalace get balance { - final wallet = this.wallet; - - if (wallet is MoneroWallet) { - return WalletBalace( - unlockedBalance: wallet.balance.formattedUnlockedBalance, - totalBalance: wallet.balance.formattedFullBalance); - } - - if (wallet is BitcoinWallet) { - return WalletBalace( - unlockedBalance: wallet.balance.confirmedFormatted, - totalBalance: wallet.balance.unconfirmedFormatted); - } - } - - @observable - ObservableList transactions; -// ObservableList.of([ -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// TransactionListItem(transaction: BitcoinTransactionInfo( -// id: '', -// height: 0, -// amount: 0, -// direction: TransactionDirection.incoming, -// date: DateTime.now(), -// isPending: false -// )), -// ]); - - @observable - String subname; - - WalletBase wallet; - - AppStore appStore; - - ReactionDisposer _reaction; - - void _onWalletChange(WalletBase wallet) { - name = wallet.name; - transactions.clear(); - transactions.addAll(wallet.transactionHistory.transactions - .map((transaction) => TransactionListItem(transaction: transaction))); - } -}