Merge pull request #88 from cake-tech/CAKE-15-new-dashboard-screen

Cake 15 new dashboard screen
This commit is contained in:
M 2020-07-30 13:22:11 +02:00
commit 2d48a4af90
48 changed files with 1439 additions and 1575 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/images/changenow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
assets/images/download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

BIN
assets/images/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

BIN
assets/images/morph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
assets/images/transfer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 B

After

Width:  |  Height:  |  Size: 212 B

BIN
assets/images/upload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

BIN
assets/images/xmrto.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -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: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_direction.dart';
import 'package:cake_wallet/src/domain/common/transaction_info.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 { class BitcoinTransactionInfo extends TransactionInfo {
BitcoinTransactionInfo( BitcoinTransactionInfo(
@ -62,11 +63,16 @@ class BitcoinTransactionInfo extends TransactionInfo {
final String id; final String id;
@override String _fiatAmount;
String amountFormatted() => bitcoinAmountToString(amount: amount);
@override @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<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final m = Map<String, dynamic>(); final m = Map<String, dynamic>();

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/core/contact_service.dart'; import 'package:cake_wallet/core/contact_service.dart';
import 'package:cake_wallet/src/domain/common/contact.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/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_list_page.dart';
import 'package:cake_wallet/src/screens/contact/contact_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'; 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/contact_list_store.dart';
import 'package:cake_wallet/store/node_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/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/auth_service.dart';
import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/monero/monero_wallet.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/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/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/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/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_edit_or_create_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_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/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart'; import 'package:cake_wallet/view_model/wallet_new_vm.dart';
import 'package:cake_wallet/store/authentication_store.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; final getIt = GetIt.instance;
@ -77,7 +82,9 @@ NodeListStore setupNodeListStore(Box<Node> nodeSource) {
Future setup( Future setup(
{Box<WalletInfo> walletInfoSource, {Box<WalletInfo> walletInfoSource,
Box<Node> nodeSource, Box<Node> nodeSource,
Box<Contact> contactSource}) async { Box<Contact> contactSource,
Box<Trade> tradesSource,
PriceStore priceStore}) async {
getIt.registerSingletonAsync<SharedPreferences>( getIt.registerSingletonAsync<SharedPreferences>(
() => SharedPreferences.getInstance()); () => SharedPreferences.getInstance());
@ -97,6 +104,13 @@ Future setup(
nodeListStore: getIt.get<NodeListStore>())); nodeListStore: getIt.get<NodeListStore>()));
getIt.registerSingleton<ContactService>( getIt.registerSingleton<ContactService>(
ContactService(contactSource, getIt.get<AppStore>().contactListStore)); ContactService(contactSource, getIt.get<AppStore>().contactListStore));
getIt.registerSingleton<TradesStore>(TradesStore(
tradesSource: tradesSource,
settingsStore: getIt.get<SettingsStore>()));
getIt.registerSingleton<TradeFilterStore>(
TradeFilterStore(wallet: getIt.get<AppStore>().wallet));
getIt.registerSingleton<TransactionFilterStore>(TransactionFilterStore());
getIt.registerFactory<KeyService>( getIt.registerFactory<KeyService>(
() => KeyService(getIt.get<FlutterSecureStorage>())); () => KeyService(getIt.get<FlutterSecureStorage>()));
@ -128,7 +142,19 @@ Future setup(
() => WalletAddressListViewModel(wallet: getIt.get<AppStore>().wallet)); () => WalletAddressListViewModel(wallet: getIt.get<AppStore>().wallet));
getIt.registerFactory( getIt.registerFactory(
() => DashboardViewModel(appStore: getIt.get<AppStore>())); () => BalanceViewModel(
wallet: getIt.get<AppStore>().wallet,
settingsStore: getIt.get<SettingsStore>(),
priceStore: priceStore));
getIt.registerFactory(
() => DashboardViewModel(
balanceViewModel: getIt.get<BalanceViewModel>(),
appStore: getIt.get<AppStore>(),
tradesStore: getIt.get<TradesStore>(),
tradeFilterStore: getIt.get<TradeFilterStore>(),
transactionFilterStore: getIt.get<TransactionFilterStore>()
));
getIt.registerFactory<AuthService>(() => AuthService( getIt.registerFactory<AuthService>(() => AuthService(
secureStorage: getIt.get<FlutterSecureStorage>(), secureStorage: getIt.get<FlutterSecureStorage>(),

View file

@ -24,7 +24,6 @@ class S implements WidgetsLocalizations {
String get account => "Account"; String get account => "Account";
String get accounts => "Accounts"; String get accounts => "Accounts";
String get accounts_subaddresses => "Accounts and subaddresses"; String get accounts_subaddresses => "Accounts and subaddresses";
String get addresses => "Addresses";
String get add => "Add"; String get add => "Add";
String get add_new_node => "Add new node"; String get add_new_node => "Add new node";
String get add_new_word => "Add new word"; String get add_new_word => "Add new word";
@ -32,6 +31,7 @@ class S implements WidgetsLocalizations {
String get address_book_menu => "Address book"; String get address_book_menu => "Address book";
String get address_remove_contact => "Remove contact"; String get address_remove_contact => "Remove contact";
String get address_remove_content => "Are you sure that you want to remove selected contact?"; String get address_remove_content => "Are you sure that you want to remove selected contact?";
String get addresses => "Addresses";
String get all => "ALL"; String get all => "ALL";
String get amount => "Amount: "; String get amount => "Amount: ";
String get amount_is_estimate => "The receive amount is an estimate"; String get amount_is_estimate => "The receive amount is an estimate";
@ -643,8 +643,6 @@ class $de extends S {
@override @override
String get accounts_subaddresses => "Konten und Unteradressen"; String get accounts_subaddresses => "Konten und Unteradressen";
@override @override
String get addresses => "Addressen";
@override
String get wallet_name => "Walletname"; String get wallet_name => "Walletname";
@override @override
String get error_text_payment_id => "Die Zahlungs-ID kann nur 16 bis 64 hexadezimale Zeichen enthalten"; String get error_text_payment_id => "Die Zahlungs-ID kann nur 16 bis 64 hexadezimale Zeichen enthalten";
@ -1265,8 +1263,6 @@ class $hi extends S {
@override @override
String get accounts_subaddresses => "लेखा और उपदेस"; String get accounts_subaddresses => "लेखा और उपदेस";
@override @override
String get addresses => "पतों";
@override
String get wallet_name => "बटुए का नाम"; String get wallet_name => "बटुए का नाम";
@override @override
String get error_text_payment_id => "पेमेंट आईडी केवल हेक्स में 16 से 64 चार्ट तक हो सकती है"; String get error_text_payment_id => "पेमेंट आईडी केवल हेक्स में 16 से 64 चार्ट तक हो सकती है";
@ -1887,8 +1883,6 @@ class $ru extends S {
@override @override
String get accounts_subaddresses => "Аккаунты и субадреса"; String get accounts_subaddresses => "Аккаунты и субадреса";
@override @override
String get addresses => "Адреса";
@override
String get wallet_name => "Имя кошелька"; String get wallet_name => "Имя кошелька";
@override @override
String get error_text_payment_id => "Идентификатор платежа может содержать от 16 до 64 символов в hex"; String get error_text_payment_id => "Идентификатор платежа может содержать от 16 до 64 символов в hex";
@ -2509,8 +2503,6 @@ class $ko extends S {
@override @override
String get accounts_subaddresses => "계정 및 하위 주소"; String get accounts_subaddresses => "계정 및 하위 주소";
@override @override
String get addresses => "구애";
@override
String get wallet_name => "지갑 이름"; String get wallet_name => "지갑 이름";
@override @override
String get error_text_payment_id => "지불 ID는 16 ~ 64 자의 16 진 문자 만 포함 할 수 있습니다"; String get error_text_payment_id => "지불 ID는 16 ~ 64 자의 16 진 문자 만 포함 할 수 있습니다";
@ -3131,8 +3123,6 @@ class $pt extends S {
@override @override
String get accounts_subaddresses => "Contas e sub-endereços"; String get accounts_subaddresses => "Contas e sub-endereços";
@override @override
String get addresses => "Endereços";
@override
String get wallet_name => "Nome da carteira"; String get wallet_name => "Nome da carteira";
@override @override
String get error_text_payment_id => "O ID de pagamento pode conter apenas de 16 a 64 caracteres em hexadecimal"; String get error_text_payment_id => "O ID de pagamento pode conter apenas de 16 a 64 caracteres em hexadecimal";
@ -3753,8 +3743,6 @@ class $uk extends S {
@override @override
String get accounts_subaddresses => "Акаунти та субадреси"; String get accounts_subaddresses => "Акаунти та субадреси";
@override @override
String get addresses => "Адреси";
@override
String get wallet_name => "Ім'я гаманця"; String get wallet_name => "Ім'я гаманця";
@override @override
String get error_text_payment_id => "Ідентифікатор платежу може містити від 16 до 64 символів в hex"; String get error_text_payment_id => "Ідентифікатор платежу може містити від 16 до 64 символів в hex";
@ -4375,8 +4363,6 @@ class $ja extends S {
@override @override
String get accounts_subaddresses => "アカウントとサブアドレス"; String get accounts_subaddresses => "アカウントとサブアドレス";
@override @override
String get addresses => "アドレス";
@override
String get wallet_name => "ウォレット名"; String get wallet_name => "ウォレット名";
@override @override
String get error_text_payment_id => "支払いIDには、16進数で16〜64文字しか含めることができません"; String get error_text_payment_id => "支払いIDには、16進数で16〜64文字しか含めることができません";
@ -5001,8 +4987,6 @@ class $pl extends S {
@override @override
String get accounts_subaddresses => "Konta i podadresy"; String get accounts_subaddresses => "Konta i podadresy";
@override @override
String get addresses => "Adresy";
@override
String get wallet_name => "Nazwa portfela"; String get wallet_name => "Nazwa portfela";
@override @override
String get error_text_payment_id => "ID może zawierać od 16 do 64 znaków w formacie szesnastkowym"; String get error_text_payment_id => "ID może zawierać od 16 do 64 znaków w formacie szesnastkowym";
@ -5623,8 +5607,6 @@ class $es extends S {
@override @override
String get accounts_subaddresses => "Cuentas y subdirecciones"; String get accounts_subaddresses => "Cuentas y subdirecciones";
@override @override
String get addresses => "Direcciones";
@override
String get wallet_name => "Nombre de la billetera"; String get wallet_name => "Nombre de la billetera";
@override @override
String get error_text_payment_id => "La ID de pago solo puede contener de 16 a 64 caracteres en hexadecimal"; String get error_text_payment_id => "La ID de pago solo puede contener de 16 a 64 caracteres en hexadecimal";
@ -6245,8 +6227,6 @@ class $nl extends S {
@override @override
String get accounts_subaddresses => "Accounts en subadressen"; String get accounts_subaddresses => "Accounts en subadressen";
@override @override
String get addresses => "Adressen";
@override
String get wallet_name => "Portemonnee naam"; String get wallet_name => "Portemonnee naam";
@override @override
String get error_text_payment_id => "Betalings-ID kan alleen 16 tot 64 tekens bevatten in hexadecimale volgorde"; String get error_text_payment_id => "Betalings-ID kan alleen 16 tot 64 tekens bevatten in hexadecimale volgorde";
@ -6867,8 +6847,6 @@ class $zh extends S {
@override @override
String get accounts_subaddresses => "帳戶和子地址"; String get accounts_subaddresses => "帳戶和子地址";
@override @override
String get addresses => "地址";
@override
String get wallet_name => "钱包名称"; String get wallet_name => "钱包名称";
@override @override
String get error_text_payment_id => "付款ID只能包含16到64个字符十六进制"; String get error_text_payment_id => "付款ID只能包含16到64个字符十六进制";

View file

@ -85,13 +85,6 @@ void main() async {
final exchangeTemplates = final exchangeTemplates =
await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName); await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
await initialSetup(
sharedPreferences: await SharedPreferences.getInstance(),
nodes: nodes,
walletInfoSource: walletInfoSource,
contactSource: contacts,
initialMigrationVersion: 3);
final sharedPreferences = await SharedPreferences.getInstance(); final sharedPreferences = await SharedPreferences.getInstance();
final walletService = WalletService(); final walletService = WalletService();
final walletListService = WalletListService( final walletListService = WalletListService(
@ -125,6 +118,15 @@ void main() async {
final walletCreationService = WalletCreationService(); final walletCreationService = WalletCreationService();
final authService = AuthService(); final authService = AuthService();
await initialSetup(
sharedPreferences: await SharedPreferences.getInstance(),
nodes: nodes,
walletInfoSource: walletInfoSource,
contactSource: contacts,
tradesSource: trades,
priceStore: priceStore,
initialMigrationVersion: 3);
setReactions( setReactions(
settingsStore: settingsStore, settingsStore: settingsStore,
priceStore: priceStore, priceStore: priceStore,
@ -163,6 +165,8 @@ Future<void> initialSetup(
@required Box<Node> nodes, @required Box<Node> nodes,
@required Box<WalletInfo> walletInfoSource, @required Box<WalletInfo> walletInfoSource,
@required Box<Contact> contactSource, @required Box<Contact> contactSource,
@required Box<Trade> tradesSource,
@required PriceStore priceStore,
int initialMigrationVersion = 3}) async { int initialMigrationVersion = 3}) async {
await defaultSettingsMigration( await defaultSettingsMigration(
version: initialMigrationVersion, version: initialMigrationVersion,
@ -171,7 +175,9 @@ Future<void> initialSetup(
await setup( await setup(
walletInfoSource: walletInfoSource, walletInfoSource: walletInfoSource,
nodeSource: nodes, nodeSource: nodes,
contactSource: contactSource); contactSource: contactSource,
tradesSource: tradesSource,
priceStore: priceStore);
await bootstrap(); await bootstrap();
monero_wallet.onStartup(); monero_wallet.onStartup();
} }

View file

@ -20,7 +20,6 @@ class Palette {
class PaletteDark { class PaletteDark {
static const Color distantBlue = Color.fromRGBO(70, 85, 133, 1.0); // mainBackgroundColor static const Color distantBlue = Color.fromRGBO(70, 85, 133, 1.0); // mainBackgroundColor
static const Color lightDistantBlue = Color.fromRGBO(81, 96, 147, 1.0); // borderCardColor static const Color lightDistantBlue = Color.fromRGBO(81, 96, 147, 1.0); // borderCardColor
static const Color nightBlue = Color.fromRGBO(45, 56, 95, 1.0); // walletCardBottomEndSync
static const Color gray = Color.fromRGBO(140, 153, 201, 1.0); // walletCardText static const Color gray = Color.fromRGBO(140, 153, 201, 1.0); // walletCardText
static const Color violetBlue = Color.fromRGBO(51, 63, 104, 1.0); // walletCardAddressField static const Color violetBlue = Color.fromRGBO(51, 63, 104, 1.0); // walletCardAddressField
static const Color moderateBlue = Color.fromRGBO(63, 77, 122, 1.0); // walletCardSubAddressField static const Color moderateBlue = Color.fromRGBO(63, 77, 122, 1.0); // walletCardSubAddressField
@ -28,8 +27,21 @@ class PaletteDark {
static const Color pigeonBlue = Color.fromRGBO(91, 112, 146, 1.0); // historyPanelText static const Color pigeonBlue = Color.fromRGBO(91, 112, 146, 1.0); // historyPanelText
static const Color moderateNightBlue = Color.fromRGBO(39, 53, 96, 1.0); // historyPanelButton static const Color moderateNightBlue = Color.fromRGBO(39, 53, 96, 1.0); // historyPanelButton
static const Color headerNightBlue = Color.fromRGBO(41, 52, 84, 1.0); // menuHeader static const Color headerNightBlue = Color.fromRGBO(41, 52, 84, 1.0); // menuHeader
static const Color lightNightBlue = Color.fromRGBO(48, 59, 95, 1.0); // menuList //static const Color lightNightBlue = Color.fromRGBO(48, 59, 95, 1.0); // menuList
static const Color moderatePurpleBlue = Color.fromRGBO(57, 74, 95, 1.0); // selectButtonText static const Color moderatePurpleBlue = Color.fromRGBO(57, 74, 95, 1.0); // selectButtonText
// NEW DESIGN
static const Color backgroundColor = Color.fromRGBO(25, 35, 60, 1.0);
static const Color nightBlue = Color.fromRGBO(35, 47, 79, 1.0);
static const Color wildNightBlue = Color.fromRGBO(39, 53, 96, 1.0);
static const Color cyanBlue = Color.fromRGBO(99, 113, 150, 1.0);
static const Color darkCyanBlue = Color.fromRGBO(91, 112, 146, 1.0);
static const Color orangeYellow = Color.fromRGBO(243, 166, 50, 1.0);
static const Color brightGreen = Color.fromRGBO(88, 243, 50, 1.0);
static const Color oceanBlue = Color.fromRGBO(27, 39, 71, 1.0);
static const Color lightNightBlue = Color.fromRGBO(39, 52, 89, 1.0);
static const Color wildBlue = Color.fromRGBO(165, 176, 205, 1.0);
// FIXME: Rename. // FIXME: Rename.
static const Color eee = Color.fromRGBO(236, 239, 245, 1.0); static const Color eee = Color.fromRGBO(236, 239, 245, 1.0);
static const Color xxx = Color.fromRGBO(72, 89, 109, 1); static const Color xxx = Color.fromRGBO(72, 89, 109, 1);

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart'; import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart'; import 'package:cake_wallet/view_model/wallet_new_vm.dart';
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart'; import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
@ -249,13 +250,7 @@ class Router {
case Routes.dashboard: case Routes.dashboard:
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
builder: (_) => createDashboardPage( builder: (_) => getIt.get<DashboardPage>());
walletService: walletService,
priceStore: priceStore,
settingsStore: settingsStore,
trades: trades,
transactionDescriptions: transactionDescriptions,
walletStore: walletStore));
case Routes.send: case Routes.send:
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(

View file

@ -8,4 +8,5 @@ abstract class TransactionInfo extends Object {
int height; int height;
String amountFormatted(); String amountFormatted();
String fiatAmount(); String fiatAmount();
void changeFiatAmount(String amount);
} }

View file

@ -2,149 +2,164 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.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/base_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/wallet_card.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/trade_history_panel.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.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';
class DashboardPage extends BasePage { class DashboardPage extends BasePage {
DashboardPage({@required this.walletViewModel}); DashboardPage({@required this.walletViewModel});
@override @override
Color get backgroundLightColor => Colors.transparent; Color get backgroundLightColor => PaletteDark.backgroundColor;
@override @override
Color get backgroundDarkColor => Colors.transparent; Color get backgroundDarkColor => PaletteDark.backgroundColor;
@override @override
Widget Function(BuildContext, Widget) get rootWrapper => Widget middle(BuildContext context) {
(BuildContext context, Widget scaffold) => Container( return SyncIndicator(dashboardViewModel: walletViewModel);
decoration: BoxDecoration( }
gradient: LinearGradient(colors: [
Theme.of(context).scaffoldBackgroundColor,
Theme.of(context).primaryColor
], begin: Alignment.topLeft, end: Alignment.bottomRight)),
child: scaffold);
@override @override
Widget trailing(BuildContext context) { Widget trailing(BuildContext context) {
final menuButton = Image.asset('assets/images/header.png', final menuButton = Image.asset('assets/images/menu.png',
color: Theme.of(context).primaryTextTheme.title.color); color: Colors.white);
return Container( return Container(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: SizedBox( width: 40,
width: 24, child: FlatButton(
child: FlatButton( highlightColor: Colors.transparent,
highlightColor: Colors.transparent, splashColor: Colors.transparent,
splashColor: Colors.transparent, padding: EdgeInsets.all(0),
padding: EdgeInsets.all(0), onPressed: () async {
onPressed: () async { await showDialog<void>(
await showDialog<void>( builder: (_) => MenuWidget(
builder: (_) => MenuWidget( name: walletViewModel.name,
name: walletViewModel.name, subname: walletViewModel.subname,
subname: walletViewModel.subname, type: walletViewModel.type),
type: walletViewModel.type), context: context);
context: context); },
}, child: menuButton
child: menuButton), )
),
); );
} }
final DashboardViewModel walletViewModel; final DashboardViewModel walletViewModel;
final sendImage = Image.asset('assets/images/send.png'); final sendImage = Image.asset('assets/images/upload.png',
final exchangeImage = Image.asset('assets/images/exchange.png'); height: 22.24, width: 24, color: Colors.white);
final buyImage = Image.asset('assets/images/coins.png'); final exchangeImage = Image.asset('assets/images/transfer.png',
height: 24.27, width: 22.25, color: Colors.white);
final receiveImage = Image.asset('assets/images/download.png',
height: 22.24, width: 24, color: Colors.white);
final controller = PageController(initialPage: 0);
var pages = <Widget>[];
bool _isEffectsInstalled = false;
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final transactionListMinHeight =
constraints.heightConstraints().maxHeight - 345 - 32;
return SingleChildScrollView( _setEffects();
child: Column(children: [
Container( return SafeArea(
height: 345, child: Column(
child: Column(children: [ mainAxisSize: MainAxisSize.max,
Padding( children: <Widget>[
padding: EdgeInsets.only(left: 24, top: 10), Expanded(
child: WalletCard(walletVM: walletViewModel)), child: PageView.builder(
Container( controller: controller,
padding: EdgeInsets.only(left: 44, right: 44, top: 32), itemCount: pages.length,
child: Row( itemBuilder: (context, index) {
children: <Widget>[ return pages[index];
Flexible( }
child: actionButton( )
context: context, ),
image: sendImage, Padding(
title: S.of(context).send, padding: EdgeInsets.only(
route: Routes.send)), bottom: 24
Flexible( ),
child: actionButton( child: Observer(
context: context, builder: (_) {
image: exchangeImage, return DotsIndicator(
title: S.of(context).exchange, dotsCount: pages.length,
route: Routes.exchange)), position: walletViewModel.currentPage,
], decorator: DotsDecorator(
color: PaletteDark.cyanBlue,
activeColor: Colors.white,
size: Size(6, 6),
activeSize: Size(6, 6),
),
);
}
),
),
Container(
width: double.infinity,
padding: EdgeInsets.only(
left: 45,
right: 45,
bottom: 24
),
child: Row(
children: <Widget>[
Flexible(
child: ActionButton(
image: sendImage,
title: S.of(context).send,
route: Routes.send,
alignment: Alignment.centerLeft,
),
), ),
) Flexible(
])), child: ActionButton(
SizedBox(height: 32), image: exchangeImage,
ConstrainedBox( title: S.of(context).exchange,
constraints: BoxConstraints(minHeight: transactionListMinHeight), route: Routes.exchange
child: TradeHistoryPanel(dashboardViewModel: walletViewModel)), ),
// Column(children: [ ),
// Text('1'), Flexible(
// Text('2') child: ActionButton(
// ]) image: receiveImage,
])); title: S.of(context).receive,
route: Routes.receive,
alignment: Alignment.centerRight,
),
)
],
),
)
],
)
);
}
void _setEffects() {
if (_isEffectsInstalled) {
return;
}
pages.add(BalancePage(dashboardViewModel: walletViewModel));
pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
controller.addListener(() {
walletViewModel.currentPage = controller.page;
}); });
reaction((_) => walletViewModel.currentPage, (double currentPage) {
if (controller.page != currentPage) {
controller.jumpTo(currentPage);
}
});
_isEffectsInstalled = true;
} }
} }
Widget actionButton(
{BuildContext context,
@required Image image,
@required String title,
@required String route}) {
return Container(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
if (route.isNotEmpty) {
Navigator.of(context, rootNavigator: true).pushNamed(route);
}
},
child: Container(
height: 48,
width: 48,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).primaryTextTheme.subhead.color,
shape: BoxShape.circle),
child: image,
),
),
Padding(
padding: EdgeInsets.only(top: 12),
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color.fromRGBO(140, 153, 201,
0.8) // Theme.of(context).primaryTextTheme.caption.color
),
),
)
],
),
);
}

View file

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
class ActionButton extends StatelessWidget{
ActionButton({
@required this.image,
@required this.title,
@required this.route,
this.alignment = Alignment.center
});
final Image image;
final String title;
final String route;
final Alignment alignment;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 93,
alignment: alignment,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
if (route.isNotEmpty) {
Navigator.of(context, rootNavigator: true).pushNamed(route);
}
},
child: Container(
height: 60,
width: 60,
alignment: Alignment.center,
decoration: BoxDecoration(
color: PaletteDark.nightBlue,
shape: BoxShape.circle),
child: image,
),
),
Text(
title,
style: TextStyle(
fontSize: 14,
color: Colors.white
),
)
],
),
);
}
}

View file

@ -0,0 +1,68 @@
import 'package:flutter/material.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';
class BalancePage extends StatelessWidget {
BalancePage({@required this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(24),
child: Center(
child: Container(
height: 160,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Observer(
builder: (_) {
return Text(
dashboardViewModel.wallet.currency.toString(),
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
color: PaletteDark.cyanBlue,
height: 1
),
);
}
),
Observer(
builder: (_) {
return Text(
dashboardViewModel.balanceViewModel.cryptoBalance,
style: TextStyle(
fontSize: 54,
fontWeight: FontWeight.bold,
color: Colors.white,
height: 1
),
);
}
),
Observer(
builder: (_) {
return Text(
dashboardViewModel.balanceViewModel.fiatBalance,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: PaletteDark.cyanBlue,
height: 1
),
);
}
),
],
),
),
),
);
}
}

View file

@ -1,255 +0,0 @@
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/routes.dart';
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
import 'package:cake_wallet/themes.dart';
import 'package:cake_wallet/theme_changer.dart';
class ButtonHeader extends SliverPersistentHeaderDelegate {
final sendImage = Image.asset('assets/images/send.png');
final exchangeImage = Image.asset('assets/images/exchange.png');
final buyImage = Image.asset('assets/images/coins.png');
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
final _themeChanger = Provider.of<ThemeChanger>(context);
Image filterButton;
if (_themeChanger.getTheme() == Themes.darkTheme) {
filterButton = Image.asset('assets/images/filter_button.png');
} else {
filterButton = Image.asset('assets/images/filter_light_button.png');
}
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24), topRight: Radius.circular(24)),
child: Container(
color: Colors.red,
// height: 75,
padding: EdgeInsets.only(top: 26, left: 20, right: 20, bottom: 10),
// color: Theme.of(context).backgroundColor,
child: Stack(
children: <Widget>[
Center(
child: Text(
S.of(context).transactions,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color),
)),
Positioned(
right: 0,
height: 36,
child: PopupMenuButton<int>(
itemBuilder: (context) => [
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).transactions,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
// PopupMenuItem(
// value: 0,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).incoming),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayIncoming,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleIncoming(),
// )
// ]))),
// PopupMenuItem(
// value: 1,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).outgoing),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayOutgoing,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleOutgoing(),
// )
// ]))),
PopupMenuItem(
value: 2,
child: Text(S.of(context).transactions_by_date)),
PopupMenuDivider(),
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).trades,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
PopupMenuItem(
value: 3,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('XMR.TO'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayXMRTO,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .xmrto),
// )
]))),
PopupMenuItem(
value: 4,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('Change.NOW'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayChangeNow,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .changeNow),
// )
]))),
PopupMenuItem(
value: 5,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('MorphToken'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayMorphToken,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .morphToken),
// )
])))
],
child: filterButton,
onSelected: (item) async {
if (item == 2) {
final List<DateTime> picked =
await date_rage_picker.showDatePicker(
context: context,
initialFirstDate:
DateTime.now().subtract(Duration(days: 1)),
initialLastDate: (DateTime.now()),
firstDate: DateTime(2015),
lastDate: DateTime.now().add(Duration(days: 1)));
if (picked != null && picked.length == 2) {
// actionListStore.transactionFilterStore
// .changeStartDate(picked.first);
// actionListStore.transactionFilterStore
// .changeEndDate(picked.last);
}
}
},
)),
],
),
),
);
}
@override
double get maxExtent => 164;
@override
double get minExtent => 66;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
Widget actionButton(
{BuildContext context,
@required Image image,
@required String title,
@required String route}) {
return Container(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
if (route.isNotEmpty) {
Navigator.of(context, rootNavigator: true).pushNamed(route);
}
},
child: Container(
height: 48,
width: 48,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).primaryTextTheme.subhead.color,
shape: BoxShape.circle),
child: image,
),
),
Padding(
padding: EdgeInsets.only(top: 12),
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color.fromRGBO(140, 153, 201,
0.8) // Theme.of(context).primaryTextTheme.caption.color
),
),
)
],
),
);
}
}

View file

@ -3,6 +3,7 @@ import 'package:intl/intl.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart'; import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/palette.dart';
class DateSectionRaw extends StatelessWidget { class DateSectionRaw extends StatelessWidget {
DateSectionRaw({this.date}); DateSectionRaw({this.date});
@ -35,21 +36,14 @@ class DateSectionRaw extends StatelessWidget {
} }
return Container( return Container(
height: 36, height: 35,
padding: EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( color: Colors.transparent,
color: Theme.of(context).backgroundColor,
border: Border.all(
width: 1,
color: Theme.of(context).backgroundColor
),
),
child: Text(title, child: Text(title,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Theme.of(context).primaryTextTheme.headline.color color: PaletteDark.darkCyanBlue
)) ))
); );
} }
} }

View file

@ -0,0 +1,187 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
import 'package:flutter_mobx/flutter_mobx.dart';
class HeaderRow extends StatelessWidget {
HeaderRow({this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
final filterIcon = Image.asset('assets/images/filter_icon.png',
color: PaletteDark.wildBlue);
@override
Widget build(BuildContext context) {
return Container(
height: 52,
color: Colors.transparent,
padding: EdgeInsets.only(left: 24, right: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
S.of(context).transactions,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Colors.white
),
),
PopupMenuButton<int>(
itemBuilder: (context) => [
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).transactions,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryTextTheme.caption.color))),
PopupMenuItem(
value: 0,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(S.of(context).incoming),
Checkbox(
value: dashboardViewModel
.transactionFilterStore
.displayIncoming,
onChanged: (value) => dashboardViewModel
.transactionFilterStore
.toggleIncoming()
)
]))),
PopupMenuItem(
value: 1,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(S.of(context).outgoing),
Checkbox(
value: dashboardViewModel
.transactionFilterStore
.displayOutgoing,
onChanged: (value) => dashboardViewModel
.transactionFilterStore
.toggleOutgoing(),
)
]))),
PopupMenuItem(
value: 2,
child:
Text(S.of(context).transactions_by_date)),
PopupMenuDivider(),
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).trades,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryTextTheme.caption.color))),
PopupMenuItem(
value: 3,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text('XMR.TO'),
Checkbox(
value: dashboardViewModel
.tradeFilterStore
.displayXMRTO,
onChanged: (value) => dashboardViewModel
.tradeFilterStore
.toggleDisplayExchange(
ExchangeProviderDescription
.xmrto),
)
]))),
PopupMenuItem(
value: 4,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text('Change.NOW'),
Checkbox(
value: dashboardViewModel
.tradeFilterStore
.displayChangeNow,
onChanged: (value) => dashboardViewModel
.tradeFilterStore
.toggleDisplayExchange(
ExchangeProviderDescription
.changeNow),
)
]))),
PopupMenuItem(
value: 5,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text('MorphToken'),
Checkbox(
value: dashboardViewModel
.tradeFilterStore
.displayMorphToken,
onChanged: (value) => dashboardViewModel
.tradeFilterStore
.toggleDisplayExchange(
ExchangeProviderDescription
.morphToken),
)
])))
],
child: Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: PaletteDark.oceanBlue
),
child: filterIcon,
),
onSelected: (item) async {
if (item == 2) {
final picked =
await date_rage_picker.showDatePicker(
context: context,
initialFirstDate: DateTime.now()
.subtract(Duration(days: 1)),
initialLastDate: (DateTime.now()),
firstDate: DateTime(2015),
lastDate: DateTime.now()
.add(Duration(days: 1)));
if (picked != null && picked.length == 2) {
dashboardViewModel.transactionFilterStore
.changeStartDate(picked.first);
dashboardViewModel.transactionFilterStore
.changeEndDate(picked.last);
}
}
},
),
],
),
);
}
}

View file

@ -0,0 +1,87 @@
import 'package:flutter/material.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';
class SyncIndicator extends StatelessWidget {
SyncIndicator({@required this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
@override
Widget build(BuildContext context) {
return Observer(
builder: (_) {
final syncIndicatorWidth = 250.0;
final status = dashboardViewModel.status;
final statusText = status.title();
final progress = status.progress();
final indicatorOffset = progress * syncIndicatorWidth;
final indicatorWidth =
progress <= 1 ? syncIndicatorWidth - indicatorOffset : 0.0;
final indicatorColor = status is SyncedSyncStatus
? PaletteDark.brightGreen
: PaletteDark.orangeYellow;
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: Container(
height: 30,
width: syncIndicatorWidth,
color: PaletteDark.lightNightBlue,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
progress <= 1
? Positioned(
left: indicatorOffset,
top: 0,
bottom: 0,
child: Container(
width: indicatorWidth,
height: 30,
color: PaletteDark.oceanBlue,
)
)
: Offstage(),
Padding(
padding: EdgeInsets.only(
left: 24,
right: 24
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: 4,
width: 4,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: indicatorColor
),
),
Padding(
padding: EdgeInsets.only(left: 6),
child: Text(
statusText,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: PaletteDark.wildBlue
),
),
)
],
),
)
],
),
),
);
}
);
}
}

View file

@ -1,322 +0,0 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/theme_changer.dart';
import 'package:cake_wallet/themes.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/view_model/dashboard_view_model.dart';
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
import 'package:cake_wallet/src/stores/action_list/action_list_store.dart';
import 'package:cake_wallet/src/stores/action_list/date_section_item.dart';
import 'package:cake_wallet/src/stores/action_list/trade_list_item.dart';
import 'package:cake_wallet/src/stores/action_list/transaction_list_item.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'date_section_raw.dart';
import 'trade_row.dart';
import 'transaction_raw.dart';
import 'button_header.dart';
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
class TradeHistoryPanel extends StatefulWidget {
TradeHistoryPanel({this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
@override
TradeHistoryPanelState createState() => TradeHistoryPanelState();
}
class TradeHistoryPanelState extends State<TradeHistoryPanel> {
final _listObserverKey = GlobalKey();
final _listKey = GlobalKey();
double panelHeight;
double screenHeight;
@override
void initState() {
panelHeight = 0;
screenHeight = 0;
super.initState();
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
}
void afterLayout(dynamic _) {
screenHeight = MediaQuery.of(context).size.height;
setState(() {
panelHeight = screenHeight;
});
}
@override
Widget build(BuildContext context) {
// AnimatedContainer(
// width: MediaQuery.of(context).size.width,
// height: panelHeight,
// duration: Duration(milliseconds: 1000),
// curve: Curves.fastOutSlowIn,
// child: )
final transactionDateFormat = DateFormat('HH:mm');
final _themeChanger = Provider.of<ThemeChanger>(context);
final filterButton = Image.asset(
_themeChanger.getTheme() == Themes.darkTheme
? 'assets/images/filter_button.png'
: 'assets/images/filter_light_button.png',
height: 36);
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
child: Container(
color: Colors.white,
child: Column(children: [
Container(
padding:
EdgeInsets.only(top: 32, left: 20, right: 20, bottom: 20),
color: Theme.of(context).backgroundColor,
child: Stack(
children: <Widget>[
SizedBox(height: 37), // Force stack height
Center(
child: Text(S.of(context).transactions,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color))),
Positioned(
right: 0,
child: PopupMenuButton<int>(
itemBuilder: (context) => [
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).transactions,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
// PopupMenuItem(
// value: 0,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).incoming),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayIncoming,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleIncoming(),
// )
// ]))),
// PopupMenuItem(
// value: 1,
// child: Observer(
// builder: (_) => Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Text(S.of(context).outgoing),
// Checkbox(
// value: actionListStore
// .transactionFilterStore
// .displayOutgoing,
// onChanged: (value) =>
// actionListStore
// .transactionFilterStore
// .toggleOutgoing(),
// )
// ]))),
PopupMenuItem(
value: 2,
child:
Text(S.of(context).transactions_by_date)),
PopupMenuDivider(),
PopupMenuItem(
enabled: false,
value: -1,
child: Text(S.of(context).trades,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.caption
.color))),
PopupMenuItem(
value: 3,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('XMR.TO'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayXMRTO,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .xmrto),
// )
]))),
PopupMenuItem(
value: 4,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('Change.NOW'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayChangeNow,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .changeNow),
// )
]))),
PopupMenuItem(
value: 5,
child: Observer(
builder: (_) => Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('MorphToken'),
// Checkbox(
// value: actionListStore
// .tradeFilterStore
// .displayMorphToken,
// onChanged: (value) =>
// actionListStore
// .tradeFilterStore
// .toggleDisplayExchange(
// ExchangeProviderDescription
// .morphToken),
// )
])))
],
child: filterButton,
onSelected: (item) async {
if (item == 2) {
final picked =
await date_rage_picker.showDatePicker(
context: context,
initialFirstDate: DateTime.now()
.subtract(Duration(days: 1)),
initialLastDate: (DateTime.now()),
firstDate: DateTime(2015),
lastDate: DateTime.now()
.add(Duration(days: 1)));
if (picked != null && picked.length == 2) {
// actionListStore.transactionFilterStore
// .changeStartDate(picked.first);
// actionListStore.transactionFilterStore
// .changeEndDate(picked.last);
}
}
},
)),
],
),
),
widget.dashboardViewModel.transactions?.isNotEmpty ?? false
? ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.dashboardViewModel.transactions.length,
itemBuilder: (_, index) {
final item =
widget.dashboardViewModel.transactions[index];
if (item is DateSectionItem) {
return DateSectionRaw(date: item.date);
}
if (item is TransactionListItem) {
final transaction = item.transaction;
final savedDisplayMode = BalanceDisplayMode.all;
//settingsStore
// .balanceDisplayMode;
final formattedAmount = savedDisplayMode ==
BalanceDisplayMode.hiddenBalance
? '---'
: transaction.amountFormatted();
final formattedFiatAmount = savedDisplayMode ==
BalanceDisplayMode.hiddenBalance
? '---'
: transaction.fiatAmount(); // symbol ???
return TransactionRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.transactionDetails,
arguments: transaction),
direction: transaction.direction,
formattedDate: transactionDateFormat
.format(transaction.date),
formattedAmount: formattedAmount,
formattedFiatAmount: formattedFiatAmount,
isPending: transaction.isPending);
}
if (item is TradeListItem) {
final trade = item.trade;
final savedDisplayMode = BalanceDisplayMode.all;
//settingsStore
// .balanceDisplayMode;
final formattedAmount = trade.amount != null
? savedDisplayMode ==
BalanceDisplayMode.hiddenBalance
? '---'
: trade.amountFormatted()
: trade.amount;
return TradeRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.tradeDetails,
arguments: trade),
provider: trade.provider,
from: trade.from,
to: trade.to,
createdAtFormattedDate:
transactionDateFormat.format(trade.createdAt),
formattedAmount: formattedAmount);
}
return Container(
color: Theme.of(context).backgroundColor,
height: 1);
},
separatorBuilder: (_, __) =>
Container(height: 14, color: Colors.white),
)
: Padding(
padding: EdgeInsets.all(20),
child: Text('Your transactions will be displayed here!',
style: TextStyle(color: Colors.grey)))
]))); //,
}
}

View file

@ -1,15 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/palette.dart';
class TradeRow extends StatelessWidget { class TradeRow extends StatelessWidget {
TradeRow( TradeRow({
{this.provider, this.provider,
this.from, this.from,
this.to, this.to,
this.createdAtFormattedDate, this.createdAtFormattedDate,
this.formattedAmount, this.formattedAmount,
@required this.onTap}); @required this.onTap});
final VoidCallback onTap; final VoidCallback onTap;
final ExchangeProviderDescription provider; final ExchangeProviderDescription provider;
@ -25,58 +26,53 @@ class TradeRow extends StatelessWidget {
return InkWell( return InkWell(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
height: 60, height: 52,
decoration: BoxDecoration( color: Colors.transparent,
color: Theme.of(context).backgroundColor, padding: EdgeInsets.only(left: 24, right: 24),
border: Border.all( child: Row(
width: 1, crossAxisAlignment: CrossAxisAlignment.center,
color: Theme.of(context).backgroundColor children: <Widget>[
), _getPoweredImage(provider),
), Expanded(
padding: EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), child: Padding(
child: Row(children: <Widget>[ padding: const EdgeInsets.only(left: 12),
Container( child: Container(
height: 36, height: 46,
width: 36, child: Column(
decoration: BoxDecoration( mainAxisAlignment: MainAxisAlignment.spaceBetween,
shape: BoxShape.circle, mainAxisSize: MainAxisSize.max,
color: Theme.of(context).backgroundColor children: <Widget>[
), Row(
child: _getPoweredImage(provider), mainAxisAlignment: MainAxisAlignment.spaceBetween,
), children: <Widget>[
Expanded( Text('${from.toString()}${to.toString()}',
child: Padding( style: TextStyle(
padding: const EdgeInsets.only(left: 10), fontSize: 16,
child: Column( fontWeight: FontWeight.w500,
children: <Widget>[ color: Colors.white
Row( )),
mainAxisAlignment: MainAxisAlignment.spaceBetween, formattedAmount != null
children: <Widget>[ ? Text(formattedAmount + ' ' + amountCrypto,
Text('${from.toString()}${to.toString()}', style: TextStyle(
style: TextStyle( fontSize: 16,
fontSize: 16, fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color color: Colors.white
)), ))
formattedAmount != null : Container()
? Text(formattedAmount + ' ' + amountCrypto, ]),
style: TextStyle( Row(
fontSize: 16, mainAxisAlignment: MainAxisAlignment.spaceBetween,
color: Theme.of(context).primaryTextTheme.title.color children: <Widget>[
)) Text(createdAtFormattedDate,
: Container() style: TextStyle(
]), fontSize: 14,
SizedBox(height: 5), color: PaletteDark.darkCyanBlue))
Row( ]),
mainAxisAlignment: MainAxisAlignment.spaceBetween, ],
children: <Widget>[ ),
Text(createdAtFormattedDate, ),
style: TextStyle( ))
fontSize: 14, color: Theme.of(context).primaryTextTheme.headline.color)) ]),
]),
],
),
))
]),
)); ));
} }
@ -84,17 +80,17 @@ class TradeRow extends StatelessWidget {
Image image; Image image;
switch (provider) { switch (provider) {
case ExchangeProviderDescription.xmrto: case ExchangeProviderDescription.xmrto:
image = Image.asset('assets/images/xmr_btc.png'); image = Image.asset('assets/images/xmrto.png', height: 36, width: 36);
break; break;
case ExchangeProviderDescription.changeNow: case ExchangeProviderDescription.changeNow:
image = Image.asset('assets/images/change_now.png'); image = Image.asset('assets/images/changenow.png', height: 36, width: 36);
break; break;
case ExchangeProviderDescription.morphToken: case ExchangeProviderDescription.morphToken:
image = Image.asset('assets/images/morph_icon.png'); image = Image.asset('assets/images/morph.png', height: 36, width: 36);
break; break;
default: default:
image = null; image = null;
} }
return image; return image;
} }
} }

View file

@ -4,13 +4,13 @@ import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
class TransactionRow extends StatelessWidget { class TransactionRow extends StatelessWidget {
TransactionRow( TransactionRow({
{this.direction, this.direction,
this.formattedDate, this.formattedDate,
this.formattedAmount, this.formattedAmount,
this.formattedFiatAmount, this.formattedFiatAmount,
this.isPending, this.isPending,
@required this.onTap}); @required this.onTap});
final VoidCallback onTap; final VoidCallback onTap;
final TransactionDirection direction; final TransactionDirection direction;
@ -24,78 +24,74 @@ class TransactionRow extends StatelessWidget {
return InkWell( return InkWell(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
height: 41, height: 52,
color: Theme.of(context).backgroundColor, color: Colors.transparent,
padding: EdgeInsets.only(left: 20, right: 20), padding: EdgeInsets.only(left: 24, right: 24),
child: Row(children: <Widget>[ child: Row(
Container( crossAxisAlignment: CrossAxisAlignment.center,
height: 36, children: <Widget>[
width: 36, Container(
decoration: BoxDecoration( height: 36,
shape: BoxShape.circle, width: 36,
color: Theme.of(context).primaryTextTheme.display3.color), decoration: BoxDecoration(
child: Image.asset(direction == TransactionDirection.incoming shape: BoxShape.circle,
? 'assets/images/down_arrow.png' color: PaletteDark.wildNightBlue
: 'assets/images/up_arrow.png'), ),
), child: Image.asset(
Expanded( direction == TransactionDirection.incoming
child: Padding( ? 'assets/images/down_arrow.png'
padding: const EdgeInsets.only(left: 10), : 'assets/images/up_arrow.png'),
child: Column( ),
mainAxisAlignment: MainAxisAlignment.spaceBetween, Expanded(
children: <Widget>[ child: Padding(
Row( padding: const EdgeInsets.only(left: 12),
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: Container(
children: <Widget>[ height: 46,
Text( child: Column(
(direction == TransactionDirection.incoming mainAxisAlignment: MainAxisAlignment.spaceBetween,
? S.of(context).received mainAxisSize: MainAxisSize.max,
: S.of(context).sent) + children: <Widget>[
(isPending ? S.of(context).pending : ''), Row(
style: TextStyle( mainAxisAlignment: MainAxisAlignment.spaceBetween,
fontSize: 16, children: <Widget>[
fontWeight: FontWeight.w500, Text(
color: Theme.of(context) (direction == TransactionDirection.incoming
.primaryTextTheme ? S.of(context).received
.title : S.of(context).sent) +
.color)), (isPending ? S.of(context).pending : ''),
Text( style: TextStyle(
direction == TransactionDirection.incoming fontSize: 16,
? formattedAmount fontWeight: FontWeight.w500,
: '- ' + formattedAmount, color: Colors.white
style: TextStyle( )),
fontSize: 16, Text(direction == TransactionDirection.incoming
fontWeight: FontWeight.w500, ? formattedAmount
color: Theme.of(context) : '- ' + formattedAmount,
.primaryTextTheme style: TextStyle(
.title fontSize: 16,
.color)) fontWeight: FontWeight.w500,
]), color: Colors.white
Row( ))
mainAxisAlignment: MainAxisAlignment.spaceBetween, ]),
children: <Widget>[ Row(
Text(formattedDate, mainAxisAlignment: MainAxisAlignment.spaceBetween,
style: TextStyle( children: <Widget>[
fontSize: 14, Text(formattedDate,
color: Theme.of(context) style: TextStyle(
.primaryTextTheme fontSize: 14,
.headline color: PaletteDark.darkCyanBlue)),
.color)), Text(direction == TransactionDirection.incoming
Text( ? formattedFiatAmount
direction == TransactionDirection.incoming : '- ' + formattedFiatAmount,
? formattedFiatAmount style: TextStyle(
: '- ' + formattedFiatAmount, fontSize: 14,
style: TextStyle( color: PaletteDark.darkCyanBlue))
fontSize: 14, ]),
color: Theme.of(context) ],
.primaryTextTheme ),
.headline ),
.color)) ))
]), ]),
],
),
))
]),
)); ));
} }
} }

View file

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/header_row.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/date_section_raw.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/trade_row.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/transaction_raw.dart';
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/date_section_item.dart';
import 'package:intl/intl.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
class TransactionsPage extends StatelessWidget {
TransactionsPage({@required this.dashboardViewModel});
final DashboardViewModel dashboardViewModel;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: 24,
bottom: 24
),
child: Column(
children: <Widget>[
HeaderRow(dashboardViewModel: dashboardViewModel),
Expanded(
child: Observer(
builder: (_) {
final items = dashboardViewModel.items;
return items?.isNotEmpty ?? false
? ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
if (item is DateSectionItem) {
return DateSectionRaw(date: item.date);
}
if (item is TransactionListItem) {
final transaction = item.transaction;
return TransactionRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.transactionDetails,
arguments: transaction),
direction: transaction.direction,
formattedDate: DateFormat('HH:mm')
.format(transaction.date),
formattedAmount: item.formattedCryptoAmount,
formattedFiatAmount: item.formattedFiatAmount,
isPending: transaction.isPending);
}
if (item is TradeListItem) {
final trade = item.trade;
return TradeRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.tradeDetails,
arguments: trade),
provider: trade.provider,
from: trade.from,
to: trade.to,
createdAtFormattedDate:
DateFormat('HH:mm').format(trade.createdAt),
formattedAmount: item.tradeFormattedAmount
);
}
return Container(
color: Theme.of(context).backgroundColor,
height: 1);
}
)
: Center(
child: Text(
S.of(context).placeholder_transactions,
style: TextStyle(
fontSize: 14,
color: Colors.grey
),
),
);
}
)
)
],
),
);
}
}

View file

@ -1,508 +0,0 @@
import 'dart:async';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/view_model/dashboard_view_model.dart';
class WalletCard extends StatefulWidget {
WalletCard({this.walletVM});
final DashboardViewModel walletVM;
@override
WalletCardState createState() => WalletCardState();
}
class WalletCardState extends State<WalletCard> {
final _syncingObserverKey = GlobalKey();
final _balanceObserverKey = GlobalKey();
final _addressObserverKey = GlobalKey();
double cardWidth;
double cardHeight;
double screenWidth;
double opacity;
bool isDraw;
bool isFrontSide;
@override
void initState() {
cardWidth = 0;
cardHeight = 220;
screenWidth = 0;
opacity = 0;
isDraw = false;
isFrontSide = true;
super.initState();
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
}
void afterLayout(dynamic _) {
screenWidth = MediaQuery.of(context).size.width - 20;
setState(() {
cardWidth = screenWidth;
opacity = 1;
});
Timer(Duration(milliseconds: 500), () => setState(() => isDraw = true));
}
@override
Widget build(BuildContext context) {
final colorsSync = [
Theme.of(context).cardTheme.color,
Theme.of(context).hoverColor
];
return Container(
width: double.infinity,
height: cardHeight,
alignment: Alignment.centerRight,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(14), bottomLeft: Radius.circular(14))),
child: AnimatedContainer(
alignment: Alignment.centerLeft,
width: cardWidth,
height: cardHeight,
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(14),
bottomLeft: Radius.circular(14)),
color: Theme.of(context).focusColor),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
child: Container(
width: cardWidth,
height: cardHeight,
color: Theme.of(context).cardColor,
child: isFrontSide
? frontSide(colorsSync)
: InkWell(
onTap: () => setState(() => isFrontSide = true),
child: backSide(colorsSync)),
),
)),
);
}
Widget frontSide(List<Color> colorsSync) {
final settingsStore = Provider.of<SettingsStore>(context);
final triangleButton = Image.asset(
'assets/images/triangle.png',
color: Theme.of(context).primaryTextTheme.title.color,
);
return Observer(
key: _syncingObserverKey,
builder: (_) {
final status = widget.walletVM.status;
final statusText = status.title();
final progress = status.progress();
final indicatorOffset = progress * cardWidth;
final indicatorWidth =
progress <= 1 ? cardWidth - indicatorOffset : 0.0;
var descriptionText = '';
if (status is SyncingSyncStatus) {
descriptionText = S.of(context).Blocks_remaining(status.toString());
}
if (status is FailedSyncStatus) {
descriptionText = S.of(context).please_try_to_connect_to_another_node;
}
return Container(
width: cardWidth,
height: cardHeight,
color: Colors.white,
child: Stack(
children: <Widget>[
progress <= 1
? Positioned(
left: indicatorOffset,
top: 0,
bottom: 0,
child: Container(
width: indicatorWidth,
height: cardHeight,
color: Color.fromRGBO(227, 238, 249, 1),
))
: Offstage(),
isDraw
? Positioned(
left: 24,
right: 24,
top: 32,
bottom: 24,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
onTap: () => Navigator.of(context)
.pushNamed(Routes.walletList),
child: Row(
children: <Widget>[
Text(
widget.walletVM.name,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
SizedBox(width: 10),
triangleButton
],
),
),
SizedBox(height: 5),
if (widget.walletVM.subname?.isNotEmpty ??
false)
Text(
widget.walletVM.subname,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
)
],
),
InkWell(
onTap: () =>
setState(() => isFrontSide = false),
child: Container(
width: 98,
height: 32,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context)
.accentTextTheme
.subtitle
.backgroundColor,
border: Border.all(
color: Color.fromRGBO(
219, 231, 237, 1)),
// FIXME
borderRadius: BorderRadius.all(
Radius.circular(16))),
child: Text(
'Receive',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
)),
)
],
),
status is SyncedSyncStatus
? Observer(
key: _balanceObserverKey,
builder: (_) {
final balanceDisplayMode =
BalanceDisplayMode.availableBalance;
// settingsStore.balanceDisplayMode;
final symbol =
settingsStore.fiatCurrency.toString();
var balance = '---';
var fiatBalance = '---';
if (balanceDisplayMode ==
BalanceDisplayMode.availableBalance) {
balance = widget.walletVM.balance
.unlockedBalance ??
'0.0';
fiatBalance = '\$ 0.00';
// '$symbol ${balanceStore.fiatUnlockedBalance}';
}
if (balanceDisplayMode ==
BalanceDisplayMode.fullBalance) {
balance = widget.walletVM.balance
.totalBalance ??
'0.0';
fiatBalance = '\$ 0.00';
// '$symbol ${balanceStore.fiatFullBalance}';
}
return Row(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
balanceDisplayMode.toString(),
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
),
SizedBox(height: 5),
Container(
height: 36,
child: Text(
balance,
style: TextStyle(
fontSize: 32,
color: Theme.of(context)
.primaryTextTheme
.title
.color,
fontWeight:
FontWeight.bold),
))
],
),
Text(
fiatBalance,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
// FIXME
// color: Theme.of(context)
// .primaryTextTheme
// .title
// .color,
color: Color.fromRGBO(
72, 89, 109, 1)),
)
],
);
})
: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
statusText,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
),
SizedBox(height: 5),
Text(
descriptionText,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
)
],
)
],
)
],
),
))
: Offstage()
],
),
);
},
);
}
Widget backSide(List<Color> colorsSync) {
final rightArrow = Image.asset('assets/images/right_arrow.png',
color: Theme.of(context).primaryTextTheme.title.color);
var messageBoxHeight = 0.0;
var messageBoxWidth = cardWidth - 10;
return Observer(
key: _addressObserverKey,
builder: (_) {
return Container(
width: cardWidth,
height: cardHeight,
alignment: Alignment.topCenter,
child: Stack(
alignment: Alignment.topRight,
children: <Widget>[
Container(
width: cardWidth,
height: cardHeight,
padding:
EdgeInsets.only(left: 24, right: 24, top: 32, bottom: 32),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10)),
gradient: LinearGradient(
colors: colorsSync,
begin: Alignment.topCenter,
end: Alignment.bottomCenter)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
S.current.card_address,
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
),
SizedBox(height: 10),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: widget.walletVM.address));
_addressObserverKey.currentState
.setState(() {
messageBoxHeight = 20;
messageBoxWidth = cardWidth;
});
Timer(Duration(milliseconds: 1000), () {
try {
_addressObserverKey.currentState
.setState(() {
messageBoxHeight = 0;
messageBoxWidth = cardWidth - 10;
});
} catch (e) {
print('${e.toString()}');
}
});
},
child: Text(
widget.walletVM.address,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
)
],
),
)),
SizedBox(width: 10),
Container(
width: 90,
height: 90,
child: QrImage(
data: widget.walletVM.address,
backgroundColor: Colors.transparent,
foregroundColor: Theme.of(context)
.primaryTextTheme
.caption
.color),
)
],
),
Container(
height: 44,
padding: EdgeInsets.only(left: 20, right: 20),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(22)),
color: Theme.of(context)
.primaryTextTheme
.overline
.color),
child: InkWell(
onTap: () =>
Navigator.of(context, rootNavigator: true)
.pushNamed(Routes.receive),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
S.of(context).addresses,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
),
rightArrow
],
),
),
)
],
),
),
AnimatedContainer(
width: messageBoxWidth,
height: messageBoxHeight,
alignment: Alignment.center,
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(topLeft: Radius.circular(10)),
color: Colors.green),
child: Text(
S.of(context).copied_to_clipboard,
style: TextStyle(fontSize: 10, color: Colors.white),
),
)
],
),
);
});
}
}

View file

@ -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<TradeListItem> filtered({List<TradeListItem> 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;
}
}

View file

@ -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 = <TradeListItem>[];
_onTradesChanged =
tradesSource.watch().listen((_) async => await updateTradeList());
updateTradeList();
}
Box<Trade> tradesSource;
StreamSubscription<BoxEvent> _onTradesChanged;
SettingsStore settingsStore;
@observable
List<TradeListItem> trades;
@action
Future updateTradeList() async => trades =
tradesSource.values.map((trade) => TradeListItem(
trade: trade,
displayMode: settingsStore.balanceDisplayMode)).toList();
}

View file

@ -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<TransactionListItem> filtered({List<TransactionListItem> transactions}) {
var _transactions = <TransactionListItem>[];
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;
}
}

View file

@ -4,7 +4,7 @@ import 'palette.dart';
class Themes { class Themes {
static final ThemeData lightTheme = ThemeData( static final ThemeData lightTheme = ThemeData(
fontFamily: 'Avenir Next', fontFamily: 'Poppins',
brightness: Brightness.light, brightness: Brightness.light,
backgroundColor: Colors.white, backgroundColor: Colors.white,
focusColor: Colors.white, // wallet card border focusColor: Colors.white, // wallet card border
@ -73,7 +73,7 @@ class Themes {
static final ThemeData darkTheme = ThemeData( static final ThemeData darkTheme = ThemeData(
fontFamily: 'Avenir Next', fontFamily: 'Poppins',
brightness: Brightness.dark, brightness: Brightness.dark,
backgroundColor: PaletteDark.darkNightBlue, backgroundColor: PaletteDark.darkNightBlue,
focusColor: PaletteDark.lightDistantBlue, // wallet card border focusColor: PaletteDark.lightDistantBlue, // wallet card border

View file

@ -0,0 +1,32 @@
enum ActionListDisplayMode { transactions, trades }
int serializeActionlistDisplayModes(List<ActionListDisplayMode> 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<ActionListDisplayMode> deserializeActionlistDisplayModes(int raw) {
final modes = List<ActionListDisplayMode>();
if (raw == 1 || raw - 10 == 1) {
modes.add(ActionListDisplayMode.trades);
}
if (raw >= 10) {
modes.add(ActionListDisplayMode.transactions);
}
return modes;
}

View file

@ -0,0 +1,3 @@
abstract class ActionListItem {
DateTime get date;
}

View file

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

View file

@ -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<TransactionListItem> 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<TradeListItem> get trades => tradesStore.trades;
@computed
double get price => balanceViewModel.price;
@computed
List<ActionListItem> get items {
final _items = <ActionListItem>[];
_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)));
}
}

View file

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

View file

@ -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<ActionListItem> formattedItemsList(List<ActionListItem> items) {
final formattedList = <ActionListItem>[];
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;
}

View file

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

View file

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

View file

@ -0,0 +1,6 @@
class WalletBalance {
WalletBalance({this.unlockedBalance, this.totalBalance});
String unlockedBalance;
String totalBalance;
}

View file

@ -1,169 +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';
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;
}
}
@observable
WalletType type;
@observable
String name;
@computed
String get address => wallet.address;
@computed
SyncStatus get status => wallet.syncStatus;
@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<Object> 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)));
}
}

View file

@ -267,6 +267,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.7" version: "3.0.7"
dots_indicator:
dependency: "direct main"
description:
name: dots_indicator
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
dotted_border: dotted_border:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -50,6 +50,7 @@ dependencies:
devicelocale: ^0.2.1 devicelocale: ^0.2.1
auto_size_text: ^2.1.0 auto_size_text: ^2.1.0
dotted_border: ^1.0.5 dotted_border: ^1.0.5
dots_indicator: ^1.2.0
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
@ -107,6 +108,11 @@ flutter:
- asset: assets/fonts/Montserrat-Regular.ttf - asset: assets/fonts/Montserrat-Regular.ttf
- asset: assets/fonts/Montserrat-Bold.ttf - asset: assets/fonts/Montserrat-Bold.ttf
- asset: assets/fonts/Montserrat-SemiBold.ttf - asset: assets/fonts/Montserrat-SemiBold.ttf
- family: Poppins
fonts:
- asset: assets/fonts/Poppins-Regular.ttf
- asset: assets/fonts/Poppins-Medium.ttf
- asset: assets/fonts/Poppins-Bold.ttf
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:

View file

@ -137,6 +137,7 @@
"share_address" : "Share address", "share_address" : "Share address",
"receive_amount" : "Amount", "receive_amount" : "Amount",
"subaddresses" : "Subaddresses", "subaddresses" : "Subaddresses",
"addresses" : "Addresses",
"rename" : "Rename", "rename" : "Rename",
"choose_account" : "Choose account", "choose_account" : "Choose account",
"create_new_account" : "Create new account", "create_new_account" : "Create new account",