diff --git a/assets/images/download.png b/assets/images/download.png new file mode 100644 index 000000000..1ae875234 Binary files /dev/null and b/assets/images/download.png differ diff --git a/assets/images/filter_icon.png b/assets/images/filter_icon.png new file mode 100644 index 000000000..7226a90e8 Binary files /dev/null and b/assets/images/filter_icon.png differ diff --git a/assets/images/menu.png b/assets/images/menu.png new file mode 100644 index 000000000..e42b77cfc Binary files /dev/null and b/assets/images/menu.png differ diff --git a/assets/images/transfer.png b/assets/images/transfer.png new file mode 100644 index 000000000..383c35fb1 Binary files /dev/null and b/assets/images/transfer.png differ diff --git a/assets/images/triangle.png b/assets/images/triangle.png index 0c48a2465..fcef7252a 100644 Binary files a/assets/images/triangle.png and b/assets/images/triangle.png differ diff --git a/assets/images/upload.png b/assets/images/upload.png new file mode 100644 index 000000000..dba320367 Binary files /dev/null and b/assets/images/upload.png differ diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 34f3bbf40..512866c0e 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -24,7 +24,6 @@ class S implements WidgetsLocalizations { String get account => "Account"; String get accounts => "Accounts"; String get accounts_subaddresses => "Accounts and subaddresses"; - String get addresses => "Addresses"; String get add => "Add"; String get add_new_node => "Add new node"; 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_remove_contact => "Remove 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 amount => "Amount: "; String get amount_is_estimate => "The receive amount is an estimate"; @@ -643,8 +643,6 @@ class $de extends S { @override String get accounts_subaddresses => "Konten und Unteradressen"; @override - String get addresses => "Addressen"; - @override String get wallet_name => "Walletname"; @override 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 String get accounts_subaddresses => "लेखा और उपदेस"; @override - String get addresses => "पतों"; - @override String get wallet_name => "बटुए का नाम"; @override String get error_text_payment_id => "पेमेंट आईडी केवल हेक्स में 16 से 64 चार्ट तक हो सकती है"; @@ -1887,8 +1883,6 @@ class $ru extends S { @override String get accounts_subaddresses => "Аккаунты и субадреса"; @override - String get addresses => "Адреса"; - @override String get wallet_name => "Имя кошелька"; @override String get error_text_payment_id => "Идентификатор платежа может содержать от 16 до 64 символов в hex"; @@ -2509,8 +2503,6 @@ class $ko extends S { @override String get accounts_subaddresses => "계정 및 하위 주소"; @override - String get addresses => "구애"; - @override String get wallet_name => "지갑 이름"; @override String get error_text_payment_id => "지불 ID는 16 ~ 64 자의 16 진 문자 만 포함 할 수 있습니다"; @@ -3131,8 +3123,6 @@ class $pt extends S { @override String get accounts_subaddresses => "Contas e sub-endereços"; @override - String get addresses => "Endereços"; - @override String get wallet_name => "Nome da carteira"; @override 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 String get accounts_subaddresses => "Акаунти та субадреси"; @override - String get addresses => "Адреси"; - @override String get wallet_name => "Ім'я гаманця"; @override String get error_text_payment_id => "Ідентифікатор платежу може містити від 16 до 64 символів в hex"; @@ -4375,8 +4363,6 @@ class $ja extends S { @override String get accounts_subaddresses => "アカウントとサブアドレス"; @override - String get addresses => "アドレス"; - @override String get wallet_name => "ウォレット名"; @override String get error_text_payment_id => "支払いIDには、16進数で16〜64文字しか含めることができません"; @@ -5001,8 +4987,6 @@ class $pl extends S { @override String get accounts_subaddresses => "Konta i podadresy"; @override - String get addresses => "Adresy"; - @override String get wallet_name => "Nazwa portfela"; @override 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 String get accounts_subaddresses => "Cuentas y subdirecciones"; @override - String get addresses => "Direcciones"; - @override String get wallet_name => "Nombre de la billetera"; @override 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 String get accounts_subaddresses => "Accounts en subadressen"; @override - String get addresses => "Adressen"; - @override String get wallet_name => "Portemonnee naam"; @override 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 String get accounts_subaddresses => "帳戶和子地址"; @override - String get addresses => "地址"; - @override String get wallet_name => "钱包名称"; @override String get error_text_payment_id => "付款ID只能包含16到64个字符(十六进制)"; diff --git a/lib/palette.dart b/lib/palette.dart index 9d0c5be32..1806888b9 100644 --- a/lib/palette.dart +++ b/lib/palette.dart @@ -20,7 +20,6 @@ class Palette { class PaletteDark { 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 nightBlue = Color.fromRGBO(45, 56, 95, 1.0); // walletCardBottomEndSync 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 moderateBlue = Color.fromRGBO(63, 77, 122, 1.0); // walletCardSubAddressField @@ -28,8 +27,19 @@ class PaletteDark { 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 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 + + // 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 cyanBlue = Color.fromRGBO(99, 113, 150, 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. static const Color eee = Color.fromRGBO(236, 239, 245, 1.0); static const Color xxx = Color.fromRGBO(72, 89, 109, 1); diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index ed297aec6..89e3af553 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -4,49 +4,43 @@ import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:cake_wallet/view_model/dashboard_view_model.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/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:flutter_mobx/flutter_mobx.dart'; +import 'package:mobx/mobx.dart'; class DashboardPage extends BasePage { DashboardPage({@required this.walletViewModel}); @override - Color get backgroundLightColor => Colors.transparent; + Color get backgroundLightColor => PaletteDark.backgroundColor; @override - Color get backgroundDarkColor => Colors.transparent; - - @override - Widget Function(BuildContext, Widget) get rootWrapper => - (BuildContext context, Widget scaffold) => Container( - decoration: BoxDecoration( - gradient: LinearGradient(colors: [ - Theme.of(context).scaffoldBackgroundColor, - Theme.of(context).primaryColor - ], begin: Alignment.topLeft, end: Alignment.bottomRight)), - child: scaffold); + Color get backgroundDarkColor => PaletteDark.backgroundColor; @override Widget trailing(BuildContext context) { - final menuButton = Image.asset('assets/images/header.png', - color: Theme.of(context).primaryTextTheme.title.color); + final menuButton = Image.asset('assets/images/menu.png', + color: Colors.white); return Container( alignment: Alignment.centerRight, child: SizedBox( - width: 24, + width: 20, child: FlatButton( highlightColor: Colors.transparent, splashColor: Colors.transparent, padding: EdgeInsets.all(0), onPressed: () async { await showDialog( - builder: (_) => MenuWidget( - name: walletViewModel.name, - subname: walletViewModel.subname, - type: walletViewModel.type), - context: context); + builder: (_) => MenuWidget( + name: walletViewModel.name, + subname: walletViewModel.subname, + type: walletViewModel.type), + context: context); }, child: menuButton), ), @@ -54,97 +48,116 @@ class DashboardPage extends BasePage { } final DashboardViewModel walletViewModel; - final sendImage = Image.asset('assets/images/send.png'); - final exchangeImage = Image.asset('assets/images/exchange.png'); - final buyImage = Image.asset('assets/images/coins.png'); + final sendImage = Image.asset('assets/images/upload.png'); + final exchangeImage = Image.asset('assets/images/transfer.png'); + final receiveImage = Image.asset('assets/images/download.png'); + final controller = PageController(initialPage: 0); + + var pages = []; + bool _isEffectsInstalled = false; @override Widget body(BuildContext context) { - return LayoutBuilder(builder: (context, constraints) { - final transactionListMinHeight = - constraints.heightConstraints().maxHeight - 345 - 32; - return SingleChildScrollView( - child: Column(children: [ - Container( - height: 345, - child: Column(children: [ - Padding( - padding: EdgeInsets.only(left: 24, top: 10), - child: WalletCard(walletVM: walletViewModel)), - Container( - padding: EdgeInsets.only(left: 44, right: 44, top: 32), - child: Row( - children: [ - Flexible( - child: actionButton( - context: context, - image: sendImage, - title: S.of(context).send, - route: Routes.send)), - Flexible( - child: actionButton( - context: context, - image: exchangeImage, - title: S.of(context).exchange, - route: Routes.exchange)), - ], - ), + _setEffects(); + + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: PageView.builder( + controller: controller, + itemCount: pages.length, + itemBuilder: (context, index) { + return pages[index]; + } ) - ])), - SizedBox(height: 32), - ConstrainedBox( - constraints: BoxConstraints(minHeight: transactionListMinHeight), - child: TradeHistoryPanel(dashboardViewModel: walletViewModel)), -// Column(children: [ -// Text('1'), -// Text('2') -// ]) - ])); + ), + Padding( + padding: EdgeInsets.only( + bottom: 24 + ), + child: Observer( + builder: (_) { + return DotsIndicator( + dotsCount: pages.length, + 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: [ + Flexible( + child: ActionButton( + image: sendImage, + title: S.of(context).send, + route: Routes.send, + alignment: Alignment.centerLeft, + ), + ), + Flexible( + child: ActionButton( + image: exchangeImage, + title: S.of(context).exchange, + route: Routes.exchange + ), + ), + Flexible( + 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(Center( + child: Text( + 'SECOND PAGE', + style: TextStyle( + color: Colors.white + ), + ), + )); + + 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: [ - GestureDetector( - onTap: () { - if (route.isNotEmpty) { - Navigator.of(context, rootNavigator: true).pushNamed(route); - } - }, - child: Container( - height: 48, - width: 48, - alignment: Alignment.center, - decoration: BoxDecoration( - color: Theme.of(context).primaryTextTheme.subhead.color, - shape: BoxShape.circle), - child: image, - ), - ), - Padding( - padding: EdgeInsets.only(top: 12), - child: Text( - title, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color.fromRGBO(140, 153, 201, - 0.8) // Theme.of(context).primaryTextTheme.caption.color - ), - ), - ) - ], - ), - ); -} diff --git a/lib/src/screens/dashboard/widgets/action_button.dart b/lib/src/screens/dashboard/widgets/action_button.dart new file mode 100644 index 000000000..a42c4ec8c --- /dev/null +++ b/lib/src/screens/dashboard/widgets/action_button.dart @@ -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: [ + 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 + ), + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/src/screens/dashboard/widgets/balance_page.dart b/lib/src/screens/dashboard/widgets/balance_page.dart new file mode 100644 index 000000000..ebbbdc8d0 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/balance_page.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:cake_wallet/view_model/dashboard_view_model.dart'; +import 'package:cake_wallet/palette.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart'; + +class BalancePage extends StatelessWidget { + BalancePage({@required this.dashboardViewModel}); + + final DashboardViewModel dashboardViewModel; + final triangleImage = Image.asset('assets/images/triangle.png'); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only( + top: 12, + left: 24, + right: 24, + bottom: 24 + ), + child: Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 0, + child: SyncIndicator(dashboardViewModel: dashboardViewModel) + ), + Container( + height: 160, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Observer( + builder: (_) { + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + dashboardViewModel.wallet.currency.toString(), + style: TextStyle( + fontSize: 40, + fontWeight: FontWeight.bold, + color: PaletteDark.cyanBlue, + height: 1 + ), + ), + Padding( + padding: EdgeInsets.only(left: 8), + child: triangleImage, + ) + ], + ); + } + ), + Observer( + builder: (_) { + return Text( + dashboardViewModel.balance.totalBalance, + style: TextStyle( + fontSize: 54, + fontWeight: FontWeight.bold, + color: Colors.white, + height: 1 + ), + ); + } + ), + Observer( + builder: (_) { + return Text( + '\$ 0.00', + style: TextStyle( + fontSize: 18, + color: PaletteDark.cyanBlue, + height: 1 + ), + ); + } + ), + ], + ), + ) + ], + ), + ); + } +} + diff --git a/lib/src/screens/dashboard/widgets/sync_indicator.dart b/lib/src/screens/dashboard/widgets/sync_indicator.dart new file mode 100644 index 000000000..abafe2988 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/sync_indicator.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:cake_wallet/view_model/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: [ + 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: [ + 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, + color: PaletteDark.wildBlue + ), + ), + ) + ], + ), + ) + ], + ), + ), + ); + } + ); + } +} \ No newline at end of file diff --git a/lib/view_model/dashboard_view_model.dart b/lib/view_model/dashboard_view_model.dart index ded80b3bc..f48cd3aad 100644 --- a/lib/view_model/dashboard_view_model.dart +++ b/lib/view_model/dashboard_view_model.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/src/domain/common/sync_status.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; import 'package:cake_wallet/store/app_store.dart'; +import 'package:cake_wallet/generated/i18n.dart'; part 'dashboard_view_model.g.dart'; @@ -35,6 +36,8 @@ abstract class DashboardViewModelBase with Store { if (_wallet is MoneroWallet) { subname = _wallet.account?.label; } + + currentPage = 0; } @observable @@ -43,12 +46,34 @@ abstract class DashboardViewModelBase with Store { @observable String name; + @observable + double currentPage; + @computed String get address => wallet.address; @computed SyncStatus get status => wallet.syncStatus; + @computed + String get syncStatusText { + var statusText = ''; + + if (status is SyncingSyncStatus) { + statusText = S.current + .Blocks_remaining( + status.toString()); + } + + if (status is FailedSyncStatus) { + statusText = S + .current + .please_try_to_connect_to_another_node; + } + + return statusText; + } + @computed WalletBalace get balance { final wallet = this.wallet; diff --git a/pubspec.lock b/pubspec.lock index 7f3229605..f8e7304da 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -267,6 +267,13 @@ packages: url: "https://pub.dartlang.org" source: hosted 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: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 7e3b3639d..b5b778c42 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,7 @@ dependencies: devicelocale: ^0.2.1 auto_size_text: ^2.1.0 dotted_border: ^1.0.5 + dots_indicator: ^1.2.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index b78aad690..64f3722a8 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -137,6 +137,7 @@ "share_address" : "Share address", "receive_amount" : "Amount", "subaddresses" : "Subaddresses", + "addresses" : "Addresses", "rename" : "Rename", "choose_account" : "Choose account", "create_new_account" : "Create new account",