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

Oleksandr Sobol committed Jul 23, 2020 at 15:20 UTC bdfe208d20bbd33962666275d331d6cb14bacd48
27 files changed +937 -1311
lib/bitcoin/bitcoin_transaction_info.dart
+8 -2
@@ -4,6 +4,7 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
4 import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
5 import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
6 import 'package:cake_wallet/src/domain/common/transaction_info.dart';
7 +import 'package:cake_wallet/src/domain/common/format_amount.dart';
8
9 class BitcoinTransactionInfo extends TransactionInfo {
10 BitcoinTransactionInfo(
@@ -62,11 +63,16 @@ class BitcoinTransactionInfo extends TransactionInfo {
63
64 final String id;
65
66 + String _fiatAmount;
67 +
68 + @override
69 + String amountFormatted() => '${formatAmount(bitcoinAmountToString(amount: amount))} BTC';
70 +
71 @override
66 - String amountFormatted() => bitcoinAmountToString(amount: amount);
72 + String fiatAmount() => _fiatAmount ?? '';
73
74 @override
69 - String fiatAmount() => '\$ 24.5';
75 + void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
76
77 Map<String, dynamic> toJson() {
78 final m = Map<String, dynamic>();
lib/di.dart
+30 -4
@@ -1,6 +1,7 @@
1 import 'package:cake_wallet/core/contact_service.dart';
2 import 'package:cake_wallet/src/domain/common/contact.dart';
3 import 'package:cake_wallet/src/domain/common/node.dart';
4 +import 'package:cake_wallet/src/domain/exchange/trade.dart';
5 import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
6 import 'package:cake_wallet/src/screens/contact/contact_page.dart';
7 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';
12 import 'package:cake_wallet/store/contact_list_store.dart';
13 import 'package:cake_wallet/store/node_list_store.dart';
14 import 'package:cake_wallet/store/settings_store.dart';
14 -import 'package:cake_wallet/store/settings_store.dart';
15 +import 'package:cake_wallet/src/stores/price/price_store.dart';
16 import 'package:cake_wallet/core/auth_service.dart';
17 import 'package:cake_wallet/core/key_service.dart';
18 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';
32 import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
33 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart';
34 import 'package:cake_wallet/view_model/auth_view_model.dart';
34 -import 'package:cake_wallet/view_model/dashboard_view_model.dart';
35 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
36 +import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
37 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
38 import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
39 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';
54 import 'package:cake_wallet/src/domain/common/wallet_type.dart';
55 import 'package:cake_wallet/view_model/wallet_new_vm.dart';
56 import 'package:cake_wallet/store/authentication_store.dart';
57 +import 'package:cake_wallet/store/dashboard/trades_store.dart';
58 +import 'package:cake_wallet/store/dashboard/trade_filter_store.dart';
59 +import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
60
61 final getIt = GetIt.instance;
62
@@ -77,7 +82,9 @@ NodeListStore setupNodeListStore(Box<Node> nodeSource) {
82 Future setup(
83 {Box<WalletInfo> walletInfoSource,
84 Box<Node> nodeSource,
80 - Box<Contact> contactSource}) async {
85 + Box<Contact> contactSource,
86 + Box<Trade> tradesSource,
87 + PriceStore priceStore}) async {
88 getIt.registerSingletonAsync<SharedPreferences>(
89 () => SharedPreferences.getInstance());
90
@@ -97,6 +104,13 @@ Future setup(
104 nodeListStore: getIt.get<NodeListStore>()));
105 getIt.registerSingleton<ContactService>(
106 ContactService(contactSource, getIt.get<AppStore>().contactListStore));
107 + getIt.registerSingleton<TradesStore>(TradesStore(
108 + tradesSource: tradesSource,
109 + settingsStore: getIt.get<SettingsStore>()));
110 + getIt.registerSingleton<TradeFilterStore>(
111 + TradeFilterStore(wallet: getIt.get<AppStore>().wallet));
112 + getIt.registerSingleton<TransactionFilterStore>(TransactionFilterStore());
113 +
114 getIt.registerFactory<KeyService>(
115 () => KeyService(getIt.get<FlutterSecureStorage>()));
116
@@ -128,7 +142,19 @@ Future setup(
142 () => WalletAddressListViewModel(wallet: getIt.get<AppStore>().wallet));
143
144 getIt.registerFactory(
131 - () => DashboardViewModel(appStore: getIt.get<AppStore>()));
145 + () => BalanceViewModel(
146 + wallet: getIt.get<AppStore>().wallet,
147 + settingsStore: getIt.get<SettingsStore>(),
148 + priceStore: priceStore));
149 +
150 + getIt.registerFactory(
151 + () => DashboardViewModel(
152 + balanceViewModel: getIt.get<BalanceViewModel>(),
153 + appStore: getIt.get<AppStore>(),
154 + tradesStore: getIt.get<TradesStore>(),
155 + tradeFilterStore: getIt.get<TradeFilterStore>(),
156 + transactionFilterStore: getIt.get<TransactionFilterStore>()
157 + ));
158
159 getIt.registerFactory<AuthService>(() => AuthService(
160 secureStorage: getIt.get<FlutterSecureStorage>(),
lib/main.dart
+14 -8
@@ -85,13 +85,6 @@ void main() async {
85 final exchangeTemplates =
86 await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
87
88 - await initialSetup(
89 - sharedPreferences: await SharedPreferences.getInstance(),
90 - nodes: nodes,
91 - walletInfoSource: walletInfoSource,
92 - contactSource: contacts,
93 - initialMigrationVersion: 3);
94 -
88 final sharedPreferences = await SharedPreferences.getInstance();
89 final walletService = WalletService();
90 final walletListService = WalletListService(
@@ -125,6 +118,15 @@ void main() async {
118 final walletCreationService = WalletCreationService();
119 final authService = AuthService();
120
121 + await initialSetup(
122 + sharedPreferences: await SharedPreferences.getInstance(),
123 + nodes: nodes,
124 + walletInfoSource: walletInfoSource,
125 + contactSource: contacts,
126 + tradesSource: trades,
127 + priceStore: priceStore,
128 + initialMigrationVersion: 3);
129 +
130 setReactions(
131 settingsStore: settingsStore,
132 priceStore: priceStore,
@@ -163,6 +165,8 @@ Future<void> initialSetup(
165 @required Box<Node> nodes,
166 @required Box<WalletInfo> walletInfoSource,
167 @required Box<Contact> contactSource,
168 + @required Box<Trade> tradesSource,
169 + @required PriceStore priceStore,
170 int initialMigrationVersion = 3}) async {
171 await defaultSettingsMigration(
172 version: initialMigrationVersion,
@@ -171,7 +175,9 @@ Future<void> initialSetup(
175 await setup(
176 walletInfoSource: walletInfoSource,
177 nodeSource: nodes,
174 - contactSource: contactSource);
178 + contactSource: contactSource,
179 + tradesSource: tradesSource,
180 + priceStore: priceStore);
181 await bootstrap();
182 monero_wallet.onStartup();
183 }
lib/src/domain/common/transaction_info.dart
+1
@@ -8,4 +8,5 @@ abstract class TransactionInfo extends Object {
8 int height;
9 String amountFormatted();
10 String fiatAmount();
11 + void changeFiatAmount(String amount);
12 }
\ No newline at end of file
lib/src/screens/dashboard/dashboard_page.dart
+9 -12
@@ -2,13 +2,14 @@ import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/routes.dart';
3 import 'package:flutter/material.dart';
4 import 'package:flutter/cupertino.dart';
5 -import 'package:cake_wallet/view_model/dashboard_view_model.dart';
5 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
6 import 'package:cake_wallet/src/screens/base_page.dart';
7 import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
8 import 'package:cake_wallet/palette.dart';
9 import 'package:dots_indicator/dots_indicator.dart';
10 import 'package:cake_wallet/src/screens/dashboard/widgets/action_button.dart';
11 import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
12 +import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
13 import 'package:flutter_mobx/flutter_mobx.dart';
14 import 'package:mobx/mobx.dart';
15 import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
@@ -35,8 +36,11 @@ class DashboardPage extends BasePage {
36 return Container(
37 alignment: Alignment.centerRight,
38 width: 40,
38 - child: InkWell(
39 - onTap: () async {
39 + child: FlatButton(
40 + highlightColor: Colors.transparent,
41 + splashColor: Colors.transparent,
42 + padding: EdgeInsets.all(0),
43 + onPressed: () async {
44 await showDialog<void>(
45 builder: (_) => MenuWidget(
46 name: walletViewModel.name,
@@ -45,7 +49,7 @@ class DashboardPage extends BasePage {
49 context: context);
50 },
51 child: menuButton
48 - ),
52 + )
53 );
54 }
55
@@ -141,14 +145,7 @@ class DashboardPage extends BasePage {
145 }
146
147 pages.add(BalancePage(dashboardViewModel: walletViewModel));
144 - pages.add(Center(
145 - child: Text(
146 - 'SECOND PAGE',
147 - style: TextStyle(
148 - color: Colors.white
149 - ),
150 - ),
151 - ));
148 + pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
149
150 controller.addListener(() {
151 walletViewModel.currentPage = controller.page;
lib/src/screens/dashboard/widgets/balance_page.dart
+3 -3
@@ -1,5 +1,5 @@
1 import 'package:flutter/material.dart';
2 -import 'package:cake_wallet/view_model/dashboard_view_model.dart';
2 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
3 import 'package:cake_wallet/palette.dart';
4 import 'package:flutter_mobx/flutter_mobx.dart';
5
@@ -35,7 +35,7 @@ class BalancePage extends StatelessWidget {
35 Observer(
36 builder: (_) {
37 return Text(
38 - dashboardViewModel.balance.totalBalance,
38 + dashboardViewModel.balanceViewModel.cryptoBalance,
39 style: TextStyle(
40 fontSize: 54,
41 fontWeight: FontWeight.bold,
@@ -48,7 +48,7 @@ class BalancePage extends StatelessWidget {
48 Observer(
49 builder: (_) {
50 return Text(
51 - '\$ 0.00',
51 + dashboardViewModel.balanceViewModel.fiatBalance,
52 style: TextStyle(
53 fontSize: 18,
54 fontWeight: FontWeight.w500,
lib/src/screens/dashboard/widgets/button_header.dart deleted
-255
@@ -1,255 +0,0 @@
1 -import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
2 -import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
3 -import 'package:flutter/cupertino.dart';
4 -import 'package:flutter/material.dart';
5 -import 'package:cake_wallet/generated/i18n.dart';
6 -import 'package:flutter_mobx/flutter_mobx.dart';
7 -import 'package:provider/provider.dart';
8 -import 'package:cake_wallet/routes.dart';
9 -import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
10 -import 'package:cake_wallet/themes.dart';
11 -import 'package:cake_wallet/theme_changer.dart';
12 -
13 -class ButtonHeader extends SliverPersistentHeaderDelegate {
14 - final sendImage = Image.asset('assets/images/send.png');
15 - final exchangeImage = Image.asset('assets/images/exchange.png');
16 - final buyImage = Image.asset('assets/images/coins.png');
17 -
18 - @override
19 - Widget build(
20 - BuildContext context, double shrinkOffset, bool overlapsContent) {
21 - final _themeChanger = Provider.of<ThemeChanger>(context);
22 - Image filterButton;
23 -
24 - if (_themeChanger.getTheme() == Themes.darkTheme) {
25 - filterButton = Image.asset('assets/images/filter_button.png');
26 - } else {
27 - filterButton = Image.asset('assets/images/filter_light_button.png');
28 - }
29 -
30 - return ClipRRect(
31 - borderRadius: BorderRadius.only(
32 - topLeft: Radius.circular(24), topRight: Radius.circular(24)),
33 - child: Container(
34 - color: Colors.red,
35 -// height: 75,
36 - padding: EdgeInsets.only(top: 26, left: 20, right: 20, bottom: 10),
37 -// color: Theme.of(context).backgroundColor,
38 - child: Stack(
39 - children: <Widget>[
40 - Center(
41 - child: Text(
42 - S.of(context).transactions,
43 - style: TextStyle(
44 - fontSize: 20,
45 - fontWeight: FontWeight.w600,
46 - color: Theme.of(context).primaryTextTheme.title.color),
47 - )),
48 - Positioned(
49 - right: 0,
50 - height: 36,
51 - child: PopupMenuButton<int>(
52 - itemBuilder: (context) => [
53 - PopupMenuItem(
54 - enabled: false,
55 - value: -1,
56 - child: Text(S.of(context).transactions,
57 - style: TextStyle(
58 - fontWeight: FontWeight.bold,
59 - color: Theme.of(context)
60 - .primaryTextTheme
61 - .caption
62 - .color))),
63 -// PopupMenuItem(
64 -// value: 0,
65 -// child: Observer(
66 -// builder: (_) => Row(
67 -// mainAxisAlignment:
68 -// MainAxisAlignment
69 -// .spaceBetween,
70 -// children: [
71 -// Text(S.of(context).incoming),
72 -// Checkbox(
73 -// value: actionListStore
74 -// .transactionFilterStore
75 -// .displayIncoming,
76 -// onChanged: (value) =>
77 -// actionListStore
78 -// .transactionFilterStore
79 -// .toggleIncoming(),
80 -// )
81 -// ]))),
82 -// PopupMenuItem(
83 -// value: 1,
84 -// child: Observer(
85 -// builder: (_) => Row(
86 -// mainAxisAlignment:
87 -// MainAxisAlignment
88 -// .spaceBetween,
89 -// children: [
90 -// Text(S.of(context).outgoing),
91 -// Checkbox(
92 -// value: actionListStore
93 -// .transactionFilterStore
94 -// .displayOutgoing,
95 -// onChanged: (value) =>
96 -// actionListStore
97 -// .transactionFilterStore
98 -// .toggleOutgoing(),
99 -// )
100 -// ]))),
101 - PopupMenuItem(
102 - value: 2,
103 - child: Text(S.of(context).transactions_by_date)),
104 - PopupMenuDivider(),
105 - PopupMenuItem(
106 - enabled: false,
107 - value: -1,
108 - child: Text(S.of(context).trades,
109 - style: TextStyle(
110 - fontWeight: FontWeight.bold,
111 - color: Theme.of(context)
112 - .primaryTextTheme
113 - .caption
114 - .color))),
115 - PopupMenuItem(
116 - value: 3,
117 - child: Observer(
118 - builder: (_) => Row(
119 - mainAxisAlignment:
120 - MainAxisAlignment.spaceBetween,
121 - children: [
122 - Text('XMR.TO'),
123 -// Checkbox(
124 -// value: actionListStore
125 -// .tradeFilterStore
126 -// .displayXMRTO,
127 -// onChanged: (value) =>
128 -// actionListStore
129 -// .tradeFilterStore
130 -// .toggleDisplayExchange(
131 -// ExchangeProviderDescription
132 -// .xmrto),
133 -// )
134 - ]))),
135 - PopupMenuItem(
136 - value: 4,
137 - child: Observer(
138 - builder: (_) => Row(
139 - mainAxisAlignment:
140 - MainAxisAlignment.spaceBetween,
141 - children: [
142 - Text('Change.NOW'),
143 -// Checkbox(
144 -// value: actionListStore
145 -// .tradeFilterStore
146 -// .displayChangeNow,
147 -// onChanged: (value) =>
148 -// actionListStore
149 -// .tradeFilterStore
150 -// .toggleDisplayExchange(
151 -// ExchangeProviderDescription
152 -// .changeNow),
153 -// )
154 - ]))),
155 - PopupMenuItem(
156 - value: 5,
157 - child: Observer(
158 - builder: (_) => Row(
159 - mainAxisAlignment:
160 - MainAxisAlignment.spaceBetween,
161 - children: [
162 - Text('MorphToken'),
163 -// Checkbox(
164 -// value: actionListStore
165 -// .tradeFilterStore
166 -// .displayMorphToken,
167 -// onChanged: (value) =>
168 -// actionListStore
169 -// .tradeFilterStore
170 -// .toggleDisplayExchange(
171 -// ExchangeProviderDescription
172 -// .morphToken),
173 -// )
174 - ])))
175 - ],
176 - child: filterButton,
177 - onSelected: (item) async {
178 - if (item == 2) {
179 - final List<DateTime> picked =
180 - await date_rage_picker.showDatePicker(
181 - context: context,
182 - initialFirstDate:
183 - DateTime.now().subtract(Duration(days: 1)),
184 - initialLastDate: (DateTime.now()),
185 - firstDate: DateTime(2015),
186 - lastDate: DateTime.now().add(Duration(days: 1)));
187 -
188 - if (picked != null && picked.length == 2) {
189 -// actionListStore.transactionFilterStore
190 -// .changeStartDate(picked.first);
191 -// actionListStore.transactionFilterStore
192 -// .changeEndDate(picked.last);
193 - }
194 - }
195 - },
196 - )),
197 - ],
198 - ),
199 - ),
200 - );
201 - }
202 -
203 - @override
204 - double get maxExtent => 164;
205 -
206 - @override
207 - double get minExtent => 66;
208 -
209 - @override
210 - bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
211 -
212 - Widget actionButton(
213 - {BuildContext context,
214 - @required Image image,
215 - @required String title,
216 - @required String route}) {
217 - return Container(
218 - width: MediaQuery.of(context).size.width,
219 - child: Column(
220 - mainAxisAlignment: MainAxisAlignment.start,
221 - crossAxisAlignment: CrossAxisAlignment.center,
222 - children: <Widget>[
223 - GestureDetector(
224 - onTap: () {
225 - if (route.isNotEmpty) {
226 - Navigator.of(context, rootNavigator: true).pushNamed(route);
227 - }
228 - },
229 - child: Container(
230 - height: 48,
231 - width: 48,
232 - alignment: Alignment.center,
233 - decoration: BoxDecoration(
234 - color: Theme.of(context).primaryTextTheme.subhead.color,
235 - shape: BoxShape.circle),
236 - child: image,
237 - ),
238 - ),
239 - Padding(
240 - padding: EdgeInsets.only(top: 12),
241 - child: Text(
242 - title,
243 - style: TextStyle(
244 - fontSize: 16,
245 - fontWeight: FontWeight.w600,
246 - color: Color.fromRGBO(140, 153, 201,
247 - 0.8) // Theme.of(context).primaryTextTheme.caption.color
248 - ),
249 - ),
250 - )
251 - ],
252 - ),
253 - );
254 - }
255 -}
lib/src/screens/dashboard/widgets/header_row.dart new
+187
@@ -0,0 +1,187 @@
1 +import 'package:flutter/material.dart';
2 +import 'package:cake_wallet/palette.dart';
3 +import 'package:cake_wallet/generated/i18n.dart';
4 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
5 +import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
6 +import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
7 +import 'package:flutter_mobx/flutter_mobx.dart';
8 +
9 +class HeaderRow extends StatelessWidget {
10 + HeaderRow({this.dashboardViewModel});
11 +
12 + final DashboardViewModel dashboardViewModel;
13 +
14 + final filterIcon = Image.asset('assets/images/filter_icon.png',
15 + color: PaletteDark.wildBlue);
16 +
17 + @override
18 + Widget build(BuildContext context) {
19 + return Container(
20 + height: 52,
21 + color: Colors.transparent,
22 + padding: EdgeInsets.only(left: 24, right: 24),
23 + child: Row(
24 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
25 + crossAxisAlignment: CrossAxisAlignment.center,
26 + children: <Widget>[
27 + Text(
28 + S.of(context).transactions,
29 + style: TextStyle(
30 + fontSize: 20,
31 + fontWeight: FontWeight.w500,
32 + color: Colors.white
33 + ),
34 + ),
35 + PopupMenuButton<int>(
36 + itemBuilder: (context) => [
37 + PopupMenuItem(
38 + enabled: false,
39 + value: -1,
40 + child: Text(S.of(context).transactions,
41 + style: TextStyle(
42 + fontWeight: FontWeight.bold,
43 + color: Theme.of(context).primaryTextTheme.caption.color))),
44 + PopupMenuItem(
45 + value: 0,
46 + child: Observer(
47 + builder: (_) => Row(
48 + mainAxisAlignment:
49 + MainAxisAlignment
50 + .spaceBetween,
51 + children: [
52 + Text(S.of(context).incoming),
53 + Checkbox(
54 + value: dashboardViewModel
55 + .transactionFilterStore
56 + .displayIncoming,
57 + onChanged: (value) => dashboardViewModel
58 + .transactionFilterStore
59 + .toggleIncoming()
60 + )
61 + ]))),
62 + PopupMenuItem(
63 + value: 1,
64 + child: Observer(
65 + builder: (_) => Row(
66 + mainAxisAlignment:
67 + MainAxisAlignment
68 + .spaceBetween,
69 + children: [
70 + Text(S.of(context).outgoing),
71 + Checkbox(
72 + value: dashboardViewModel
73 + .transactionFilterStore
74 + .displayOutgoing,
75 + onChanged: (value) => dashboardViewModel
76 + .transactionFilterStore
77 + .toggleOutgoing(),
78 + )
79 + ]))),
80 + PopupMenuItem(
81 + value: 2,
82 + child:
83 + Text(S.of(context).transactions_by_date)),
84 + PopupMenuDivider(),
85 + PopupMenuItem(
86 + enabled: false,
87 + value: -1,
88 + child: Text(S.of(context).trades,
89 + style: TextStyle(
90 + fontWeight: FontWeight.bold,
91 + color: Theme.of(context).primaryTextTheme.caption.color))),
92 + PopupMenuItem(
93 + value: 3,
94 + child: Observer(
95 + builder: (_) => Row(
96 + mainAxisAlignment:
97 + MainAxisAlignment
98 + .spaceBetween,
99 + children: [
100 + Text('XMR.TO'),
101 + Checkbox(
102 + value: dashboardViewModel
103 + .tradeFilterStore
104 + .displayXMRTO,
105 + onChanged: (value) => dashboardViewModel
106 + .tradeFilterStore
107 + .toggleDisplayExchange(
108 + ExchangeProviderDescription
109 + .xmrto),
110 + )
111 + ]))),
112 + PopupMenuItem(
113 + value: 4,
114 + child: Observer(
115 + builder: (_) => Row(
116 + mainAxisAlignment:
117 + MainAxisAlignment
118 + .spaceBetween,
119 + children: [
120 + Text('Change.NOW'),
121 + Checkbox(
122 + value: dashboardViewModel
123 + .tradeFilterStore
124 + .displayChangeNow,
125 + onChanged: (value) => dashboardViewModel
126 + .tradeFilterStore
127 + .toggleDisplayExchange(
128 + ExchangeProviderDescription
129 + .changeNow),
130 + )
131 + ]))),
132 + PopupMenuItem(
133 + value: 5,
134 + child: Observer(
135 + builder: (_) => Row(
136 + mainAxisAlignment:
137 + MainAxisAlignment
138 + .spaceBetween,
139 + children: [
140 + Text('MorphToken'),
141 + Checkbox(
142 + value: dashboardViewModel
143 + .tradeFilterStore
144 + .displayMorphToken,
145 + onChanged: (value) => dashboardViewModel
146 + .tradeFilterStore
147 + .toggleDisplayExchange(
148 + ExchangeProviderDescription
149 + .morphToken),
150 + )
151 + ])))
152 + ],
153 + child: Container(
154 + height: 36,
155 + width: 36,
156 + decoration: BoxDecoration(
157 + shape: BoxShape.circle,
158 + color: PaletteDark.oceanBlue
159 + ),
160 + child: filterIcon,
161 + ),
162 + onSelected: (item) async {
163 + if (item == 2) {
164 + final picked =
165 + await date_rage_picker.showDatePicker(
166 + context: context,
167 + initialFirstDate: DateTime.now()
168 + .subtract(Duration(days: 1)),
169 + initialLastDate: (DateTime.now()),
170 + firstDate: DateTime(2015),
171 + lastDate: DateTime.now()
172 + .add(Duration(days: 1)));
173 +
174 + if (picked != null && picked.length == 2) {
175 + dashboardViewModel.transactionFilterStore
176 + .changeStartDate(picked.first);
177 + dashboardViewModel.transactionFilterStore
178 + .changeEndDate(picked.last);
179 + }
180 + }
181 + },
182 + ),
183 + ],
184 + ),
185 + );
186 + }
187 +}
\ No newline at end of file
lib/src/screens/dashboard/widgets/sync_indicator.dart
+1 -1
@@ -1,5 +1,5 @@
1 import 'package:flutter/material.dart';
2 -import 'package:cake_wallet/view_model/dashboard_view_model.dart';
2 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
3 import 'package:cake_wallet/palette.dart';
4 import 'package:flutter_mobx/flutter_mobx.dart';
5 import 'package:cake_wallet/src/domain/common/sync_status.dart';
lib/src/screens/dashboard/widgets/trade_history_panel.dart deleted
-322
@@ -1,322 +0,0 @@
1 -import 'package:cake_wallet/generated/i18n.dart';
2 -import 'package:cake_wallet/theme_changer.dart';
3 -import 'package:cake_wallet/themes.dart';
4 -import 'package:flutter/cupertino.dart';
5 -import 'package:flutter/material.dart';
6 -import 'package:flutter_mobx/flutter_mobx.dart';
7 -import 'package:intl/intl.dart';
8 -import 'package:provider/provider.dart';
9 -import 'package:cake_wallet/routes.dart';
10 -import 'package:cake_wallet/view_model/dashboard_view_model.dart';
11 -import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
12 -import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
13 -import 'package:cake_wallet/src/stores/action_list/date_section_item.dart';
14 -import 'package:cake_wallet/src/stores/action_list/trade_list_item.dart';
15 -import 'package:cake_wallet/src/stores/action_list/transaction_list_item.dart';
16 -import 'package:cake_wallet/src/stores/settings/settings_store.dart';
17 -import 'date_section_raw.dart';
18 -import 'trade_row.dart';
19 -import 'transaction_raw.dart';
20 -import 'button_header.dart';
21 -import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
22 -
23 -class TradeHistoryPanel extends StatefulWidget {
24 - TradeHistoryPanel({this.dashboardViewModel});
25 -
26 - final DashboardViewModel dashboardViewModel;
27 -
28 - @override
29 - TradeHistoryPanelState createState() => TradeHistoryPanelState();
30 -}
31 -
32 -class TradeHistoryPanelState extends State<TradeHistoryPanel> {
33 - final _listObserverKey = GlobalKey();
34 - final _listKey = GlobalKey();
35 -
36 - double panelHeight;
37 - double screenHeight;
38 -
39 - @override
40 - void initState() {
41 - panelHeight = 0;
42 - screenHeight = 0;
43 - super.initState();
44 - WidgetsBinding.instance.addPostFrameCallback(afterLayout);
45 - }
46 -
47 - void afterLayout(dynamic _) {
48 - screenHeight = MediaQuery.of(context).size.height;
49 - setState(() {
50 - panelHeight = screenHeight;
51 - });
52 - }
53 -
54 - @override
55 - Widget build(BuildContext context) {
56 - // AnimatedContainer(
57 -// width: MediaQuery.of(context).size.width,
58 -// height: panelHeight,
59 -// duration: Duration(milliseconds: 1000),
60 -// curve: Curves.fastOutSlowIn,
61 -// child: )
62 -
63 - final transactionDateFormat = DateFormat('HH:mm');
64 - final _themeChanger = Provider.of<ThemeChanger>(context);
65 - final filterButton = Image.asset(
66 - _themeChanger.getTheme() == Themes.darkTheme
67 - ? 'assets/images/filter_button.png'
68 - : 'assets/images/filter_light_button.png',
69 - height: 36);
70 -
71 - return ClipRRect(
72 - borderRadius: BorderRadius.only(
73 - topLeft: Radius.circular(20), topRight: Radius.circular(20)),
74 - child: Container(
75 - color: Colors.white,
76 - child: Column(children: [
77 - Container(
78 - padding:
79 - EdgeInsets.only(top: 32, left: 20, right: 20, bottom: 20),
80 - color: Theme.of(context).backgroundColor,
81 - child: Stack(
82 - children: <Widget>[
83 - SizedBox(height: 37), // Force stack height
84 - Center(
85 - child: Text(S.of(context).transactions,
86 - style: TextStyle(
87 - fontSize: 20,
88 - fontWeight: FontWeight.w600,
89 - color: Theme.of(context)
90 - .primaryTextTheme
91 - .title
92 - .color))),
93 - Positioned(
94 - right: 0,
95 - child: PopupMenuButton<int>(
96 - itemBuilder: (context) => [
97 - PopupMenuItem(
98 - enabled: false,
99 - value: -1,
100 - child: Text(S.of(context).transactions,
101 - style: TextStyle(
102 - fontWeight: FontWeight.bold,
103 - color: Theme.of(context)
104 - .primaryTextTheme
105 - .caption
106 - .color))),
107 -// PopupMenuItem(
108 -// value: 0,
109 -// child: Observer(
110 -// builder: (_) => Row(
111 -// mainAxisAlignment:
112 -// MainAxisAlignment
113 -// .spaceBetween,
114 -// children: [
115 -// Text(S.of(context).incoming),
116 -// Checkbox(
117 -// value: actionListStore
118 -// .transactionFilterStore
119 -// .displayIncoming,
120 -// onChanged: (value) =>
121 -// actionListStore
122 -// .transactionFilterStore
123 -// .toggleIncoming(),
124 -// )
125 -// ]))),
126 -// PopupMenuItem(
127 -// value: 1,
128 -// child: Observer(
129 -// builder: (_) => Row(
130 -// mainAxisAlignment:
131 -// MainAxisAlignment
132 -// .spaceBetween,
133 -// children: [
134 -// Text(S.of(context).outgoing),
135 -// Checkbox(
136 -// value: actionListStore
137 -// .transactionFilterStore
138 -// .displayOutgoing,
139 -// onChanged: (value) =>
140 -// actionListStore
141 -// .transactionFilterStore
142 -// .toggleOutgoing(),
143 -// )
144 -// ]))),
145 - PopupMenuItem(
146 - value: 2,
147 - child:
148 - Text(S.of(context).transactions_by_date)),
149 - PopupMenuDivider(),
150 - PopupMenuItem(
151 - enabled: false,
152 - value: -1,
153 - child: Text(S.of(context).trades,
154 - style: TextStyle(
155 - fontWeight: FontWeight.bold,
156 - color: Theme.of(context)
157 - .primaryTextTheme
158 - .caption
159 - .color))),
160 - PopupMenuItem(
161 - value: 3,
162 - child: Observer(
163 - builder: (_) => Row(
164 - mainAxisAlignment:
165 - MainAxisAlignment.spaceBetween,
166 - children: [
167 - Text('XMR.TO'),
168 -// Checkbox(
169 -// value: actionListStore
170 -// .tradeFilterStore
171 -// .displayXMRTO,
172 -// onChanged: (value) =>
173 -// actionListStore
174 -// .tradeFilterStore
175 -// .toggleDisplayExchange(
176 -// ExchangeProviderDescription
177 -// .xmrto),
178 -// )
179 - ]))),
180 - PopupMenuItem(
181 - value: 4,
182 - child: Observer(
183 - builder: (_) => Row(
184 - mainAxisAlignment:
185 - MainAxisAlignment.spaceBetween,
186 - children: [
187 - Text('Change.NOW'),
188 -// Checkbox(
189 -// value: actionListStore
190 -// .tradeFilterStore
191 -// .displayChangeNow,
192 -// onChanged: (value) =>
193 -// actionListStore
194 -// .tradeFilterStore
195 -// .toggleDisplayExchange(
196 -// ExchangeProviderDescription
197 -// .changeNow),
198 -// )
199 - ]))),
200 - PopupMenuItem(
201 - value: 5,
202 - child: Observer(
203 - builder: (_) => Row(
204 - mainAxisAlignment:
205 - MainAxisAlignment.spaceBetween,
206 - children: [
207 - Text('MorphToken'),
208 -// Checkbox(
209 -// value: actionListStore
210 -// .tradeFilterStore
211 -// .displayMorphToken,
212 -// onChanged: (value) =>
213 -// actionListStore
214 -// .tradeFilterStore
215 -// .toggleDisplayExchange(
216 -// ExchangeProviderDescription
217 -// .morphToken),
218 -// )
219 - ])))
220 - ],
221 - child: filterButton,
222 - onSelected: (item) async {
223 - if (item == 2) {
224 - final picked =
225 - await date_rage_picker.showDatePicker(
226 - context: context,
227 - initialFirstDate: DateTime.now()
228 - .subtract(Duration(days: 1)),
229 - initialLastDate: (DateTime.now()),
230 - firstDate: DateTime(2015),
231 - lastDate: DateTime.now()
232 - .add(Duration(days: 1)));
233 -
234 - if (picked != null && picked.length == 2) {
235 -// actionListStore.transactionFilterStore
236 -// .changeStartDate(picked.first);
237 -// actionListStore.transactionFilterStore
238 -// .changeEndDate(picked.last);
239 - }
240 - }
241 - },
242 - )),
243 - ],
244 - ),
245 - ),
246 - widget.dashboardViewModel.transactions?.isNotEmpty ?? false
247 - ? ListView.separated(
248 - physics: NeverScrollableScrollPhysics(),
249 - shrinkWrap: true,
250 - itemCount: widget.dashboardViewModel.transactions.length,
251 - itemBuilder: (_, index) {
252 - final item =
253 - widget.dashboardViewModel.transactions[index];
254 -
255 - if (item is DateSectionItem) {
256 - return DateSectionRaw(date: item.date);
257 - }
258 -
259 - if (item is TransactionListItem) {
260 - final transaction = item.transaction;
261 - final savedDisplayMode = BalanceDisplayMode.all;
262 - //settingsStore
263 -// .balanceDisplayMode;
264 - final formattedAmount = savedDisplayMode ==
265 - BalanceDisplayMode.hiddenBalance
266 - ? '---'
267 - : transaction.amountFormatted();
268 - final formattedFiatAmount = savedDisplayMode ==
269 - BalanceDisplayMode.hiddenBalance
270 - ? '---'
271 - : transaction.fiatAmount(); // symbol ???
272 -
273 - return TransactionRow(
274 - onTap: () => Navigator.of(context).pushNamed(
275 - Routes.transactionDetails,
276 - arguments: transaction),
277 - direction: transaction.direction,
278 - formattedDate: transactionDateFormat
279 - .format(transaction.date),
280 - formattedAmount: formattedAmount,
281 - formattedFiatAmount: formattedFiatAmount,
282 - isPending: transaction.isPending);
283 - }
284 -
285 - if (item is TradeListItem) {
286 - final trade = item.trade;
287 - final savedDisplayMode = BalanceDisplayMode.all;
288 - //settingsStore
289 - // .balanceDisplayMode;
290 - final formattedAmount = trade.amount != null
291 - ? savedDisplayMode ==
292 - BalanceDisplayMode.hiddenBalance
293 - ? '---'
294 - : trade.amountFormatted()
295 - : trade.amount;
296 -
297 - return TradeRow(
298 - onTap: () => Navigator.of(context).pushNamed(
299 - Routes.tradeDetails,
300 - arguments: trade),
301 - provider: trade.provider,
302 - from: trade.from,
303 - to: trade.to,
304 - createdAtFormattedDate:
305 - transactionDateFormat.format(trade.createdAt),
306 - formattedAmount: formattedAmount);
307 - }
308 -
309 - return Container(
310 - color: Theme.of(context).backgroundColor,
311 - height: 1);
312 - },
313 - separatorBuilder: (_, __) =>
314 - Container(height: 14, color: Colors.white),
315 - )
316 - : Padding(
317 - padding: EdgeInsets.all(20),
318 - child: Text('Your transactions will be displayed here!',
319 - style: TextStyle(color: Colors.grey)))
320 - ]))); //,
321 - }
322 -}
lib/src/screens/dashboard/widgets/trade_row.dart
+1 -1
@@ -37,7 +37,7 @@ class TradeRow extends StatelessWidget {
37 child: Padding(
38 padding: const EdgeInsets.only(left: 12),
39 child: Container(
40 - height: 42,
40 + height: 46,
41 child: Column(
42 mainAxisAlignment: MainAxisAlignment.spaceBetween,
43 mainAxisSize: MainAxisSize.max,
lib/src/screens/dashboard/widgets/transaction_raw.dart
+1 -1
@@ -46,7 +46,7 @@ class TransactionRow extends StatelessWidget {
46 child: Padding(
47 padding: const EdgeInsets.only(left: 12),
48 child: Container(
49 - height: 42,
49 + height: 46,
50 child: Column(
51 mainAxisAlignment: MainAxisAlignment.spaceBetween,
52 mainAxisSize: MainAxisSize.max,
lib/src/screens/dashboard/widgets/transactions_page.dart new
+98
@@ -0,0 +1,98 @@
1 +import 'package:flutter/material.dart';
2 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
3 +import 'package:flutter_mobx/flutter_mobx.dart';
4 +import 'package:cake_wallet/src/screens/dashboard/widgets/header_row.dart';
5 +import 'package:cake_wallet/src/screens/dashboard/widgets/date_section_raw.dart';
6 +import 'package:cake_wallet/src/screens/dashboard/widgets/trade_row.dart';
7 +import 'package:cake_wallet/src/screens/dashboard/widgets/transaction_raw.dart';
8 +import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
9 +import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
10 +import 'package:cake_wallet/view_model/dashboard/date_section_item.dart';
11 +import 'package:intl/intl.dart';
12 +import 'package:cake_wallet/routes.dart';
13 +import 'package:cake_wallet/generated/i18n.dart';
14 +
15 +class TransactionsPage extends StatelessWidget {
16 + TransactionsPage({@required this.dashboardViewModel});
17 +
18 + final DashboardViewModel dashboardViewModel;
19 +
20 + @override
21 + Widget build(BuildContext context) {
22 + return Container(
23 + padding: EdgeInsets.only(
24 + top: 24,
25 + bottom: 24
26 + ),
27 + child: Column(
28 + children: <Widget>[
29 + HeaderRow(dashboardViewModel: dashboardViewModel),
30 + Expanded(
31 + child: Observer(
32 + builder: (_) {
33 + final items = dashboardViewModel.items;
34 +
35 + return items?.isNotEmpty ?? false
36 + ? ListView.builder(
37 + itemCount: items.length,
38 + itemBuilder: (context, index) {
39 +
40 + final item = items[index];
41 +
42 + if (item is DateSectionItem) {
43 + return DateSectionRaw(date: item.date);
44 + }
45 +
46 + if (item is TransactionListItem) {
47 + final transaction = item.transaction;
48 +
49 + return TransactionRow(
50 + onTap: () => Navigator.of(context).pushNamed(
51 + Routes.transactionDetails,
52 + arguments: transaction),
53 + direction: transaction.direction,
54 + formattedDate: DateFormat('HH:mm')
55 + .format(transaction.date),
56 + formattedAmount: item.formattedCryptoAmount,
57 + formattedFiatAmount: item.formattedFiatAmount,
58 + isPending: transaction.isPending);
59 + }
60 +
61 + if (item is TradeListItem) {
62 + final trade = item.trade;
63 +
64 + return TradeRow(
65 + onTap: () => Navigator.of(context).pushNamed(
66 + Routes.tradeDetails,
67 + arguments: trade),
68 + provider: trade.provider,
69 + from: trade.from,
70 + to: trade.to,
71 + createdAtFormattedDate:
72 + DateFormat('HH:mm').format(trade.createdAt),
73 + formattedAmount: item.tradeFormattedAmount
74 + );
75 + }
76 +
77 + return Container(
78 + color: Theme.of(context).backgroundColor,
79 + height: 1);
80 + }
81 + )
82 + : Center(
83 + child: Text(
84 + S.of(context).placeholder_transactions,
85 + style: TextStyle(
86 + fontSize: 14,
87 + color: Colors.grey
88 + ),
89 + ),
90 + );
91 + }
92 + )
93 + )
94 + ],
95 + ),
96 + );
97 + }
98 +}
\ No newline at end of file
lib/src/screens/dashboard/widgets/wallet_card.dart deleted
-508
@@ -1,508 +0,0 @@
1 -import 'dart:async';
2 -import 'package:cake_wallet/palette.dart';
3 -import 'package:flutter/services.dart';
4 -import 'package:provider/provider.dart';
5 -import 'package:flutter/cupertino.dart';
6 -import 'package:flutter/material.dart';
7 -import 'package:flutter_mobx/flutter_mobx.dart';
8 -import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
9 -import 'package:cake_wallet/src/stores/settings/settings_store.dart';
10 -import 'package:cake_wallet/generated/i18n.dart';
11 -import 'package:cake_wallet/src/domain/common/sync_status.dart';
12 -import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
13 -import 'package:cake_wallet/routes.dart';
14 -import 'package:cake_wallet/view_model/dashboard_view_model.dart';
15 -
16 -class WalletCard extends StatefulWidget {
17 - WalletCard({this.walletVM});
18 -
19 - final DashboardViewModel walletVM;
20 -
21 - @override
22 - WalletCardState createState() => WalletCardState();
23 -}
24 -
25 -class WalletCardState extends State<WalletCard> {
26 - final _syncingObserverKey = GlobalKey();
27 - final _balanceObserverKey = GlobalKey();
28 - final _addressObserverKey = GlobalKey();
29 -
30 - double cardWidth;
31 - double cardHeight;
32 - double screenWidth;
33 - double opacity;
34 - bool isDraw;
35 - bool isFrontSide;
36 -
37 - @override
38 - void initState() {
39 - cardWidth = 0;
40 - cardHeight = 220;
41 - screenWidth = 0;
42 - opacity = 0;
43 - isDraw = false;
44 - isFrontSide = true;
45 - super.initState();
46 - WidgetsBinding.instance.addPostFrameCallback(afterLayout);
47 - }
48 -
49 - void afterLayout(dynamic _) {
50 - screenWidth = MediaQuery.of(context).size.width - 20;
51 - setState(() {
52 - cardWidth = screenWidth;
53 - opacity = 1;
54 - });
55 - Timer(Duration(milliseconds: 500), () => setState(() => isDraw = true));
56 - }
57 -
58 - @override
59 - Widget build(BuildContext context) {
60 - final colorsSync = [
61 - Theme.of(context).cardTheme.color,
62 - Theme.of(context).hoverColor
63 - ];
64 -
65 - return Container(
66 - width: double.infinity,
67 - height: cardHeight,
68 - alignment: Alignment.centerRight,
69 - decoration: BoxDecoration(
70 - borderRadius: BorderRadius.only(
71 - topLeft: Radius.circular(14), bottomLeft: Radius.circular(14))),
72 - child: AnimatedContainer(
73 - alignment: Alignment.centerLeft,
74 - width: cardWidth,
75 - height: cardHeight,
76 - duration: Duration(milliseconds: 500),
77 - curve: Curves.fastOutSlowIn,
78 - decoration: BoxDecoration(
79 - borderRadius: BorderRadius.only(
80 - topLeft: Radius.circular(14),
81 - bottomLeft: Radius.circular(14)),
82 - color: Theme.of(context).focusColor),
83 - child: ClipRRect(
84 - borderRadius: BorderRadius.only(
85 - topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
86 - child: Container(
87 - width: cardWidth,
88 - height: cardHeight,
89 - color: Theme.of(context).cardColor,
90 - child: isFrontSide
91 - ? frontSide(colorsSync)
92 - : InkWell(
93 - onTap: () => setState(() => isFrontSide = true),
94 - child: backSide(colorsSync)),
95 - ),
96 - )),
97 - );
98 - }
99 -
100 - Widget frontSide(List<Color> colorsSync) {
101 - final settingsStore = Provider.of<SettingsStore>(context);
102 - final triangleButton = Image.asset(
103 - 'assets/images/triangle.png',
104 - color: Theme.of(context).primaryTextTheme.title.color,
105 - );
106 -
107 - return Observer(
108 - key: _syncingObserverKey,
109 - builder: (_) {
110 - final status = widget.walletVM.status;
111 - final statusText = status.title();
112 - final progress = status.progress();
113 - final indicatorOffset = progress * cardWidth;
114 - final indicatorWidth =
115 - progress <= 1 ? cardWidth - indicatorOffset : 0.0;
116 - var descriptionText = '';
117 -
118 - if (status is SyncingSyncStatus) {
119 - descriptionText = S.of(context).Blocks_remaining(status.toString());
120 - }
121 -
122 - if (status is FailedSyncStatus) {
123 - descriptionText = S.of(context).please_try_to_connect_to_another_node;
124 - }
125 -
126 - return Container(
127 - width: cardWidth,
128 - height: cardHeight,
129 - color: Colors.white,
130 - child: Stack(
131 - children: <Widget>[
132 - progress <= 1
133 - ? Positioned(
134 - left: indicatorOffset,
135 - top: 0,
136 - bottom: 0,
137 - child: Container(
138 - width: indicatorWidth,
139 - height: cardHeight,
140 - color: Color.fromRGBO(227, 238, 249, 1),
141 - ))
142 - : Offstage(),
143 - isDraw
144 - ? Positioned(
145 - left: 24,
146 - right: 24,
147 - top: 32,
148 - bottom: 24,
149 - child: Container(
150 - child: Column(
151 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
152 - children: <Widget>[
153 - Row(
154 - crossAxisAlignment: CrossAxisAlignment.start,
155 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
156 - children: <Widget>[
157 - Column(
158 - crossAxisAlignment: CrossAxisAlignment.start,
159 - children: <Widget>[
160 - InkWell(
161 - onTap: () => Navigator.of(context)
162 - .pushNamed(Routes.walletList),
163 - child: Row(
164 - children: <Widget>[
165 - Text(
166 - widget.walletVM.name,
167 - style: TextStyle(
168 - fontSize: 20,
169 - fontWeight: FontWeight.bold,
170 - color: Theme.of(context)
171 - .primaryTextTheme
172 - .title
173 - .color),
174 - ),
175 - SizedBox(width: 10),
176 - triangleButton
177 - ],
178 - ),
179 - ),
180 - SizedBox(height: 5),
181 - if (widget.walletVM.subname?.isNotEmpty ??
182 - false)
183 - Text(
184 - widget.walletVM.subname,
185 - style: TextStyle(
186 - fontSize: 12,
187 - fontWeight: FontWeight.w600,
188 - color: Theme.of(context)
189 - .primaryTextTheme
190 - .caption
191 - .color),
192 - )
193 - ],
194 - ),
195 - InkWell(
196 - onTap: () =>
197 - setState(() => isFrontSide = false),
198 - child: Container(
199 - width: 98,
200 - height: 32,
201 - alignment: Alignment.center,
202 - decoration: BoxDecoration(
203 - color: Theme.of(context)
204 - .accentTextTheme
205 - .subtitle
206 - .backgroundColor,
207 - border: Border.all(
208 - color: Color.fromRGBO(
209 - 219, 231, 237, 1)),
210 - // FIXME
211 - borderRadius: BorderRadius.all(
212 - Radius.circular(16))),
213 - child: Text(
214 - 'Receive',
215 - style: TextStyle(
216 - fontSize: 12,
217 - fontWeight: FontWeight.w600,
218 - color: Theme.of(context)
219 - .primaryTextTheme
220 - .title
221 - .color),
222 - )),
223 - )
224 - ],
225 - ),
226 - status is SyncedSyncStatus
227 - ? Observer(
228 - key: _balanceObserverKey,
229 - builder: (_) {
230 - final balanceDisplayMode =
231 - BalanceDisplayMode.availableBalance;
232 -// settingsStore.balanceDisplayMode;
233 - final symbol =
234 - settingsStore.fiatCurrency.toString();
235 - var balance = '---';
236 - var fiatBalance = '---';
237 -
238 - if (balanceDisplayMode ==
239 - BalanceDisplayMode.availableBalance) {
240 - balance = widget.walletVM.balance
241 - .unlockedBalance ??
242 - '0.0';
243 - fiatBalance = '\$ 0.00';
244 -// '$symbol ${balanceStore.fiatUnlockedBalance}';
245 - }
246 -
247 - if (balanceDisplayMode ==
248 - BalanceDisplayMode.fullBalance) {
249 - balance = widget.walletVM.balance
250 - .totalBalance ??
251 - '0.0';
252 - fiatBalance = '\$ 0.00';
253 -// '$symbol ${balanceStore.fiatFullBalance}';
254 - }
255 -
256 - return Row(
257 - crossAxisAlignment:
258 - CrossAxisAlignment.end,
259 - mainAxisAlignment:
260 - MainAxisAlignment.spaceBetween,
261 - children: <Widget>[
262 - Column(
263 - mainAxisAlignment:
264 - MainAxisAlignment.spaceBetween,
265 - crossAxisAlignment:
266 - CrossAxisAlignment.start,
267 - children: <Widget>[
268 - Text(
269 - balanceDisplayMode.toString(),
270 - style: TextStyle(
271 - fontSize: 12,
272 - color: Theme.of(context)
273 - .primaryTextTheme
274 - .caption
275 - .color),
276 - ),
277 - SizedBox(height: 5),
278 - Container(
279 - height: 36,
280 - child: Text(
281 - balance,
282 - style: TextStyle(
283 - fontSize: 32,
284 - color: Theme.of(context)
285 - .primaryTextTheme
286 - .title
287 - .color,
288 - fontWeight:
289 - FontWeight.bold),
290 - ))
291 - ],
292 - ),
293 - Text(
294 - fiatBalance,
295 - style: TextStyle(
296 - fontSize: 14,
297 - fontWeight: FontWeight.w600,
298 -// FIXME
299 -// color: Theme.of(context)
300 -// .primaryTextTheme
301 -// .title
302 -// .color,
303 - color: Color.fromRGBO(
304 - 72, 89, 109, 1)),
305 - )
306 - ],
307 - );
308 - })
309 - : Row(
310 - crossAxisAlignment: CrossAxisAlignment.end,
311 - mainAxisAlignment:
312 - MainAxisAlignment.spaceBetween,
313 - children: <Widget>[
314 - Column(
315 - crossAxisAlignment:
316 - CrossAxisAlignment.start,
317 - children: <Widget>[
318 - Text(
319 - statusText,
320 - style: TextStyle(
321 - fontSize: 12,
322 - fontWeight: FontWeight.w600,
323 - color: Theme.of(context)
324 - .primaryTextTheme
325 - .caption
326 - .color),
327 - ),
328 - SizedBox(height: 5),
329 - Text(
330 - descriptionText,
331 - style: TextStyle(
332 - fontSize: 14,
333 - fontWeight: FontWeight.w600,
334 - color: Theme.of(context)
335 - .primaryTextTheme
336 - .title
337 - .color),
338 - )
339 - ],
340 - )
341 - ],
342 - )
343 - ],
344 - ),
345 - ))
346 - : Offstage()
347 - ],
348 - ),
349 - );
350 - },
351 - );
352 - }
353 -
354 - Widget backSide(List<Color> colorsSync) {
355 - final rightArrow = Image.asset('assets/images/right_arrow.png',
356 - color: Theme.of(context).primaryTextTheme.title.color);
357 - var messageBoxHeight = 0.0;
358 - var messageBoxWidth = cardWidth - 10;
359 -
360 - return Observer(
361 - key: _addressObserverKey,
362 - builder: (_) {
363 - return Container(
364 - width: cardWidth,
365 - height: cardHeight,
366 - alignment: Alignment.topCenter,
367 - child: Stack(
368 - alignment: Alignment.topRight,
369 - children: <Widget>[
370 - Container(
371 - width: cardWidth,
372 - height: cardHeight,
373 - padding:
374 - EdgeInsets.only(left: 24, right: 24, top: 32, bottom: 32),
375 - decoration: BoxDecoration(
376 - borderRadius: BorderRadius.only(
377 - topLeft: Radius.circular(10),
378 - bottomLeft: Radius.circular(10)),
379 - gradient: LinearGradient(
380 - colors: colorsSync,
381 - begin: Alignment.topCenter,
382 - end: Alignment.bottomCenter)),
383 - child: Column(
384 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
385 - children: <Widget>[
386 - Row(
387 - crossAxisAlignment: CrossAxisAlignment.start,
388 - children: <Widget>[
389 - Expanded(
390 - child: Container(
391 - child: Column(
392 - crossAxisAlignment: CrossAxisAlignment.start,
393 - children: <Widget>[
394 - Text(
395 - S.current.card_address,
396 - style: TextStyle(
397 - fontSize: 12,
398 - color: Theme.of(context)
399 - .primaryTextTheme
400 - .caption
401 - .color),
402 - ),
403 - SizedBox(height: 10),
404 - GestureDetector(
405 - onTap: () {
406 - Clipboard.setData(ClipboardData(
407 - text: widget.walletVM.address));
408 - _addressObserverKey.currentState
409 - .setState(() {
410 - messageBoxHeight = 20;
411 - messageBoxWidth = cardWidth;
412 - });
413 - Timer(Duration(milliseconds: 1000), () {
414 - try {
415 - _addressObserverKey.currentState
416 - .setState(() {
417 - messageBoxHeight = 0;
418 - messageBoxWidth = cardWidth - 10;
419 - });
420 - } catch (e) {
421 - print('${e.toString()}');
422 - }
423 - });
424 - },
425 - child: Text(
426 - widget.walletVM.address,
427 - style: TextStyle(
428 - fontSize: 12,
429 - fontWeight: FontWeight.w600,
430 - color: Theme.of(context)
431 - .primaryTextTheme
432 - .title
433 - .color),
434 - ),
435 - )
436 - ],
437 - ),
438 - )),
439 - SizedBox(width: 10),
440 - Container(
441 - width: 90,
442 - height: 90,
443 - child: QrImage(
444 - data: widget.walletVM.address,
445 - backgroundColor: Colors.transparent,
446 - foregroundColor: Theme.of(context)
447 - .primaryTextTheme
448 - .caption
449 - .color),
450 - )
451 - ],
452 - ),
453 - Container(
454 - height: 44,
455 - padding: EdgeInsets.only(left: 20, right: 20),
456 - alignment: Alignment.center,
457 - decoration: BoxDecoration(
458 - borderRadius: BorderRadius.all(Radius.circular(22)),
459 - color: Theme.of(context)
460 - .primaryTextTheme
461 - .overline
462 - .color),
463 - child: InkWell(
464 - onTap: () =>
465 - Navigator.of(context, rootNavigator: true)
466 - .pushNamed(Routes.receive),
467 - child: Row(
468 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
469 - children: <Widget>[
470 - Text(
471 - S.of(context).addresses,
472 - style: TextStyle(
473 - fontSize: 14,
474 - fontWeight: FontWeight.w600,
475 - color: Theme.of(context)
476 - .primaryTextTheme
477 - .title
478 - .color),
479 - ),
480 - rightArrow
481 - ],
482 - ),
483 - ),
484 - )
485 - ],
486 - ),
487 - ),
488 - AnimatedContainer(
489 - width: messageBoxWidth,
490 - height: messageBoxHeight,
491 - alignment: Alignment.center,
492 - duration: Duration(milliseconds: 500),
493 - curve: Curves.fastOutSlowIn,
494 - decoration: BoxDecoration(
495 - borderRadius:
496 - BorderRadius.only(topLeft: Radius.circular(10)),
497 - color: Colors.green),
498 - child: Text(
499 - S.of(context).copied_to_clipboard,
500 - style: TextStyle(fontSize: 10, color: Colors.white),
501 - ),
502 - )
503 - ],
504 - ),
505 - );
506 - });
507 - }
508 -}
lib/store/dashboard/trade_filter_store.dart new
+62
@@ -0,0 +1,62 @@
1 +import 'package:cake_wallet/core/wallet_base.dart';
2 +import 'package:mobx/mobx.dart';
3 +import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
4 +import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
5 +
6 +part 'trade_filter_store.g.dart';
7 +
8 +class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore;
9 +
10 +abstract class TradeFilterStoreBase with Store {
11 + TradeFilterStoreBase(
12 + {this.displayXMRTO = true,
13 + this.displayChangeNow = true,
14 + this.displayMorphToken = true,
15 + this.wallet});
16 +
17 + @observable
18 + bool displayXMRTO;
19 +
20 + @observable
21 + bool displayChangeNow;
22 +
23 + @observable
24 + bool displayMorphToken;
25 +
26 + WalletBase wallet;
27 +
28 + @action
29 + void toggleDisplayExchange(ExchangeProviderDescription provider) {
30 + switch (provider) {
31 + case ExchangeProviderDescription.changeNow:
32 + displayChangeNow = !displayChangeNow;
33 + break;
34 + case ExchangeProviderDescription.xmrto:
35 + displayXMRTO = !displayXMRTO;
36 + break;
37 + case ExchangeProviderDescription.morphToken:
38 + displayMorphToken = !displayMorphToken;
39 + break;
40 + }
41 + }
42 +
43 + List<TradeListItem> filtered({List<TradeListItem> trades}) {
44 + final _trades =
45 + trades.where((item) => item.trade.walletId == wallet.id).toList();
46 + final needToFilter = !displayChangeNow || !displayXMRTO || !displayMorphToken;
47 +
48 + return needToFilter
49 + ? trades
50 + .where((item) =>
51 + (displayXMRTO &&
52 + item.trade.provider == ExchangeProviderDescription.xmrto) ||
53 + (displayChangeNow &&
54 + item.trade.provider ==
55 + ExchangeProviderDescription.changeNow) ||
56 + (displayMorphToken &&
57 + item.trade.provider ==
58 + ExchangeProviderDescription.morphToken))
59 + .toList()
60 + : _trades;
61 + }
62 +}
\ No newline at end of file
lib/store/dashboard/trades_store.dart new
+35
@@ -0,0 +1,35 @@
1 +import 'dart:async';
2 +import 'package:cake_wallet/src/domain/exchange/trade.dart';
3 +import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
4 +import 'package:flutter/cupertino.dart';
5 +import 'package:hive/hive.dart';
6 +import 'package:mobx/mobx.dart';
7 +import 'package:cake_wallet/store/settings_store.dart';
8 +
9 +part 'trades_store.g.dart';
10 +
11 +class TradesStore = TradesStoreBase with _$TradesStore;
12 +
13 +abstract class TradesStoreBase with Store {
14 + TradesStoreBase({this.tradesSource, this.settingsStore}) {
15 + trades = <TradeListItem>[];
16 +
17 + _onTradesChanged =
18 + tradesSource.watch().listen((_) async => await updateTradeList());
19 +
20 + updateTradeList();
21 + }
22 +
23 + Box<Trade> tradesSource;
24 + StreamSubscription<BoxEvent> _onTradesChanged;
25 + SettingsStore settingsStore;
26 +
27 + @observable
28 + List<TradeListItem> trades;
29 +
30 + @action
31 + Future updateTradeList() async => trades =
32 + tradesSource.values.map((trade) => TradeListItem(
33 + trade: trade,
34 + displayMode: settingsStore.balanceDisplayMode)).toList();
35 +}
\ No newline at end of file
lib/store/dashboard/transaction_filter_store.dart new
+69
@@ -0,0 +1,69 @@
1 +import 'package:mobx/mobx.dart';
2 +import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
3 +import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
4 +
5 +part 'transaction_filter_store.g.dart';
6 +
7 +class TransactionFilterStore = TransactionFilterStoreBase
8 + with _$TransactionFilterStore;
9 +
10 +abstract class TransactionFilterStoreBase with Store {
11 + TransactionFilterStoreBase(
12 + {this.displayIncoming = true, this.displayOutgoing = true});
13 +
14 + @observable
15 + bool displayIncoming;
16 +
17 + @observable
18 + bool displayOutgoing;
19 +
20 + @observable
21 + DateTime startDate;
22 +
23 + @observable
24 + DateTime endDate;
25 +
26 + @action
27 + void toggleIncoming() => displayIncoming = !displayIncoming;
28 +
29 + @action
30 + void toggleOutgoing() => displayOutgoing = !displayOutgoing;
31 +
32 + @action
33 + void changeStartDate(DateTime date) => startDate = date;
34 +
35 + @action
36 + void changeEndDate(DateTime date) => endDate = date;
37 +
38 + List<TransactionListItem> filtered({List<TransactionListItem> transactions}) {
39 + var _transactions = <TransactionListItem>[];
40 + final needToFilter = !displayOutgoing ||
41 + !displayIncoming ||
42 + (startDate != null && endDate != null);
43 +
44 + if (needToFilter) {
45 + _transactions = transactions.where((item) {
46 + var allowed = true;
47 +
48 + if (allowed && startDate != null && endDate != null) {
49 + allowed = startDate.isBefore(item.transaction.date) &&
50 + endDate.isAfter(item.transaction.date);
51 + }
52 +
53 + if (allowed && (!displayOutgoing || !displayIncoming)) {
54 + allowed = (displayOutgoing &&
55 + item.transaction.direction ==
56 + TransactionDirection.outgoing) ||
57 + (displayIncoming &&
58 + item.transaction.direction == TransactionDirection.incoming);
59 + }
60 +
61 + return allowed;
62 + }).toList();
63 + } else {
64 + _transactions = transactions;
65 + }
66 +
67 + return _transactions;
68 + }
69 +}
\ No newline at end of file
lib/view_model/dashboard/action_list_display_mode.dart new
+32
@@ -0,0 +1,32 @@
1 +enum ActionListDisplayMode { transactions, trades }
2 +
3 +int serializeActionlistDisplayModes(List<ActionListDisplayMode> modes) {
4 + var i = 0;
5 +
6 + for (final mode in modes) {
7 + switch (mode) {
8 + case ActionListDisplayMode.trades:
9 + i += 1;
10 + break;
11 + case ActionListDisplayMode.transactions:
12 + i += 10;
13 + break;
14 + }
15 + }
16 +
17 + return i;
18 +}
19 +
20 +List<ActionListDisplayMode> deserializeActionlistDisplayModes(int raw) {
21 + final modes = List<ActionListDisplayMode>();
22 +
23 + if (raw == 1 || raw - 10 == 1) {
24 + modes.add(ActionListDisplayMode.trades);
25 + }
26 +
27 + if (raw >= 10) {
28 + modes.add(ActionListDisplayMode.transactions);
29 + }
30 +
31 + return modes;
32 +}
lib/view_model/dashboard/action_list_item.dart new
+3
@@ -0,0 +1,3 @@
1 +abstract class ActionListItem {
2 + DateTime get date;
3 +}
\ No newline at end of file
lib/view_model/dashboard/balance_view_model.dart new
+115
@@ -0,0 +1,115 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
2 +import 'package:cake_wallet/core/wallet_base.dart';
3 +import 'package:cake_wallet/monero/monero_wallet.dart';
4 +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
5 +import 'package:cake_wallet/src/domain/common/calculate_fiat_amount.dart';
6 +import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
7 +import 'package:cake_wallet/view_model/dashboard/wallet_balance.dart';
8 +import 'package:cake_wallet/store/settings_store.dart';
9 +import 'package:cake_wallet/src/stores/price/price_store.dart';
10 +import 'package:flutter/cupertino.dart';
11 +import 'package:mobx/mobx.dart';
12 +
13 +part 'balance_view_model.g.dart';
14 +
15 +class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel;
16 +
17 +abstract class BalanceViewModelBase with Store {
18 + BalanceViewModelBase({
19 + @required this.wallet,
20 + @required this.settingsStore,
21 + @required this.priceStore
22 + });
23 +
24 + final WalletBase wallet;
25 + final SettingsStore settingsStore;
26 + final PriceStore priceStore;
27 +
28 + WalletBalance _getWalletBalance() {
29 + final _wallet = wallet;
30 +
31 + if (_wallet is MoneroWallet) {
32 + return WalletBalance(
33 + unlockedBalance: _wallet.balance.formattedUnlockedBalance,
34 + totalBalance: _wallet.balance.formattedFullBalance);
35 + }
36 +
37 + if (_wallet is BitcoinWallet) {
38 + return WalletBalance(
39 + unlockedBalance: _wallet.balance.confirmedFormatted,
40 + totalBalance: _wallet.balance.unconfirmedFormatted);
41 + }
42 + }
43 +
44 + String _getFiatBalance({double price, String cryptoAmount}) {
45 + if (cryptoAmount == null) {
46 + return '0.00';
47 + }
48 +
49 + return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount);
50 + }
51 +
52 + @computed
53 + double get price {
54 + String symbol;
55 + final _wallet = wallet;
56 +
57 + if (_wallet is MoneroWallet) {
58 + symbol = PriceStoreBase.generateSymbolForPair(
59 + fiat: settingsStore.fiatCurrency, crypto: CryptoCurrency.xmr);
60 + }
61 +
62 + if (_wallet is BitcoinWallet) {
63 + symbol = PriceStoreBase.generateSymbolForPair(
64 + fiat: settingsStore.fiatCurrency, crypto: CryptoCurrency.btc);
65 + }
66 +
67 + return priceStore.prices[symbol];
68 + }
69 +
70 + @computed
71 + String get cryptoBalance {
72 + final walletBalance = _getWalletBalance();
73 + final displayMode = settingsStore.balanceDisplayMode;
74 + var balance = '---';
75 +
76 + if (displayMode == BalanceDisplayMode.availableBalance) {
77 + balance = walletBalance.unlockedBalance ?? '0.0';
78 + }
79 +
80 + if (displayMode == BalanceDisplayMode.fullBalance) {
81 + balance = walletBalance.totalBalance ?? '0.0';
82 + }
83 +
84 + return balance;
85 + }
86 +
87 + @computed
88 + String get fiatBalance {
89 + final walletBalance = _getWalletBalance();
90 + final displayMode = settingsStore.balanceDisplayMode;
91 + final fiatCurrency = settingsStore.fiatCurrency;
92 + var balance = '---';
93 +
94 + final totalBalance = _getFiatBalance(
95 + price: price,
96 + cryptoAmount: walletBalance.totalBalance
97 + );
98 +
99 + final unlockedBalance = _getFiatBalance(
100 + price: price,
101 + cryptoAmount: walletBalance.unlockedBalance
102 + );
103 +
104 + if (displayMode == BalanceDisplayMode.availableBalance) {
105 + balance = fiatCurrency.toString() + ' ' + unlockedBalance ?? '0.00';
106 + }
107 +
108 + if (displayMode == BalanceDisplayMode.fullBalance) {
109 + balance = fiatCurrency.toString() + ' ' + totalBalance ?? '0.00';
110 + }
111 +
112 + return balance;
113 + }
114 +
115 +}
\ No newline at end of file
lib/view_model/dashboard/dashboard_view_model.dart new
+145
@@ -0,0 +1,145 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
2 +import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
3 +import 'package:cake_wallet/monero/monero_wallet.dart';
4 +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
5 +import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
6 +import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
7 +import 'package:cake_wallet/src/domain/common/transaction_info.dart';
8 +import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
9 +import 'package:cake_wallet/src/domain/exchange/trade.dart';
10 +import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
11 +import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
12 +import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
13 +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
14 +import 'package:cake_wallet/view_model/dashboard/action_list_display_mode.dart';
15 +import 'package:mobx/mobx.dart';
16 +import 'package:cake_wallet/core/wallet_base.dart';
17 +import 'package:cake_wallet/src/domain/common/sync_status.dart';
18 +import 'package:cake_wallet/src/domain/common/wallet_type.dart';
19 +import 'package:cake_wallet/store/app_store.dart';
20 +import 'package:cake_wallet/generated/i18n.dart';
21 +import 'package:cake_wallet/store/dashboard/trades_store.dart';
22 +import 'package:cake_wallet/store/dashboard/trade_filter_store.dart';
23 +import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
24 +import 'package:cake_wallet/view_model/dashboard/formatted_item_list.dart';
25 +
26 +part 'dashboard_view_model.g.dart';
27 +
28 +class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
29 +
30 +abstract class DashboardViewModelBase with Store {
31 + DashboardViewModelBase({
32 + this.balanceViewModel,
33 + this.appStore,
34 + this.tradesStore,
35 + this.tradeFilterStore,
36 + this.transactionFilterStore}) {
37 +
38 + name = appStore.wallet?.name;
39 + wallet ??= appStore.wallet;
40 + type = wallet.type;
41 +
42 + transactions = ObservableList.of(wallet.transactionHistory.transactions
43 + .map((transaction) => TransactionListItem(
44 + transaction: transaction,
45 + price: price,
46 + fiatCurrency: appStore.settingsStore.fiatCurrency,
47 + displayMode: balanceDisplayMode)));
48 +
49 + _reaction = reaction((_) => appStore.wallet, _onWalletChange);
50 +
51 + final _wallet = wallet;
52 +
53 + if (_wallet is MoneroWallet) {
54 + subname = _wallet.account?.label;
55 + }
56 +
57 + currentPage = 0;
58 + }
59 +
60 + @observable
61 + WalletType type;
62 +
63 + @observable
64 + String name;
65 +
66 + @observable
67 + double currentPage;
68 +
69 + @observable
70 + ObservableList<TransactionListItem> transactions;
71 +
72 + @observable
73 + String subname;
74 +
75 + @computed
76 + String get address => wallet.address;
77 +
78 + @computed
79 + SyncStatus get status => wallet.syncStatus;
80 +
81 + @computed
82 + String get syncStatusText {
83 + var statusText = '';
84 +
85 + if (status is SyncingSyncStatus) {
86 + statusText = S.current
87 + .Blocks_remaining(
88 + status.toString());
89 + }
90 +
91 + if (status is FailedSyncStatus) {
92 + statusText = S
93 + .current
94 + .please_try_to_connect_to_another_node;
95 + }
96 +
97 + return statusText;
98 + }
99 +
100 + @computed
101 + BalanceDisplayMode get balanceDisplayMode =>
102 + appStore.settingsStore.balanceDisplayMode;
103 +
104 + @computed
105 + List<TradeListItem> get trades => tradesStore.trades;
106 +
107 + @computed
108 + double get price => balanceViewModel.price;
109 +
110 + @computed
111 + List<ActionListItem> get items {
112 + final _items = <ActionListItem>[];
113 +
114 + _items
115 + .addAll(transactionFilterStore.filtered(transactions: transactions));
116 + _items.addAll(tradeFilterStore.filtered(trades: trades));
117 +
118 + return formattedItemsList(_items);
119 + }
120 +
121 + WalletBase wallet;
122 +
123 + BalanceViewModel balanceViewModel;
124 +
125 + AppStore appStore;
126 +
127 + TradesStore tradesStore;
128 +
129 + TradeFilterStore tradeFilterStore;
130 +
131 + TransactionFilterStore transactionFilterStore;
132 +
133 + ReactionDisposer _reaction;
134 +
135 + void _onWalletChange(WalletBase wallet) {
136 + name = wallet.name;
137 + transactions.clear();
138 + transactions.addAll(wallet.transactionHistory.transactions
139 + .map((transaction) => TransactionListItem(
140 + transaction: transaction,
141 + price: price,
142 + fiatCurrency: appStore.settingsStore.fiatCurrency,
143 + displayMode: balanceDisplayMode)));
144 + }
145 +}
lib/view_model/dashboard/date_section_item.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
2 +
3 +class DateSectionItem extends ActionListItem {
4 + DateSectionItem(this.date);
5 +
6 + @override
7 + final DateTime date;
8 +}
\ No newline at end of file
lib/view_model/dashboard/formatted_item_list.dart new
+34
@@ -0,0 +1,34 @@
1 +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
2 +import 'package:cake_wallet/view_model/dashboard/date_section_item.dart';
3 +
4 +List<ActionListItem> formattedItemsList(List<ActionListItem> items) {
5 + final formattedList = <ActionListItem>[];
6 + DateTime lastDate;
7 + items.sort((a, b) => b.date.compareTo(a.date));
8 +
9 + for (var i = 0; i < items.length; i++) {
10 + final transaction = items[i];
11 +
12 + if (lastDate == null) {
13 + lastDate = transaction.date;
14 + formattedList.add(DateSectionItem(transaction.date));
15 + formattedList.add(transaction);
16 + continue;
17 + }
18 +
19 + final isCurrentDay = lastDate.year == transaction.date.year &&
20 + lastDate.month == transaction.date.month &&
21 + lastDate.day == transaction.date.day;
22 +
23 + if (isCurrentDay) {
24 + formattedList.add(transaction);
25 + continue;
26 + }
27 +
28 + lastDate = transaction.date;
29 + formattedList.add(DateSectionItem(transaction.date));
30 + formattedList.add(transaction);
31 + }
32 +
33 + return formattedList;
34 +}
\ No newline at end of file
lib/view_model/dashboard/trade_list_item.dart new
+21
@@ -0,0 +1,21 @@
1 +import 'package:cake_wallet/src/domain/exchange/trade.dart';
2 +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
3 +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
4 +
5 +class TradeListItem extends ActionListItem {
6 + TradeListItem({this.trade, this.displayMode});
7 +
8 + final Trade trade;
9 + final BalanceDisplayMode displayMode;
10 +
11 + String get tradeFormattedAmount {
12 + return trade.amount != null
13 + ? displayMode == BalanceDisplayMode.hiddenBalance
14 + ? '---'
15 + : trade.amountFormatted()
16 + : trade.amount;
17 + }
18 +
19 + @override
20 + DateTime get date => trade.createdAt;
21 +}
lib/view_model/dashboard/transaction_list_item.dart new
+54
@@ -0,0 +1,54 @@
1 +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
2 +import 'package:cake_wallet/src/domain/common/fiat_currency.dart';
3 +import 'package:cake_wallet/src/domain/common/transaction_info.dart';
4 +import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
5 +import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
6 +import 'package:cake_wallet/src/domain/monero/monero_transaction_info.dart';
7 +import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
8 +import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
9 +import 'package:cake_wallet/src/domain/common/calculate_fiat_amount_raw.dart';
10 +
11 +class TransactionListItem extends ActionListItem {
12 + TransactionListItem({
13 + this.transaction,
14 + this.price,
15 + this.fiatCurrency,
16 + this.displayMode
17 + });
18 +
19 + final TransactionInfo transaction;
20 + final double price;
21 + final FiatCurrency fiatCurrency;
22 + final BalanceDisplayMode displayMode;
23 +
24 + String get formattedCryptoAmount {
25 +
26 + return displayMode == BalanceDisplayMode.hiddenBalance
27 + ? '---'
28 + : transaction.amountFormatted();
29 + }
30 +
31 + String get formattedFiatAmount {
32 +
33 + if (transaction is MoneroTransactionInfo) {
34 + final amount = calculateFiatAmountRaw(
35 + cryptoAmount: moneroAmountToDouble(amount: transaction.amount),
36 + price: price);
37 + transaction.changeFiatAmount(amount);
38 + }
39 +
40 + if (transaction is BitcoinTransactionInfo) {
41 + final amount = calculateFiatAmountRaw(
42 + cryptoAmount: bitcoinAmountToDouble(amount: transaction.amount),
43 + price: price);
44 + transaction.changeFiatAmount(amount);
45 + }
46 +
47 + return displayMode == BalanceDisplayMode.hiddenBalance
48 + ? '---'
49 + : fiatCurrency.title + ' ' + transaction.fiatAmount();
50 + }
51 +
52 + @override
53 + DateTime get date => transaction.date;
54 +}
\ No newline at end of file
lib/view_model/dashboard/wallet_balance.dart new
+6
@@ -0,0 +1,6 @@
1 +class WalletBalance {
2 + WalletBalance({this.unlockedBalance, this.totalBalance});
3 +
4 + String unlockedBalance;
5 + String totalBalance;
6 +}
\ No newline at end of file
lib/view_model/dashboard_view_model.dart deleted
-194
@@ -1,194 +0,0 @@
1 -import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
2 -import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
3 -import 'package:cake_wallet/monero/monero_wallet.dart';
4 -import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
5 -import 'package:cake_wallet/src/domain/common/transaction_info.dart';
6 -import 'package:cake_wallet/src/stores/action_list/transaction_list_item.dart';
7 -import 'package:mobx/mobx.dart';
8 -import 'package:cake_wallet/core/wallet_base.dart';
9 -import 'package:cake_wallet/src/domain/common/sync_status.dart';
10 -import 'package:cake_wallet/src/domain/common/wallet_type.dart';
11 -import 'package:cake_wallet/store/app_store.dart';
12 -import 'package:cake_wallet/generated/i18n.dart';
13 -
14 -part 'dashboard_view_model.g.dart';
15 -
16 -class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
17 -
18 -class WalletBalace {
19 - WalletBalace({this.unlockedBalance, this.totalBalance});
20 -
21 - final String unlockedBalance;
22 - final String totalBalance;
23 -}
24 -
25 -abstract class DashboardViewModelBase with Store {
26 - DashboardViewModelBase({this.appStore}) {
27 - name = appStore.wallet?.name;
28 - wallet ??= appStore.wallet;
29 - type = wallet.type;
30 - transactions = ObservableList.of(wallet.transactionHistory.transactions
31 - .map((transaction) => TransactionListItem(transaction: transaction)));
32 - _reaction = reaction((_) => appStore.wallet, _onWalletChange);
33 -
34 - final _wallet = wallet;
35 -
36 - if (_wallet is MoneroWallet) {
37 - subname = _wallet.account?.label;
38 - }
39 -
40 - currentPage = 0;
41 - }
42 -
43 - @observable
44 - WalletType type;
45 -
46 - @observable
47 - String name;
48 -
49 - @observable
50 - double currentPage;
51 -
52 - @computed
53 - String get address => wallet.address;
54 -
55 - @computed
56 - SyncStatus get status => wallet.syncStatus;
57 -
58 - @computed
59 - String get syncStatusText {
60 - var statusText = '';
61 -
62 - if (status is SyncingSyncStatus) {
63 - statusText = S.current
64 - .Blocks_remaining(
65 - status.toString());
66 - }
67 -
68 - if (status is FailedSyncStatus) {
69 - statusText = S
70 - .current
71 - .please_try_to_connect_to_another_node;
72 - }
73 -
74 - return statusText;
75 - }
76 -
77 - @computed
78 - WalletBalace get balance {
79 - final wallet = this.wallet;
80 -
81 - if (wallet is MoneroWallet) {
82 - return WalletBalace(
83 - unlockedBalance: wallet.balance.formattedUnlockedBalance,
84 - totalBalance: wallet.balance.formattedFullBalance);
85 - }
86 -
87 - if (wallet is BitcoinWallet) {
88 - return WalletBalace(
89 - unlockedBalance: wallet.balance.confirmedFormatted,
90 - totalBalance: wallet.balance.unconfirmedFormatted);
91 - }
92 - }
93 -
94 - @observable
95 - ObservableList<Object> transactions;
96 -// ObservableList.of([
97 -// TransactionListItem(transaction: BitcoinTransactionInfo(
98 -// id: '',
99 -// height: 0,
100 -// amount: 0,
101 -// direction: TransactionDirection.incoming,
102 -// date: DateTime.now(),
103 -// isPending: false
104 -// )),
105 -// TransactionListItem(transaction: BitcoinTransactionInfo(
106 -// id: '',
107 -// height: 0,
108 -// amount: 0,
109 -// direction: TransactionDirection.incoming,
110 -// date: DateTime.now(),
111 -// isPending: false
112 -// )),
113 -// TransactionListItem(transaction: BitcoinTransactionInfo(
114 -// id: '',
115 -// height: 0,
116 -// amount: 0,
117 -// direction: TransactionDirection.incoming,
118 -// date: DateTime.now(),
119 -// isPending: false
120 -// )),
121 -// TransactionListItem(transaction: BitcoinTransactionInfo(
122 -// id: '',
123 -// height: 0,
124 -// amount: 0,
125 -// direction: TransactionDirection.incoming,
126 -// date: DateTime.now(),
127 -// isPending: false
128 -// )),
129 -// TransactionListItem(transaction: BitcoinTransactionInfo(
130 -// id: '',
131 -// height: 0,
132 -// amount: 0,
133 -// direction: TransactionDirection.incoming,
134 -// date: DateTime.now(),
135 -// isPending: false
136 -// )),
137 -// TransactionListItem(transaction: BitcoinTransactionInfo(
138 -// id: '',
139 -// height: 0,
140 -// amount: 0,
141 -// direction: TransactionDirection.incoming,
142 -// date: DateTime.now(),
143 -// isPending: false
144 -// )),
145 -// TransactionListItem(transaction: BitcoinTransactionInfo(
146 -// id: '',
147 -// height: 0,
148 -// amount: 0,
149 -// direction: TransactionDirection.incoming,
150 -// date: DateTime.now(),
151 -// isPending: false
152 -// )),
153 -// TransactionListItem(transaction: BitcoinTransactionInfo(
154 -// id: '',
155 -// height: 0,
156 -// amount: 0,
157 -// direction: TransactionDirection.incoming,
158 -// date: DateTime.now(),
159 -// isPending: false
160 -// )),
161 -// TransactionListItem(transaction: BitcoinTransactionInfo(
162 -// id: '',
163 -// height: 0,
164 -// amount: 0,
165 -// direction: TransactionDirection.incoming,
166 -// date: DateTime.now(),
167 -// isPending: false
168 -// )),
169 -// TransactionListItem(transaction: BitcoinTransactionInfo(
170 -// id: '',
171 -// height: 0,
172 -// amount: 0,
173 -// direction: TransactionDirection.incoming,
174 -// date: DateTime.now(),
175 -// isPending: false
176 -// )),
177 -// ]);
178 -
179 - @observable
180 - String subname;
181 -
182 - WalletBase wallet;
183 -
184 - AppStore appStore;
185 -
186 - ReactionDisposer _reaction;
187 -
188 - void _onWalletChange(WalletBase wallet) {
189 - name = wallet.name;
190 - transactions.clear();
191 - transactions.addAll(wallet.transactionHistory.transactions
192 - .map((transaction) => TransactionListItem(transaction: transaction)));
193 - }
194 -}