From 93b8bd8a3552c4cc54aa8e9483ce51d11414f4cf Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Tue, 14 Apr 2020 21:15:47 +0300 Subject: [PATCH 01/51] CWA-198 | created wallet card --- assets/images/2.0x/triangle.png | Bin 0 -> 202 bytes assets/images/3.0x/triangle.png | Bin 0 -> 242 bytes assets/images/triangle.png | Bin 0 -> 193 bytes lib/palette.dart | 9 + lib/src/screens/dashboard/dashboard_page.dart | 35 +++- .../dashboard/widgets/wallet_card.dart | 198 ++++++++++++++++++ 6 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 assets/images/2.0x/triangle.png create mode 100644 assets/images/3.0x/triangle.png create mode 100644 assets/images/triangle.png create mode 100644 lib/src/screens/dashboard/widgets/wallet_card.dart diff --git a/assets/images/2.0x/triangle.png b/assets/images/2.0x/triangle.png new file mode 100644 index 0000000000000000000000000000000000000000..1a7baf26d5adefdb60b7134fd807e65eedc6ba7c GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1|+R>-G2co&H|6fVg?2=RS;(M3{v?36l5$8 za(7}_cTVOdki(Mh=XR_&!bG7o(^V sLuf;{iGnzXAUjuM9^1<)(md9T$GFUP{$_}O3$%*C)78&qol`;+0J$bP0l+XkK8V^!6 literal 0 HcmV?d00001 diff --git a/assets/images/triangle.png b/assets/images/triangle.png new file mode 100644 index 0000000000000000000000000000000000000000..0c48a2465f6c29d22b3caa087ec1255cbd839954 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{!3Opi<85p>QL70(Y)*K0-AY*Zm zyA#8@b22Z19F}xPUq=Rpjs4tz5?O)#Fi#i9kP61LJsWu&40u@n3NZ&f(&RIp null; @override Widget body(BuildContext context) => DashboardPageBody(key: _bodyKey); - @override + /*@override Widget floatingActionButton(BuildContext context) => FloatingActionButton( child: Image.asset('assets/images/exchange_icon.png', color: Colors.white, height: 26, width: 22), @@ -100,7 +103,7 @@ class DashboardPage extends BasePage { onItemSelected: (String item) => walletMenu.action(walletMenu.items.indexOf(item))), context: bodyContext); - } + }*/ } class DashboardPageBody extends StatefulWidget { @@ -120,7 +123,27 @@ class DashboardPageBodyState extends State { @override Widget build(BuildContext context) { - final balanceStore = Provider.of(context); + final List colors = [PaletteDark.backgroundStart, PaletteDark.backgroundEnd]; + + return SafeArea( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: colors + ) + ), + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(left: 20, top: 78), + child: WalletCard(), + ) + ], + ), + ), + ); + + /*final balanceStore = Provider.of(context); final actionListStore = Provider.of(context); final syncStore = Provider.of(context); final settingsStore = Provider.of(context); @@ -593,6 +616,6 @@ class DashboardPageBodyState extends State { return Container(); }); - }); + });*/ } } diff --git a/lib/src/screens/dashboard/widgets/wallet_card.dart b/lib/src/screens/dashboard/widgets/wallet_card.dart new file mode 100644 index 000000000..0bf8ae34d --- /dev/null +++ b/lib/src/screens/dashboard/widgets/wallet_card.dart @@ -0,0 +1,198 @@ +import 'package:cake_wallet/src/stores/sync/sync_store.dart'; +import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:cake_wallet/palette.dart'; +import 'package:provider/provider.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/domain/common/sync_status.dart'; + +class WalletCard extends StatefulWidget { + @override + WalletCardState createState() => WalletCardState(); +} + +class WalletCardState extends State { + final _syncingObserverKey = GlobalKey(); + final triangleButton = Image.asset('assets/images/triangle.png'); + + final List colorsSync = [PaletteDark.walletCardTopEndSync, PaletteDark.walletCardBottomEndSync]; + double cardWidth; + double screenWidth; + double opacity; + + @override + void initState() { + cardWidth = 0; + screenWidth = 0; + opacity = 0; + super.initState(); + WidgetsBinding.instance.addPostFrameCallback(afterLayout); + } + + void afterLayout(dynamic _) { + screenWidth = MediaQuery.of(context).size.width; + setState(() { + cardWidth = screenWidth; + opacity = 1; + }); + } + + @override + Widget build(BuildContext context) { + final syncStore = Provider.of(context); + final walletStore = Provider.of(context); + + return Container( + width: double.infinity, + height: 220, + alignment: Alignment.centerRight, + child: AnimatedContainer( + alignment: Alignment.centerLeft, + width: cardWidth, + height: 220, + duration: Duration(milliseconds: 500), + curve: Curves.fastOutSlowIn, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)), + gradient: LinearGradient( + colors: [PaletteDark.walletCardTopStartSync.withOpacity(opacity), + PaletteDark.walletCardBottomStartSync.withOpacity(opacity)], + begin: Alignment.topCenter, + end: Alignment.bottomCenter + ) + ), + child: screenWidth > 0 && cardWidth == screenWidth + ? InkWell( + onTap: (){print('TAP');}, + child: Observer( + key: _syncingObserverKey, + builder: (_) { + final status = syncStore.status; + final statusText = status.title(); + final progress = syncStore.status.progress(); + //final isFialure = status is FailedSyncStatus; + + var descriptionText = ''; + + if (status is SyncingSyncStatus) { + descriptionText = S + .of(context) + .Blocks_remaining( + syncStore.status.toString()); + } + + if (status is FailedSyncStatus) { + descriptionText = S + .of(context) + .please_try_to_connect_to_another_node; + } + + return Container( + width: cardWidth, + height: 220, + child: Stack( + children: [ + Container( + height: 220, + width: progress * cardWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)), + gradient: LinearGradient( + colors: colorsSync, + begin: Alignment.topCenter, + end: Alignment.bottomCenter + ) + ), + ), + Positioned( + left: 20, + right: 20, + top: 30, + bottom: 30, + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InkWell( + onTap: (){print('TAP 2');}, + child: Row( + children: [ + Text( + walletStore.name, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold + ), + ), + SizedBox(width: 10), + triangleButton + ], + ), + ), + SizedBox( + height: 5, + ), + Text( + walletStore.account.label, + style: TextStyle( + fontSize: 12 + ), + ) + ], + ), + Text( + walletStore.account.label + ) + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + statusText, + style: TextStyle( + fontSize: 12 + ), + ), + SizedBox(height: 5), + Text( + descriptionText, + style: TextStyle( + fontSize: 14 + ), + ) + ], + ), + Text( + walletStore.account.label + ) + ], + ) + ], + ), + ) + ) + ], + ), + ); + }, + ) + ) + : Offstage(), + ), + ); + } +} \ No newline at end of file From fc8c632e21016b47e8a98eb331493f83b705f162 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Wed, 15 Apr 2020 19:33:41 +0300 Subject: [PATCH 02/51] CWA-198 | created front and back sides of wallet card --- assets/images/2.0x/right_arrow.png | Bin 0 -> 244 bytes assets/images/3.0x/right_arrow.png | Bin 0 -> 268 bytes assets/images/right_arrow.png | Bin 0 -> 186 bytes lib/generated/i18n.dart | 23 + lib/palette.dart | 4 + lib/src/screens/dashboard/dashboard_page.dart | 4 +- .../dashboard/widgets/wallet_card.dart | 434 ++++++++++++++---- res/values/strings_de.arb | 4 +- res/values/strings_en.arb | 4 +- res/values/strings_es.arb | 4 +- res/values/strings_hi.arb | 4 +- res/values/strings_ja.arb | 4 +- res/values/strings_ko.arb | 4 +- res/values/strings_nl.arb | 4 +- res/values/strings_pl.arb | 4 +- res/values/strings_pt.arb | 4 +- res/values/strings_ru.arb | 4 +- res/values/strings_uk.arb | 4 +- res/values/strings_zh.arb | 4 +- 19 files changed, 398 insertions(+), 115 deletions(-) create mode 100644 assets/images/2.0x/right_arrow.png create mode 100644 assets/images/3.0x/right_arrow.png create mode 100644 assets/images/right_arrow.png diff --git a/assets/images/2.0x/right_arrow.png b/assets/images/2.0x/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..279cf0ccfb40540f0edfc308ced0511d5545e403 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9E$svykh8Km+7D9BhG zcl<_0KkqT+pkp3<#>K6H4vP)b7S1?u=Tm31R~IKw z`o2e^lP209&W&{nzB2p3n#byTtxE*9PAI!S`A>6sK<%QGfA+zopr06*MRvj6}9 literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/right_arrow.png b/assets/images/3.0x/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..35eb86002bcea167d8c4e933dbf98c08f67e53e5 GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^%0R5d!3HF+wkG@mQk(@Ik;M!QiWVTu=sL|X0Vv2= z9OUlAuxebtp7(RIy2^gy%I(+p$haI`Z-3a-Tb*dzfD7P4k_^ zob-rYtwq3z<0r@E*$pZ_28^B(!N;T1nKm&Woy{@7Y~^I}n+(6TSZ;;C)DQ$Zmci52 K&t;ucLK6V=G*?&v literal 0 HcmV?d00001 diff --git a/assets/images/right_arrow.png b/assets/images/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..8864a49f81d86ebb097a4625a186605d7de25a89 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k&H|6fVg?3oVGw3ym^DWND9BhG zZF653?fFeZohJCe<>OFGPZ*8di&## ca$)P4|LJz}1awCJ0vgTW>FVdQ&MBb@0I?%EW&i*H literal 0 HcmV?d00001 diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 186ac1ddb..845145783 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -40,6 +40,7 @@ class S implements WidgetsLocalizations { String get available_balance => "Available Balance"; String get biometric_auth_reason => "Scan your fingerprint to authenticate"; String get cancel => "Cancel"; + String get card_address => "Address:"; String get change => "Change"; String get change_currency => "Change Currency"; String get change_exchange_provider => "Change Exchange Provider"; @@ -362,6 +363,8 @@ class $de extends S { @override String get wallet_list_create_new_wallet => "Neue Wallet erstellen"; @override + String get card_address => "Adresse:"; + @override String get seed_language_portuguese => "Portugiesisch"; @override String get setup_pin => "PIN einrichten"; @@ -930,6 +933,8 @@ class $hi extends S { @override String get wallet_list_create_new_wallet => "नया बटुआ बनाएँ"; @override + String get card_address => "पता:"; + @override String get seed_language_portuguese => "पुर्तगाली"; @override String get setup_pin => "पिन सेट करें"; @@ -1498,6 +1503,8 @@ class $ru extends S { @override String get wallet_list_create_new_wallet => "Создать новый кошелёк"; @override + String get card_address => "Адрес:"; + @override String get seed_language_portuguese => "Португальский"; @override String get setup_pin => "Настроить PIN"; @@ -2066,6 +2073,8 @@ class $ko extends S { @override String get wallet_list_create_new_wallet => "새 월렛 만들기"; @override + String get card_address => "주소:"; + @override String get seed_language_portuguese => "포르투갈 인"; @override String get setup_pin => "설정 PIN"; @@ -2634,6 +2643,8 @@ class $pt extends S { @override String get wallet_list_create_new_wallet => "Criar nova carteira"; @override + String get card_address => "Endereço:"; + @override String get seed_language_portuguese => "Português"; @override String get setup_pin => "Configurar PIN"; @@ -3202,6 +3213,8 @@ class $uk extends S { @override String get wallet_list_create_new_wallet => "Створити новий гаманець"; @override + String get card_address => "Адреса:"; + @override String get seed_language_portuguese => "Португальська"; @override String get setup_pin => "Встановити PIN"; @@ -3770,6 +3783,8 @@ class $ja extends S { @override String get wallet_list_create_new_wallet => "新しいウォレットを作成"; @override + String get card_address => "住所:"; + @override String get seed_language_portuguese => "ポルトガル語"; @override String get setup_pin => "PINのセットアップ"; @@ -4342,6 +4357,8 @@ class $pl extends S { @override String get wallet_list_create_new_wallet => "Utwórz nowy portfel"; @override + String get card_address => "Adres:"; + @override String get seed_language_portuguese => "Portugalski"; @override String get setup_pin => "Ustaw PIN"; @@ -4910,6 +4927,8 @@ class $es extends S { @override String get wallet_list_create_new_wallet => "Crear nueva billetera"; @override + String get card_address => "Dirección:"; + @override String get seed_language_portuguese => "Portugués"; @override String get setup_pin => "PIN de configuración"; @@ -5478,6 +5497,8 @@ class $nl extends S { @override String get wallet_list_create_new_wallet => "Maak een nieuwe portemonnee"; @override + String get card_address => "Adres:"; + @override String get seed_language_portuguese => "Portugees"; @override String get setup_pin => "PIN instellen"; @@ -6046,6 +6067,8 @@ class $zh extends S { @override String get wallet_list_create_new_wallet => "创建新钱包"; @override + String get card_address => "地址:"; + @override String get seed_language_portuguese => "葡萄牙語"; @override String get setup_pin => "设定PIN码"; diff --git a/lib/palette.dart b/lib/palette.dart index 382ddebff..06d889b16 100644 --- a/lib/palette.dart +++ b/lib/palette.dart @@ -78,4 +78,8 @@ class PaletteDark { static const Color walletCardBottomStartSync = Color.fromRGBO(70, 85, 133, 1.0); static const Color walletCardTopEndSync = Color.fromRGBO(70, 85, 133, 1.0); static const Color walletCardBottomEndSync = Color.fromRGBO(45, 56, 95, 1.0); + static const Color walletCardText = Color.fromRGBO(140, 153, 201, 1.0); + static const Color walletCardAddressField = Color.fromRGBO(51, 63, 104, 1.0); + static const Color walletCardAddressText = Color.fromRGBO(183, 197, 242, 1.0); + static const Color walletCardSubAddressField = Color.fromRGBO(63, 77, 122, 1.0); } \ No newline at end of file diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 5fa659976..ab0185b8b 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -114,12 +114,12 @@ class DashboardPageBody extends StatefulWidget { } class DashboardPageBodyState extends State { - final _connectionStatusObserverKey = GlobalKey(); + /*final _connectionStatusObserverKey = GlobalKey(); final _balanceObserverKey = GlobalKey(); final _balanceTitleObserverKey = GlobalKey(); final _syncingObserverKey = GlobalKey(); final _listObserverKey = GlobalKey(); - final _listKey = GlobalKey(); + final _listKey = GlobalKey();*/ @override Widget build(BuildContext context) { diff --git a/lib/src/screens/dashboard/widgets/wallet_card.dart b/lib/src/screens/dashboard/widgets/wallet_card.dart index 0bf8ae34d..d086b9c53 100644 --- a/lib/src/screens/dashboard/widgets/wallet_card.dart +++ b/lib/src/screens/dashboard/widgets/wallet_card.dart @@ -1,12 +1,18 @@ +import 'dart:async'; +import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:cake_wallet/src/stores/balance/balance_store.dart'; +import 'package:cake_wallet/src/stores/settings/settings_store.dart'; import 'package:cake_wallet/src/stores/sync/sync_store.dart'; import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:provider/provider.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/qr_image.dart'; class WalletCard extends StatefulWidget { @override @@ -15,18 +21,25 @@ class WalletCard extends StatefulWidget { class WalletCardState extends State { final _syncingObserverKey = GlobalKey(); - final triangleButton = Image.asset('assets/images/triangle.png'); + final _balanceObserverKey = GlobalKey(); + final _addressObserverKey = GlobalKey(); final List colorsSync = [PaletteDark.walletCardTopEndSync, PaletteDark.walletCardBottomEndSync]; 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); } @@ -37,21 +50,21 @@ class WalletCardState extends State { cardWidth = screenWidth; opacity = 1; }); + Timer(Duration(milliseconds: 350), () => + setState(() => isDraw = true) + ); } @override Widget build(BuildContext context) { - final syncStore = Provider.of(context); - final walletStore = Provider.of(context); - return Container( width: double.infinity, - height: 220, + height: cardHeight, alignment: Alignment.centerRight, child: AnimatedContainer( alignment: Alignment.centerLeft, width: cardWidth, - height: 220, + height: cardHeight, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn, decoration: BoxDecoration( @@ -63,98 +76,156 @@ class WalletCardState extends State { end: Alignment.bottomCenter ) ), - child: screenWidth > 0 && cardWidth == screenWidth - ? InkWell( - onTap: (){print('TAP');}, - child: Observer( - key: _syncingObserverKey, - builder: (_) { - final status = syncStore.status; - final statusText = status.title(); - final progress = syncStore.status.progress(); - //final isFialure = status is FailedSyncStatus; + child: InkWell( + onTap: () => setState(() => isFrontSide = !isFrontSide), + child: isFrontSide + ? frontSide() + : backSide() + ), + ), + ); + } - var descriptionText = ''; + Widget frontSide() { + final syncStore = Provider.of(context); + final walletStore = Provider.of(context); + final settingsStore = Provider.of(context); + final balanceStore = Provider.of(context); + final triangleButton = Image.asset('assets/images/triangle.png'); - if (status is SyncingSyncStatus) { - descriptionText = S - .of(context) - .Blocks_remaining( - syncStore.status.toString()); - } + return Observer( + key: _syncingObserverKey, + builder: (_) { + final status = syncStore.status; + final statusText = status.title(); + final progress = syncStore.status.progress(); - if (status is FailedSyncStatus) { - descriptionText = S - .of(context) - .please_try_to_connect_to_another_node; - } + String shortAddress = walletStore.subaddress.address; + shortAddress = shortAddress.replaceRange(4, shortAddress.length - 4, '...'); - return Container( - width: cardWidth, - height: 220, - child: Stack( - children: [ - Container( - height: 220, - width: progress * cardWidth, - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)), - gradient: LinearGradient( - colors: colorsSync, - begin: Alignment.topCenter, - end: Alignment.bottomCenter - ) - ), - ), - Positioned( - left: 20, - right: 20, - top: 30, - bottom: 30, - child: Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, + var descriptionText = ''; + + if (status is SyncingSyncStatus) { + descriptionText = S + .of(context) + .Blocks_remaining( + syncStore.status.toString()); + } + + if (status is FailedSyncStatus) { + descriptionText = S + .of(context) + .please_try_to_connect_to_another_node; + } + + return Container( + width: cardWidth, + height: cardHeight, + child: Stack( + children: [ + Container( + height: cardHeight, + width: progress * cardWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)), + gradient: LinearGradient( + colors: colorsSync, + begin: Alignment.topCenter, + end: Alignment.bottomCenter + ) + ), + ), + isDraw ? Positioned( + left: 20, + right: 20, + top: 30, + bottom: 30, + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InkWell( + onTap: () {print('TAP 2');}, + child: Row( children: [ - InkWell( - onTap: (){print('TAP 2');}, - child: Row( - children: [ - Text( - walletStore.name, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold - ), - ), - SizedBox(width: 10), - triangleButton - ], - ), - ), - SizedBox( - height: 5, - ), Text( - walletStore.account.label, + walletStore.name, style: TextStyle( - fontSize: 12 + fontSize: 20, + fontWeight: FontWeight.bold ), - ) + ), + SizedBox(width: 10), + triangleButton ], ), - Text( - walletStore.account.label - ) - ], + ), + SizedBox( + height: 5, + ), + Text( + walletStore.account.label, + style: TextStyle( + fontSize: 12, + color: PaletteDark.walletCardText + ), + ) + ], + ), + Container( + width: 98, + height: 32, + alignment: Alignment.center, + decoration: BoxDecoration( + color: PaletteDark.walletCardAddressField, + borderRadius: BorderRadius.all(Radius.circular(16)) ), - Row( + child: Text( + shortAddress, + style: TextStyle( + fontSize: 12, + color: PaletteDark.walletCardAddressText + ), + ), + ) + ], + ), + status is SyncedSyncStatus + ? Observer( + key: _balanceObserverKey, + builder: (_) { + final balanceDisplayMode = settingsStore.balanceDisplayMode; + final symbol = settingsStore + .fiatCurrency + .toString(); + var balance = '---'; + var fiatBalance = '---'; + + if (balanceDisplayMode == + BalanceDisplayMode.availableBalance) { + balance = + balanceStore.unlockedBalance ?? + '0.0'; + fiatBalance = + '$symbol ${balanceStore.fiatUnlockedBalance}'; + } + + if (balanceDisplayMode == + BalanceDisplayMode.fullBalance) { + balance = + balanceStore.fullBalance ?? '0.0'; + fiatBalance = + '$symbol ${balanceStore.fiatFullBalance}'; + } + + return Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -162,37 +233,198 @@ class WalletCardState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - statusText, + balanceDisplayMode.toString(), style: TextStyle( - fontSize: 12 + fontSize: 12, + color: PaletteDark.walletCardText ), ), SizedBox(height: 5), Text( - descriptionText, + balance, style: TextStyle( - fontSize: 14 + fontSize: 28 ), ) ], ), Text( - walletStore.account.label + fiatBalance, + style: TextStyle( + fontSize: 14 + ), ) ], - ) - ], + ); + } + ) + : Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + statusText, + style: TextStyle( + fontSize: 12, + color: PaletteDark.walletCardText + ), + ), + SizedBox(height: 5), + Text( + descriptionText, + style: TextStyle( + fontSize: 14 + ), + ) + ], + ) + ], + ) + ], + ), + ) + ) + : Offstage() + ], + ), + ); + }, + ); + } + + Widget backSide() { + final walletStore = Provider.of(context); + final rightArrow = Image.asset('assets/images/right_arrow.png'); + double messageBoxHeight = 0; + + return Observer( + key: _addressObserverKey, + builder: (_) { + return Container( + width: cardWidth, + height: cardHeight, + alignment: Alignment.topCenter, + child: Stack( + children: [ + Container( + width: cardWidth, + height: cardHeight, + padding: EdgeInsets.only(left: 20, right: 20, top: 30, bottom: 30), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)), + gradient: LinearGradient( + colors: colorsSync, + begin: Alignment.topCenter, + end: Alignment.bottomCenter + ) + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Expanded( + child: Container( + height: 72, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + S.current.card_address, + style: TextStyle( + fontSize: 12, + color: PaletteDark.walletCardText + ), + ), + GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData( + text: walletStore.subaddress.address)); + _addressObserverKey.currentState.setState(() => messageBoxHeight = 20); + Timer(Duration(milliseconds: 1000), () { + try { + _addressObserverKey.currentState.setState(() => messageBoxHeight = 0); + } catch(e) { + print('${e.toString()}'); + } + }); + }, + child: Text( + walletStore.subaddress.address, + style: TextStyle( + fontSize: 14, + ), + ), + ) + ], + ), + ) + ), + SizedBox(width: 20), + Container( + width: 72, + height: 72, + child: QrImage( + data: walletStore.subaddress.address, + backgroundColor: Colors.transparent, + foregroundColor: PaletteDark.walletCardText, ), ) + ], + ), + Container( + height: 44, + padding: EdgeInsets.only(left: 20, right: 20), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(22)), + color: PaletteDark.walletCardSubAddressField + ), + child: InkWell( + onTap: () {}, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + S.current.subaddresses, + style: TextStyle( + fontSize: 14, + ), + ), + rightArrow + ], + ), + ), ) ], ), - ); - }, - ) - ) - : Offstage(), - ), + ), + AnimatedContainer( + width: cardWidth, + 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 + ), + ), + ) + ], + ), + ); + } ); } } \ No newline at end of file diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 58d26c54c..572ccbbbd 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -349,5 +349,7 @@ "version" : "Ausführung ${currentVersion}", "openalias_alert_title" : "XMR-Empfänger erkannt", - "openalias_alert_content" : "Sie senden Geld an\n${recipient_name}" + "openalias_alert_content" : "Sie senden Geld an\n${recipient_name}", + + "card_address" : "Adresse:" } \ No newline at end of file diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 2a019d3e7..469b08f28 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -349,5 +349,7 @@ "version" : "Version ${currentVersion}", "openalias_alert_title" : "XMR Recipient Detected", - "openalias_alert_content" : "You will be sending funds to\n${recipient_name}" + "openalias_alert_content" : "You will be sending funds to\n${recipient_name}", + + "card_address" : "Address:" } \ No newline at end of file diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 6b15f9c95..be8257b32 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -349,5 +349,7 @@ "version" : "Versión ${currentVersion}", "openalias_alert_title" : "Destinatario XMR detectado", - "openalias_alert_content" : "Enviará fondos a\n${recipient_name}" + "openalias_alert_content" : "Enviará fondos a\n${recipient_name}", + + "card_address" : "Dirección:" } \ No newline at end of file diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 6760af1ff..b4a8763ec 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -349,5 +349,7 @@ "version" : "संस्करण ${currentVersion}", "openalias_alert_title" : "XMR प्राप्तकर्ता का पता लगाया", - "openalias_alert_content" : "आपको धनराशि भेजी जाएगी\n${recipient_name}" + "openalias_alert_content" : "आपको धनराशि भेजी जाएगी\n${recipient_name}", + + "card_address" : "पता:" } \ No newline at end of file diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index ddac44e75..c6e76cc1f 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -349,5 +349,7 @@ "version" : "バージョン ${currentVersion}", "openalias_alert_title" : "XMR受信者が検出されました", - "openalias_alert_content" : "に送金します\n${recipient_name}" + "openalias_alert_content" : "に送金します\n${recipient_name}", + + "card_address" : "住所:" } \ No newline at end of file diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 644629554..8b470908c 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -349,5 +349,7 @@ "version" : "버전 ${currentVersion}", "openalias_alert_title" : "XMR 수신자 감지", - "openalias_alert_content" : "당신은에 자금을 보낼 것입니다\n${recipient_name}" + "openalias_alert_content" : "당신은에 자금을 보낼 것입니다\n${recipient_name}", + + "card_address" : "주소:" } \ No newline at end of file diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index cefa5284b..f0916e1d9 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -349,5 +349,7 @@ "version" : "Versie ${currentVersion}", "openalias_alert_title" : "XMR-ontvanger gedetecteerd", - "openalias_alert_content" : "U stuurt geld naar\n${recipient_name}" + "openalias_alert_content" : "U stuurt geld naar\n${recipient_name}", + + "card_address" : "Adres:" } \ No newline at end of file diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 5da641175..d08fba806 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -349,5 +349,7 @@ "version" : "Wersja ${currentVersion}", "openalias_alert_title" : "Wykryto odbiorcę XMR", - "openalias_alert_content" : "Będziesz wysyłać środki na\n${recipient_name}" + "openalias_alert_content" : "Będziesz wysyłać środki na\n${recipient_name}", + + "card_address" : "Adres:" } \ No newline at end of file diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index c1ff1ca32..09e0a383c 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -349,5 +349,7 @@ "version" : "Versão ${currentVersion}", "openalias_alert_title" : "Destinatário XMR detectado", - "openalias_alert_content" : "Você enviará fundos para\n${recipient_name}" + "openalias_alert_content" : "Você enviará fundos para\n${recipient_name}", + + "card_address" : "Endereço:" } diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 947cc1cb5..cb7f935aa 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -349,5 +349,7 @@ "version" : "Версия ${currentVersion}", "openalias_alert_title" : "Получатель XMR обнаружен", - "openalias_alert_content" : "Вы будете отправлять средства\n${recipient_name}" + "openalias_alert_content" : "Вы будете отправлять средства\n${recipient_name}", + + "card_address" : "Адрес:" } \ No newline at end of file diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 39ce4762c..e8a24c230 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -349,5 +349,7 @@ "version" : "Версія ${currentVersion}", "openalias_alert_title" : "Отримувача XMR виявлено", - "openalias_alert_content" : "Ви будете відправляти кошти\n${recipient_name}" + "openalias_alert_content" : "Ви будете відправляти кошти\n${recipient_name}", + + "card_address" : "Адреса:" } \ No newline at end of file diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 61625661a..5c074a0f4 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -349,5 +349,7 @@ "version" : "版 ${currentVersion}", "openalias_alert_title" : "檢測到XMR收件人", - "openalias_alert_content" : "您將匯款至\n${recipient_name}" + "openalias_alert_content" : "您將匯款至\n${recipient_name}", + + "card_address" : "地址:" } \ No newline at end of file From b7198f4f6c858259e97e7a9d05e831aebb966d15 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Wed, 15 Apr 2020 21:09:41 +0300 Subject: [PATCH 03/51] CWA-198 | added buttons to dashboard page --- lib/src/screens/dashboard/dashboard_page.dart | 9 ++ .../dashboard/widgets/buttons_widget.dart | 118 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 lib/src/screens/dashboard/widgets/buttons_widget.dart diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index ab0185b8b..fa7819f2f 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -25,6 +25,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/wallet_card.dart'; +import 'package:cake_wallet/src/screens/dashboard/widgets/buttons_widget.dart'; class DashboardPage extends BasePage { final _bodyKey = GlobalKey(); @@ -137,6 +138,14 @@ class DashboardPageBodyState extends State { Padding( padding: EdgeInsets.only(left: 20, top: 78), child: WalletCard(), + ), + Padding( + padding: EdgeInsets.only(top: 28), + child: ButtonsWidget(), + ), + Expanded( + child: Container( + ) ) ], ), diff --git a/lib/src/screens/dashboard/widgets/buttons_widget.dart b/lib/src/screens/dashboard/widgets/buttons_widget.dart new file mode 100644 index 000000000..cef410fdf --- /dev/null +++ b/lib/src/screens/dashboard/widgets/buttons_widget.dart @@ -0,0 +1,118 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/routes.dart'; + +class ButtonsWidget extends StatefulWidget { + @override + ButtonsWidgetState createState() => ButtonsWidgetState(); +} + +class ButtonsWidgetState extends State { + final sendImage = Image.asset('assets/images/send.png'); + final exchangeImage = Image.asset('assets/images/exchange.png'); + final buyImage = Image.asset('assets/images/coins.png'); + + double height; + bool isDraw; + + @override + void initState() { + height = 0; + isDraw = false; + super.initState(); + WidgetsBinding.instance.addPostFrameCallback(afterLayout); + } + + void afterLayout(dynamic _) { + setState(() => height = 108); + Timer(Duration(milliseconds: 250), () => + setState(() => isDraw = true) + ); + } + + @override + Widget build(BuildContext context) { + return Container( + height: 108, + padding: EdgeInsets.only(left: 44, right: 44), + alignment: Alignment.bottomCenter, + child: AnimatedContainer( + height: height, + duration: Duration(milliseconds: 500), + curve: Curves.fastOutSlowIn, + child: isDraw + ? Row( + children: [ + Flexible( + child: actionButton( + image: sendImage, + title: S.of(context).send, + route: Routes.send + ) + ), + Flexible( + child: actionButton( + image: exchangeImage, + title: S.of(context).exchange, + route: Routes.exchange + ) + ), + Flexible( + child: actionButton( + image: buyImage, + title: 'Buy', + route: '' + ) + ) + ], + ) + : Offstage(), + ), + ); + } + + Widget actionButton({ + @required Image image, + @required String title, + @required String route}) { + + return Container( + width: double.infinity, + 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: Colors.white, + shape: BoxShape.circle + ), + child: image, + ), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: Text( + title, + style: TextStyle( + fontSize: 16, + color: PaletteDark.walletCardText + ), + ), + ) + ], + ), + ); + } +} \ No newline at end of file From 823030403a145fd24010c68efc41d4ea46070f04 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Thu, 16 Apr 2020 21:41:04 +0300 Subject: [PATCH 04/51] CWA-198 | added transaction history panel to dashboard page; added fiat currency symbol to transaction_info; changed date_section_raw, trade_row and transaction_raw --- assets/images/2.0x/coins.png | Bin 0 -> 971 bytes assets/images/2.0x/down_arrow.png | Bin 0 -> 428 bytes assets/images/2.0x/exchange.png | Bin 0 -> 1079 bytes assets/images/2.0x/filter_button.png | Bin 0 -> 1344 bytes assets/images/2.0x/menu_button.png | Bin 0 -> 226 bytes assets/images/2.0x/send.png | Bin 0 -> 582 bytes assets/images/2.0x/up_arrow.png | Bin 0 -> 429 bytes assets/images/3.0x/coins.png | Bin 0 -> 1409 bytes assets/images/3.0x/down_arrow.png | Bin 0 -> 559 bytes assets/images/3.0x/exchange.png | Bin 0 -> 1528 bytes assets/images/3.0x/filter_button.png | Bin 0 -> 1923 bytes assets/images/3.0x/menu_button.png | Bin 0 -> 293 bytes assets/images/3.0x/send.png | Bin 0 -> 836 bytes assets/images/3.0x/up_arrow.png | Bin 0 -> 479 bytes assets/images/coins.png | Bin 0 -> 600 bytes assets/images/down_arrow.png | Bin 0 -> 287 bytes assets/images/exchange.png | Bin 0 -> 588 bytes assets/images/filter_button.png | Bin 0 -> 693 bytes assets/images/menu_button.png | Bin 0 -> 165 bytes assets/images/send.png | Bin 0 -> 378 bytes assets/images/up_arrow.png | Bin 0 -> 292 bytes lib/palette.dart | 3 + lib/src/domain/common/transaction_info.dart | 2 +- lib/src/screens/dashboard/dashboard_page.dart | 33 +++- .../{ => widgets}/date_section_raw.dart | 6 +- .../widgets/trade_history_panel.dart | 179 ++++++++++++++++++ .../dashboard/{ => widgets}/trade_row.dart | 35 ++-- .../{ => widgets}/transaction_raw.dart | 50 ++--- 28 files changed, 255 insertions(+), 53 deletions(-) create mode 100644 assets/images/2.0x/coins.png create mode 100644 assets/images/2.0x/down_arrow.png create mode 100644 assets/images/2.0x/exchange.png create mode 100644 assets/images/2.0x/filter_button.png create mode 100644 assets/images/2.0x/menu_button.png create mode 100644 assets/images/2.0x/send.png create mode 100644 assets/images/2.0x/up_arrow.png create mode 100644 assets/images/3.0x/coins.png create mode 100644 assets/images/3.0x/down_arrow.png create mode 100644 assets/images/3.0x/exchange.png create mode 100644 assets/images/3.0x/filter_button.png create mode 100644 assets/images/3.0x/menu_button.png create mode 100644 assets/images/3.0x/send.png create mode 100644 assets/images/3.0x/up_arrow.png create mode 100644 assets/images/coins.png create mode 100644 assets/images/down_arrow.png create mode 100644 assets/images/exchange.png create mode 100644 assets/images/filter_button.png create mode 100644 assets/images/menu_button.png create mode 100644 assets/images/send.png create mode 100644 assets/images/up_arrow.png rename lib/src/screens/dashboard/{ => widgets}/date_section_raw.dart (89%) create mode 100644 lib/src/screens/dashboard/widgets/trade_history_panel.dart rename lib/src/screens/dashboard/{ => widgets}/trade_row.dart (71%) rename lib/src/screens/dashboard/{ => widgets}/transaction_raw.dart (60%) diff --git a/assets/images/2.0x/coins.png b/assets/images/2.0x/coins.png new file mode 100644 index 0000000000000000000000000000000000000000..c96e6e48c4ec2fea8f02e1302148928ee807273f GIT binary patch literal 971 zcmV;+12p`JP)Dx9F{3F@*SEo|BokQ+cGL?|q1N&{lmWL2pxO1eN*x*<0pJpo~XO1dFA z0pSJ)HX%)BcrS5UE3%!~p0U(VipCz#jNi|^Z$5`X2ppbWW=w!B;CxL2WEg-&{dDaf zhy6Xtn2nb(}Z&RFBOXozDxfCI8ZTL_|p4ClPOSIFK(ng~Jk`#EH>6)9x~ z+YF<2cB;c*xQ0y(hQaKngy?t`eqa%QsJE$r%McQ{X!%VcTbUZIip2o8A2L`2oxYel zGnYn*`wh-t<7JL5VgN>d|HZ~OT_(X|z7AB;aBAIYJNo#|!n9iq4>F8`g%L^P0%=!d z?Q0>{-{YJKi@^bCgdB~EzBM2?|3ZeH)Z0x=f0JPm7W33@9^6VWBFF0O@nez- zLWq26XR{TX#TEc&x#4>fmkJv-7LtL+0uR#~b$$pC#qJW*@t{#O0E==J4XeqC5St6> z;`J!=gFqRkp!_w>Rb;wTr_UQvS!e{1e^L~5zE|Lp!R_gYJw z+rAFqA@ zG%mv_2=oEPm?Z`S%3d0cpT5K20m0a|A>|sTxwrTHL1^U|g~hzrxtR;I=L)gVTqzL; zQMJ?pAQmc9A$vNYQZ?bL|M&q?V2CbioF?9lO_-n8Qy2#JWxGt~% zqd3Ax_z>WFevo^BfL0Ayd~_Z|{2)&KK`Q}VY1H#XEcO74bIiPIzVy4x^VxeT{La4M;D@!pkoQ4=tfkZ8iYe7T{#nXb&*%>>n#6teq zpdD78jiQYhguC4B&hx#6OAgrOc4ihd=6=b--R{iZcW>r>Z)OjmL4yYW7unIz2|geu z1Q;?rI+Ls{RT5IUNk?MBl`<*l@NcSMj}VwZA(GYh2=H;?>(Z-SuDt{nG=U}qPv5sV zfTvZtoN)Z!4k-F7Ya2-xxH=Z}?(pt?JAcy4w_t(PY0Ob&v82Xmh!tWAEYT9|m5X~# z#jfxREYT9&lQ}U!f)} zuOVo{DX9)T{QBi0jQyf2fsTI1e-GIgC7`xL#x%}jc1 zqqf1eCZJSz8A-`ilFsY9oyUxadL>U@&`plDRH z3*ULhQA~2Yr>ZZ-=8xp&r0}02;2A+pH+{;fKLM8TAT%5ae?Zhltz(dW^i`u>? zlU}E4T8-@!$`&kY{O*zpc%3Ke?8tKq~6J$l^Zq zb{;ztbj@gsw3eZf$qoTxm@~dM%ZDGmYta@mOinv>Xupa;6{`P*G53mdhGWlD$`p6JjQ?2fWPiYLMv zb2JE=m;JY{v_6c|);hv$SzrO%*R4!C7qz{8ge#R47{d0o(A*qZEMpyEvLK@fSM4iz z>4;XDw-#J|h^JfkG0_1 zA6^WYZ{D$^pwq#AN+6Dd8SD<-H#A+s+K1(~Z4W*6V#JQB5E|-vTozQI^Yb*%3%n!t xuhMHJn+iRbkA8u_NtP;J*0Sm~Xwcvv!rU?K5002ovPDHLkV1nw{_eB5z literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/filter_button.png b/assets/images/2.0x/filter_button.png new file mode 100644 index 0000000000000000000000000000000000000000..767e4e561526714275c9167a6635475d8e31622b GIT binary patch literal 1344 zcmV-G1;6@d*e8@1@IzZ zEQqZfF4a!kNOLEDRe-8s>;b-GjQw`teyQLZA*76o@(xaxL1u}-C6+_DGE`wc+maXC z2X5CPMN$!{Q51m7NR?155$Z8gAW?x-n0L+Ts<^~A$yiD^up^?!zVB}(X;p~`)L&tu zghKuK`|~vwx5@Y{71MLWcv&|pK0~bJ%5TT(6c~lHB;tv%@?b|Aj74hJmx1ReIPkFaqA655vJN;0{0^Pj5um+}YG2}=OclU!EpU^+A{-|`)z9WIu zaz;U%2FjgUQrjS{emh3=6GjkbUjujLvNo3rq`j2}?9B$+**sR`Dp_g6QmfWDIe& zM{%xpL7*Vt$%Jb~Av=lF3**Wr7aP7YR^n8Td1AJ4VB2It#+VgkR~*HQT2Yfg%veUo zA;M~7EUF7MZ5LLMZRlQte_8}doj}Bt9$p6CO<#@5ou6!v(1_XrM+8upX7 zC7Krv#u(0bMh0Ws$caV6j~T~=qo5`tC(41_*)~olrX?8VfjR;+SM<3MzQYr-r!xA; z;LRKHmOch~P!Yvc3PFaPAT|dAxnQwAG^w1>z0SAg{hvvzo8{C9-Akzpq;8h?W(vE; z+OxVq>SjJ;0~tr$Ypd~n(_nQH6Pww#B6jl7)L}IVlyxgo>xu4}zAy;0vfO$?r$biF zlLYMkdbu+jJ$hk2D9EhYe}Igk)roP(V~bhdRQKKc-lv|}*BxX4pLyfZ?QF)KYdND> z#P~YG;{Fkb-3f~8tVRzt>_GML#HC@HIx1x6BXP)v>lMs0-rJja#op@4FZw zd_G(KyMwzmbX0Np=GFf0d)~*oRj-T@Kzix5L-*@qX{dlW25EvHj)l&)v% zXYBlvR>lll;0^;aFX=RDm!IpN{Kf)p&>t%D#2lCge%z)>;4v5Hdc7mel^4Wr+J$>e z!2s7{piry9O1CZ*C9xGlal41&b}Q(!P_^W5<6lf}_Ig8;$oD0O#wK}M?uSrG3)Aqu z=@6Dz@p9U^lTNV9MLao{DdQxCIVbf+`OvCNIVrJf-Su9YqC|f0dYQKKi}Ir-AI1{= z5`jDk@*YK8l4~;wBw|QgXLKV0-fkaZ%B3wzBmV)tTlApnVGnu$00000V4T5^Y;NM&H|6fVg?2=RS;(M3{v?36l5$8 za(7}_cTVOdki(Mh=ig1u+{(8uD5zH~%B@@7Pz?l literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/send.png b/assets/images/2.0x/send.png new file mode 100644 index 0000000000000000000000000000000000000000..055ee615aee148e733dbd4e2b827e622529996a4 GIT binary patch literal 582 zcmV-M0=fN(P)WVsK-KE4hK(z_>8P6?y`D1T-v23mxAZ zg|vk>3~9@kkPI`te!usoZw7#jbo=mjNFPuXhm6EHFL7Oe>GeltmAK3R{#6P%SAxhI z00cl;1tN0*Rft>wR3LH#h(J7zORx`sCB(w_6CoHVh#s==Jc|o)5CBAbo-s10Ck8Y2 zp&3T)vRRpgr*+uEG?>lmLetL3oaO?i#Qi5B4zUtF95o|cX)$;GQ3E*dP#GaBF*azo zs?AgYS!&;ZMrsT4PzYk}C8V|qJa3$vIZ22{_wn79ENkZ2Hkp<@jRU}0RY1OM1)7u4 zT&%hP_uPg8&9U_M_4$z_w}48&;QR{;($bv9ati`Y>p($b*a1s(`Mt>OrFrNKAnACd zTCjt#jII#E#i1)FI4`HQuE3+X9W$2z7lFX-g z4{Tb~agoR&K@(gVkm*&c`U*P;<6Sb31Frz+lGwC>8Q=eyrjr!7t@%6%YH82VHw9tF zja@U2o8Mdoq4G|wY{3f`w@b0b)TCJuC&klIMpkUQ{cTtGwk#cEC)Kr3E2eTH4r!;tzC*rHpw|AkG@ATaM~beM_uTXo7gvqZy+xU z*V$M(L6sX2`GaGVGkK2|6GjoOp)?%LA|D_~BT}Q`$2ar7_YDyYq5b5fa{l(M?+H-_ zA-+;dRp{MErF=fF0Q|wt z2Bv}7A;P*+%7bYUmYX1sl<@5At^l}0QBeU)h@%Ujg;E|aFD>-I5^@o=x%(dxgX=bl z8AL+VN^^c6EI^x}&E4Y`oxBc?KuLMi#l?WLHErKMdZ3JvXksxBum1_KXNecgK=g2RU5EV*YBXQ{`Vw4V5kUtN0$pZAE z?@vT1E%3qp-@osI2DG!-qupap?=3KoAOdLo(VTxec;LZ5|5i($w7WOk&4gG-L(`2H+>p|BI%-&ms(0^xWKs%I=NZV-SGkomhdC{r zH4{V$#9Df-VL3rlrtOjtov0T3`|-0yn$vOkQ{7a{^IM9Jy?ejjXe3SNgebtqT64ao zMNpffhUV)JM8v^mbr2Iqg=Li&&^Wqi;iN*=@Bg8nIyE?#axR%#963seC*T-V6fJ8J zL<{u)$psQgds3-=lQRF|<7X#R(pr~7T}-#pc({A~nT(FT97@d;EeD>I-AO9!Vg0*; zv4vvXMy%7vdL#r#S&wxG`!|W+;PXQI?digo=ayDAzt+65g$6|;lPSvOc2WJC0FUP$rFt!b z7^}_s4a!gr)%TGn28qDfvMs9r@e$D2?(%rJp-m9u{?fu8D_>I=LSpk;k^Scc*K4g; zGc(sopKT{!PE9B>0VKq(7uCPsAXEo=V}M>+?!nZAq71{E$s%1q|H;M0eNolV@0?`= z_LssieE#O@)!s%%W=)T0ETKqt!-mP7g`$P1E_h8u&s$H5WF}b8a!uVGVzwS3vg(}! zLm2FzqN2{a%9Iez0y_ut^z;^QbW*b(7s)AWna8DPxsq>^E(J`>-lBvkI}iL$1Xo0< z_Q4=b3(?QeCqbpi(7DMh z6er4JCQ+bcITkqOvlhywgNlT!LQy+{Oc>@8@dc&#-erclNyjoLc$`}=XJ)q3=|7Vo z7YuXfgraMP`5>k$6kRmTZDW{Fj0tkpFo%LMR45JrT{g_ue*11KY4fv5q<$9D3qJ3V zP9hXXxtOs~bm7U3q2O^*R!N$PkmQl7zDT4@SGZ6txwxCau$aN0I9wa1fZ9Ug7DfjVRA{6kV-@l6L>e+7si`E{{+&{p7}&;P7sx?_e4% z6#ErDzp6zE#eqIP!nHcc1!UG@F4RFT09`iBZ9Y+-1$5akUmdY6WCJCa4Rde+C6^6z zZ~!Hj4Rde+!sRC`zyZX!)m6jX1$+^TBk)BijsWVOmpo*r5U?ZhKDNqWO0;NDH@b3a{ z^h>n60p>id{OKJ2AdR5kCZqu(g>DQkx*OUx7|5;~LGNbeKaas;c+D}dJ(8^$MScQ) z=7U&wBPC!Y7g&YEC_1(mKtfNs%94Z%9uwfvH literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/exchange.png b/assets/images/3.0x/exchange.png new file mode 100644 index 0000000000000000000000000000000000000000..52d78d21ee3aa73f1b5a63d7882cf5ae6de35fa6 GIT binary patch literal 1528 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 JPDHLkV1mN4hw%Ua literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/menu_button.png b/assets/images/3.0x/menu_button.png new file mode 100644 index 0000000000000000000000000000000000000000..97f28ae94c13c3d4ef3f87db32a2a34a8ca37e47 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^oItG0!3HF2);Jn~1PVMNiy0UcEkKyjb(&!UP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{w_}!$B+ufx04p~9WoGTTfhCxq=^DeYm^Rt z^a2PfFD+Bm5e3Ej+5U74{iCcSYLr_25&zO(CI#_H{7aLX%Wm9%PX z7h>^<)2-Ykk*>A&T@=ru?mV3}4~4Jp%$x0-cG@`p+lRTXeLG$M?P}q8@v$Ms?bwnF z$rEm^IP!jBjBv3>K=X?Y&o=*hs3GS(_vQ1$e$Q90cF%AB$0D+j<$u7}b@pwRj!8By mH-e0UjsEvdIU_jvC!6igBTm^%V&4LN!QkoY=d#Wzp$P!Sc5(Os literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/send.png b/assets/images/3.0x/send.png new file mode 100644 index 0000000000000000000000000000000000000000..f77c93aed1beb07e5f3df0daef8a20e07c09164e GIT binary patch literal 836 zcmV-K1H1f*P)Z?#F~I1_)m!WHLag zF+~})JHwRQ8)P#80w85@e(u(UbOs17CK!as8*DJnd72r9${2ej7*k3GdG{%Q9vRB?U1X8@#8Z~?`s5HhBTL}I79zoR>x_s(f&n8UZ|F%u%a3DHY1 zrp4m%{3;Wk4A{a!h#W+Xg9*jWy_71`+uH^Te}Ny^3fSAzo0}f~D$X9hw+Cn@pc#Q? z29N>9`t@>V-`-t2jbf2iK=BvSh$n<7wLbpr*}IMgPCCO9ZU&JIQm>#1dqK1^g(&j4 z8Gz(qaGOg#Ksk@Ddhh^1@nXqV!_Wl9mWiBvVxHr=P O0000KnArmxZgS>$R#GFG_AWH4C6Dpzl zm-1x${xA0Ve89Gg&{O*}HC4cfBUPmEI3Ls0WqmJzy_w26!l)H6pP$mPG)4qZ@tXO1LiH8)MbTR{-&?if!hs!sVe+@6g*^nC3)3Xf9zfS8q6k zgBBN5E!PxQ0Ms~u#asu3qihh8*U;Ns0`YwWge&}kxea0kz{!>I{hV^k~Yq Vz(DgB!~g&Q002ovPDHLkV1hj#ztjK# literal 0 HcmV?d00001 diff --git a/assets/images/coins.png b/assets/images/coins.png new file mode 100644 index 0000000000000000000000000000000000000000..8541ee94243aa3c093d31ecff2dbcc3a962337eb GIT binary patch literal 600 zcmV-e0;m0nP)Q|saq1)R2I53?5k@x?A3&V&V-bymlVvjTBjR8Tlkx^Qy0I9;1iV3c0_$Kx zfZpr>Rxp&Www{EBo^yIWe&^gvVoI(b-!o*IJ4CcaN~M($>9LK3a21gYeS@W}l@2#t z5g|1Ba#L+OP+W?b!a@{Ii`m*TA9E^ObZ}IUXPuebU#V0l%01M|U>DTg-b(sT}6;Hv=Zh`AX%J zAjG%jP=ecPQwbtHz&e6;hN${tVvvD7p~OcdWggtO7TFgBcZ^BJ_U>_~KNwU^A`inv zGeLeka7Jf_Wz`nhM*&^v+t9y|5+}T3z0Dv}zF#^&+N{j0C<@`#(?=R>nZ`1#N#-3S z%Z1id4u|XCtE;Y9(lUncNDN$8pZZNY<0th)cL@KWgL`C-yLvsm%-gatBIsR>6Dw2) zqAn#py?XV|i&;lsDL%6oi6}|%QI*=?Vbg4J3`9%`)^3!*(Famr8Nt?sZSF|#V2d(m z#cbJR%X+}+ttH`F+F$oz%Eu|l^!xqKlwmXoLzGID2M9KgD{yG875L}G)B#x88NQcmR_#@uUDi@7d(Ur9IGk``)6B5vN>7%gJm=@BSs{{DSGit!=ZDz|-X~%! hDtjkCxh?UCv3_TCTh`*eNkI2Ac)I$ztaD0e0sybYZbJY7 literal 0 HcmV?d00001 diff --git a/assets/images/exchange.png b/assets/images/exchange.png new file mode 100644 index 0000000000000000000000000000000000000000..ce2d3928f43a16df2952a26738dd5a63c5d68992 GIT binary patch literal 588 zcmV-S0<-;zP)66~>9Yyyyx3_ci-Q3K-2hdeb%oNzoJ`RRa#yCTZ1M~u7A97{^g2foiuP=_= zfRDnu&1CM{>T$(f{k8a00;?_PB5;r{zF@A~OeLlqS4v|da&RC(+?*VFGsPIP|AEuF zr@kI0W=u(lXhWx91r_D;yc&`z2|<>i6L2zDuoRS$1H3fpG?y~4;$N=lExk`8V>;-| z$E$N`^;=^R&Ii6+w+I1h_;~;1As#~X^i_~&w|qRST32zL_~!C>zIDIZigMYLBq4O= z2R%5xos_OyV4PncWbb!CSFzF_Js9PDLiN){INM$xFB+lQyHy4(-B#to`qJoWZQT@s z@^mmxsh>xF(8H65Ogpstg@%fCN*~|GL@1Oa@7{!?(G0ofoQyo#{v3fa8%v{W_4{xT zSa2R!AWBsIT%j$GYsg8@pOHwab&m&u2{_aM=%4__iV(A@#IW5FSXW_-?243Ax_SHs z95V$3K*BWSK(O{CHk0E%u|OHY)c>S9dAeAjE9i%Gfz`@v0@<`yLn?y$b<%NPYa3cu a9(@C2L&*S!X6_~c0000}5<%c0+i9gA(D2Xn;W zgA;pXU7k;62lmZqOhnrN2XJG;oP;9mOPRqB3hJ9T0a3Cqra>jxGV|_3!U_fXCh(tn zm%9n$BkF`XJV$RYwo#0-g3>r4@0*xItb}y7HW$Sg6^QwX$}UN3AZPZYnQ<2Xv(NmOzRcMM8bnf#@V`C!G`qgBb@cFfPkh+mGQjpi zs@VBE-7XXr9iU|ivbM^qm=u-L3wL`R*yHtAUn b>+<|7d4%(__($JO00000NkvXXu0mjf=;k!g literal 0 HcmV?d00001 diff --git a/assets/images/menu_button.png b/assets/images/menu_button.png new file mode 100644 index 0000000000000000000000000000000000000000..33a3e5c94f4da5b325f1434496fdf7eecc75496b GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y~!3HE1UzHvKQk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFK)#iyi(^Oy} z-9K}7k)X^0J$C;3v!1fTuD?&+nh|SeJBk0hgyakU&K0tpzeFQCt`?L6O=0kK^>bP0 Hl+XkK+@vj0 literal 0 HcmV?d00001 diff --git a/assets/images/send.png b/assets/images/send.png new file mode 100644 index 0000000000000000000000000000000000000000..aef504999fd9adf5462eaf0dd6bf132789716483 GIT binary patch literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAuq2eY-?C^Qa&%qO?zfrYrUI+GbEE| z|Ejf~W~-JfbaKoydtGX-r4s2N;AGYwlFxsm{mJRGg{O5M{_IJ(l=XF+>lwyJ%tD-H z(|$-SyS4sxO+3pKDdql&T+a%0cpCn{w~CWEkP+*4#*xdj!)iu$=2;~(VX@cD(V4c5 zQ<6&hzdv|weOgN(@Xm!l4N^LnR-6|4+t4)oTW9x*;~76))r!wM_ZR(8wOS~-v9^YB z;xv9Csi~jpVwUq4-bngaQD>fQwdefvZvJqWj?4RviwjyG8?BqUon!OT)V*$B%MQdP VIm~&QWCRQ<22WQ%mvv4FO#o|ak0k&A literal 0 HcmV?d00001 diff --git a/assets/images/up_arrow.png b/assets/images/up_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..35324017625653b282db32c7c1c5dfc954403ecd GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CH!3HFy_x^nYq&N#aB8wRqxP?KOkzv*x37{Zj zage(c!@6@aFM%AEbVpxD28NCO+i~#(mGkixeS{a zW7+-QFeS+xVcEbashD1u^~OQ@$`T=&tdo '${formatAmount(moneroAmountToString(amount: amount))} XMR'; - String fiatAmount() => _fiatAmount ?? ''; + String fiatAmount(String symbol) => _fiatAmount != null ? symbol + ' ' + _fiatAmount : ''; void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); } diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index fa7819f2f..a379d22ed 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -18,14 +18,15 @@ 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/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/dashboard/date_section_raw.dart'; -import 'package:cake_wallet/src/screens/dashboard/trade_row.dart'; -import 'package:cake_wallet/src/screens/dashboard/transaction_raw.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/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/wallet_card.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/buttons_widget.dart'; +import 'package:cake_wallet/src/screens/dashboard/widgets/trade_history_panel.dart'; class DashboardPage extends BasePage { final _bodyKey = GlobalKey(); @@ -115,6 +116,7 @@ class DashboardPageBody extends StatefulWidget { } class DashboardPageBodyState extends State { + final menuButton = Image.asset('assets/images/menu_button.png'); /*final _connectionStatusObserverKey = GlobalKey(); final _balanceObserverKey = GlobalKey(); final _balanceTitleObserverKey = GlobalKey(); @@ -136,7 +138,27 @@ class DashboardPageBodyState extends State { child: Column( children: [ Padding( - padding: EdgeInsets.only(left: 20, top: 78), + padding: EdgeInsets.only(top: 14), + child: Container( + width: double.infinity, + alignment: Alignment.centerRight, + child: SizedBox( + height: 37, + width: 37, + child: ButtonTheme( + minWidth: double.minPositive, + child: FlatButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + padding: EdgeInsets.all(0), + onPressed: () {}, + child: menuButton), + ), + ), + ) + ), + Padding( + padding: EdgeInsets.only(left: 20, top: 23), child: WalletCard(), ), Padding( @@ -144,8 +166,7 @@ class DashboardPageBodyState extends State { child: ButtonsWidget(), ), Expanded( - child: Container( - ) + child: TradeHistoryPanel() ) ], ), diff --git a/lib/src/screens/dashboard/date_section_raw.dart b/lib/src/screens/dashboard/widgets/date_section_raw.dart similarity index 89% rename from lib/src/screens/dashboard/date_section_raw.dart rename to lib/src/screens/dashboard/widgets/date_section_raw.dart index 86fc3ff06..edbc5c854 100644 --- a/lib/src/screens/dashboard/date_section_raw.dart +++ b/lib/src/screens/dashboard/widgets/date_section_raw.dart @@ -20,8 +20,8 @@ class DateSectionRaw extends StatelessWidget { final settingsStore = Provider.of(context); final currentLanguage = settingsStore.languageCode; final dateSectionDateFormat = settingsStore.getCurrentDateFormat( - formatUSA: "MMM d", - formatDefault: "d MMM"); + formatUSA: "yyyy MMM d", + formatDefault: "d MMM yyyy"); var title = ""; if (isToday) { @@ -39,7 +39,7 @@ class DateSectionRaw extends StatelessWidget { padding: const EdgeInsets.only(top: 10, bottom: 10), child: Center( child: Text(title, - style: TextStyle(fontSize: 16, color: Palette.wildDarkBlue))), + style: TextStyle(fontSize: 12, color: PaletteDark.historyPanelText))), ); } } diff --git a/lib/src/screens/dashboard/widgets/trade_history_panel.dart b/lib/src/screens/dashboard/widgets/trade_history_panel.dart new file mode 100644 index 000000000..2f4fad150 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/trade_history_panel.dart @@ -0,0 +1,179 @@ +import 'dart:async'; +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 'package:flutter/material.dart'; +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/generated/i18n.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 'date_section_raw.dart'; +import 'trade_row.dart'; +import 'transaction_raw.dart'; + +class TradeHistoryPanel extends StatefulWidget { + @override + TradeHistoryPanelState createState() => TradeHistoryPanelState(); +} + +class TradeHistoryPanelState extends State { + final _listObserverKey = GlobalKey(); + final _listKey = GlobalKey(); + + double panelHeight; + double screenHeight; + double opacity; + bool isDraw; + + @override + void initState() { + panelHeight = 0; + screenHeight = 0; + opacity = 0; + isDraw = false; + super.initState(); + WidgetsBinding.instance.addPostFrameCallback(afterLayout); + } + + void afterLayout(dynamic _) { + screenHeight = MediaQuery.of(context).size.height; + setState(() { + panelHeight = screenHeight; + opacity = 1; + }); + Timer(Duration(milliseconds: 350), () => + setState(() => isDraw = true) + ); + } + + @override + Widget build(BuildContext context) { + final actionListStore = Provider.of(context); + final settingsStore = Provider.of(context); + final transactionDateFormat = DateFormat("HH:mm"); + final filterButton = Image.asset('assets/images/filter_button.png'); + + return Container( + width: double.infinity, + alignment: Alignment.bottomCenter, + child: AnimatedContainer( + width: double.infinity, + height: panelHeight, + duration: Duration(milliseconds: 1000), + curve: Curves.fastOutSlowIn, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), + color: PaletteDark.historyPanel.withOpacity(opacity), + ), + child: isDraw + ? Container( + padding: EdgeInsets.only(top: 20, left: 20, right: 20), + child: Column( + children: [ + Container( + width: double.infinity, + height: 36, + margin: EdgeInsets.only(bottom: 10), + child: Stack( + alignment: Alignment.center, + children: [ + Text( + S.of(context).trade_history_title, + style: TextStyle( + fontSize: 20 + ), + ), + Positioned( + right: 0, + child: GestureDetector( + onTap: () {}, + child: filterButton, + ) + ) + ], + ), + ), + Observer( + key: _listObserverKey, + builder: (_) { + final items = actionListStore.items == null + ? [] + : actionListStore.items; + final itemsCount = items.length; + final symbol = settingsStore.fiatCurrency.toString(); + + return Expanded( + child: ListView.builder( + key: _listKey, + padding: EdgeInsets.only(bottom: 15), + itemCount: itemsCount, + itemBuilder: (context, index) { + + final item = items[index]; + + if (item is DateSectionItem) { + return DateSectionRaw(date: item.date); + } + + if (item is TransactionListItem) { + final transaction = item.transaction; + final savedDisplayMode = 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 = 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(); + } + ) + ); + }) + ], + ), + ) + : Offstage() + ), + ); + } +} \ No newline at end of file diff --git a/lib/src/screens/dashboard/trade_row.dart b/lib/src/screens/dashboard/widgets/trade_row.dart similarity index 71% rename from lib/src/screens/dashboard/trade_row.dart rename to lib/src/screens/dashboard/widgets/trade_row.dart index 75a3371bd..ce603c359 100644 --- a/lib/src/screens/dashboard/trade_row.dart +++ b/lib/src/screens/dashboard/widgets/trade_row.dart @@ -21,25 +21,25 @@ class TradeRow extends StatelessWidget { @override Widget build(BuildContext context) { - final amountCrypto = provider == ExchangeProviderDescription.xmrto - ? to.toString() - : from.toString(); + final amountCrypto = from.toString(); return InkWell( onTap: onTap, child: Container( - padding: EdgeInsets.only(top: 14, bottom: 14, left: 20, right: 20), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: PaletteDark.darkGrey, - width: 0.5, - style: BorderStyle.solid))), + padding: EdgeInsets.only(top: 5, bottom: 5), child: Row(children: [ - _getPoweredImage(provider), + Container( + height: 36, + width: 36, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: PaletteDark.historyPanelButton + ), + child: _getPoweredImage(provider), + ), Expanded( child: Padding( - padding: const EdgeInsets.only(left: 10, right: 10), + padding: const EdgeInsets.only(left: 10), child: Column( children: [ Row( @@ -48,23 +48,20 @@ class TradeRow extends StatelessWidget { Text('${from.toString()} → ${to.toString()}', style: TextStyle( fontSize: 16, - color: Theme.of(context) - .primaryTextTheme - .subhead - .color)), + )), formattedAmount != null ? Text(formattedAmount + ' ' + amountCrypto, style: const TextStyle( - fontSize: 16, color: Palette.purpleBlue)) + fontSize: 16)) : Container() ]), - SizedBox(height: 6), + SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(createdAtFormattedDate, style: const TextStyle( - fontSize: 13, color: Palette.blueGrey)) + fontSize: 14, color: PaletteDark.historyPanelText)) ]), ], ), diff --git a/lib/src/screens/dashboard/transaction_raw.dart b/lib/src/screens/dashboard/widgets/transaction_raw.dart similarity index 60% rename from lib/src/screens/dashboard/transaction_raw.dart rename to lib/src/screens/dashboard/widgets/transaction_raw.dart index 383db5218..bf970cd27 100644 --- a/lib/src/screens/dashboard/transaction_raw.dart +++ b/lib/src/screens/dashboard/widgets/transaction_raw.dart @@ -24,24 +24,25 @@ class TransactionRow extends StatelessWidget { return InkWell( onTap: onTap, child: Container( - padding: EdgeInsets.only(top: 14, bottom: 14, left: 20, right: 20), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: PaletteDark.darkGrey, - width: 0.5, - style: BorderStyle.solid))), + padding: EdgeInsets.only(top: 5, bottom: 5), child: Row(children: [ - Image.asset( - direction == TransactionDirection.incoming - ? 'assets/images/transaction_incoming.png' - : 'assets/images/transaction_outgoing.png', - height: 25, - width: 25), + Container( + height: 36, + width: 36, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: PaletteDark.historyPanelButton + ), + child: Image.asset( + direction == TransactionDirection.incoming + ? 'assets/images/down_arrow.png' + : 'assets/images/up_arrow.png'), + ), Expanded( child: Padding( - padding: const EdgeInsets.only(left: 10, right: 10), + padding: const EdgeInsets.only(left: 10), child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -53,24 +54,25 @@ class TransactionRow extends StatelessWidget { (isPending ? S.of(context).pending : ''), style: TextStyle( fontSize: 16, - color: Theme.of(context) - .primaryTextTheme - .subhead - .color)), - Text(formattedAmount, + )), + Text(direction == TransactionDirection.incoming + ? formattedAmount + : '- ' + formattedAmount, style: const TextStyle( - fontSize: 16, color: Palette.purpleBlue)) + fontSize: 16)) ]), - SizedBox(height: 6), + SizedBox(height: 5,), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(formattedDate, style: const TextStyle( - fontSize: 13, color: Palette.blueGrey)), - Text(formattedFiatAmount, + fontSize: 14, color: PaletteDark.historyPanelText)), + Text(direction == TransactionDirection.incoming + ? formattedFiatAmount + : '- ' + formattedFiatAmount, style: const TextStyle( - fontSize: 14, color: Palette.blueGrey)) + fontSize: 14, color: PaletteDark.historyPanelText)) ]), ], ), From 2a18f4a1e40a272f31cbaa2bdb17befe62137a31 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Fri, 17 Apr 2020 22:40:11 +0300 Subject: [PATCH 05/51] CWA-198 | removed buttons_widget, fixed wallet_card, trade_history_panel, date_section_raw, trade_raw, transaction_raw and dashboard_page --- lib/generated/i18n.dart | 23 + lib/src/screens/dashboard/dashboard_page.dart | 590 +----------------- .../dashboard/widgets/buttons_widget.dart | 118 ---- .../dashboard/widgets/date_section_raw.dart | 11 +- .../widgets/trade_history_panel.dart | 476 +++++++++++--- .../screens/dashboard/widgets/trade_row.dart | 8 +- .../dashboard/widgets/transaction_raw.dart | 8 +- .../dashboard/widgets/wallet_card.dart | 36 +- res/values/strings_de.arb | 3 +- res/values/strings_en.arb | 3 +- res/values/strings_es.arb | 3 +- res/values/strings_hi.arb | 3 +- res/values/strings_ja.arb | 3 +- res/values/strings_ko.arb | 3 +- res/values/strings_nl.arb | 3 +- res/values/strings_pl.arb | 3 +- res/values/strings_pt.arb | 3 +- res/values/strings_ru.arb | 3 +- res/values/strings_uk.arb | 3 +- res/values/strings_zh.arb | 3 +- 20 files changed, 474 insertions(+), 832 deletions(-) delete mode 100644 lib/src/screens/dashboard/widgets/buttons_widget.dart diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 845145783..99ece7cc0 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -39,6 +39,7 @@ class S implements WidgetsLocalizations { String get authentication => "Authentication"; String get available_balance => "Available Balance"; String get biometric_auth_reason => "Scan your fingerprint to authenticate"; + String get buy => "Buy"; String get cancel => "Cancel"; String get card_address => "Address:"; String get change => "Change"; @@ -439,6 +440,8 @@ class $de extends S { @override String get trade_details_fetching => "Holen"; @override + String get buy => "Kaufen"; + @override String get confirm_sending => "Bestätigen Sie das Senden"; @override String get settings_title => "die Einstellungen"; @@ -1009,6 +1012,8 @@ class $hi extends S { @override String get trade_details_fetching => "ला रहा है"; @override + String get buy => "खरीदें"; + @override String get confirm_sending => "भेजने की पुष्टि करें"; @override String get settings_title => "सेटिंग्स"; @@ -1579,6 +1584,8 @@ class $ru extends S { @override String get trade_details_fetching => "Получение"; @override + String get buy => "Купить"; + @override String get confirm_sending => "Подтвердить отправку"; @override String get settings_title => "Настройки"; @@ -2149,6 +2156,8 @@ class $ko extends S { @override String get trade_details_fetching => "가져 오는 중"; @override + String get buy => "구입"; + @override String get confirm_sending => "전송 확인"; @override String get settings_title => "설정"; @@ -2719,6 +2728,8 @@ class $pt extends S { @override String get trade_details_fetching => "Buscando"; @override + String get buy => "Comprar"; + @override String get confirm_sending => "Confirmar o envio"; @override String get settings_title => "Configurações"; @@ -3289,6 +3300,8 @@ class $uk extends S { @override String get trade_details_fetching => "Отримання"; @override + String get buy => "Купити"; + @override String get confirm_sending => "Підтвердити відправлення"; @override String get settings_title => "Налаштування"; @@ -3859,6 +3872,8 @@ class $ja extends S { @override String get trade_details_fetching => "フェッチング"; @override + String get buy => "購入"; + @override String get confirm_sending => "送信を確認"; @override String get settings_title => "設定"; @@ -4433,6 +4448,8 @@ class $pl extends S { @override String get trade_details_fetching => "Ujmujący"; @override + String get buy => "Kup"; + @override String get confirm_sending => "Potwierdź wysłanie"; @override String get settings_title => "Ustawienia"; @@ -5003,6 +5020,8 @@ class $es extends S { @override String get trade_details_fetching => "Cargando"; @override + String get buy => "Comprar"; + @override String get confirm_sending => "Confirmar envío"; @override String get settings_title => "Configuraciones"; @@ -5573,6 +5592,8 @@ class $nl extends S { @override String get trade_details_fetching => "Ophalen"; @override + String get buy => "Kopen"; + @override String get confirm_sending => "Bevestig verzending"; @override String get settings_title => "Instellingen"; @@ -6143,6 +6164,8 @@ class $zh extends S { @override String get trade_details_fetching => "正在取得"; @override + String get buy => "購買"; + @override String get confirm_sending => "确认发送"; @override String get settings_title => "设定值"; diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index a379d22ed..eca98a9e9 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -1,111 +1,18 @@ -import 'package:provider/provider.dart'; -import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; -import 'package:cake_wallet/src/domain/common/sync_status.dart'; -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:cake_wallet/src/stores/balance/balance_store.dart'; -import 'package:cake_wallet/src/stores/sync/sync_store.dart'; -import 'package:cake_wallet/src/stores/settings/settings_store.dart'; -import 'package:cake_wallet/src/stores/wallet/wallet_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/screens/base_page.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/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart'; -import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/wallet_card.dart'; -import 'package:cake_wallet/src/screens/dashboard/widgets/buttons_widget.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/trade_history_panel.dart'; class DashboardPage extends BasePage { final _bodyKey = GlobalKey(); - /*@override - Widget leading(BuildContext context) { - return SizedBox( - width: 30, - child: FlatButton( - padding: EdgeInsets.all(0), - onPressed: () => _presentWalletMenu(context), - child: Image.asset('assets/images/more.png', - color: Theme.of(context).primaryTextTheme.caption.color, - width: 30))); - } - - @override - Widget middle(BuildContext context) { - final walletStore = Provider.of(context); - - return Observer(builder: (_) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - walletStore.name, - style: TextStyle( - color: Theme.of(context).primaryTextTheme.title.color), - ), - SizedBox(height: 5), - Text( - walletStore.account != null ? '${walletStore.account.label}' : '', - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 10, - color: Theme.of(context).primaryTextTheme.title.color), - ), - ]); - }); - } - - @override - Widget trailing(BuildContext context) { - return SizedBox( - width: 20, - child: FlatButton( - padding: EdgeInsets.all(0), - onPressed: () => Navigator.of(context).pushNamed(Routes.settings), - child: Image.asset('assets/images/settings_icon.png', - color: Colors.grey, height: 20)), - ); - }*/ @override ObstructingPreferredSizeWidget appBar(BuildContext context) => null; @override Widget body(BuildContext context) => DashboardPageBody(key: _bodyKey); - - /*@override - Widget floatingActionButton(BuildContext context) => FloatingActionButton( - child: Image.asset('assets/images/exchange_icon.png', - color: Colors.white, height: 26, width: 22), - backgroundColor: Palette.floatingActionButton, - onPressed: () async => await Navigator.of(context, rootNavigator: true) - .pushNamed(Routes.exchange)); - - void _presentWalletMenu(BuildContext bodyContext) { - final walletMenu = WalletMenu(bodyContext); - - showDialog( - builder: (_) => Picker( - items: walletMenu.items, - selectedAtIndex: -1, - title: S.of(bodyContext).wallet_menu, - pickerHeight: 510, - onItemSelected: (String item) => - walletMenu.action(walletMenu.items.indexOf(item))), - context: bodyContext); - }*/ } class DashboardPageBody extends StatefulWidget { @@ -117,12 +24,6 @@ class DashboardPageBody extends StatefulWidget { class DashboardPageBodyState extends State { final menuButton = Image.asset('assets/images/menu_button.png'); - /*final _connectionStatusObserverKey = GlobalKey(); - final _balanceObserverKey = GlobalKey(); - final _balanceTitleObserverKey = GlobalKey(); - final _syncingObserverKey = GlobalKey(); - final _listObserverKey = GlobalKey(); - final _listKey = GlobalKey();*/ @override Widget build(BuildContext context) { @@ -161,491 +62,22 @@ class DashboardPageBodyState extends State { padding: EdgeInsets.only(left: 20, top: 23), child: WalletCard(), ), - Padding( - padding: EdgeInsets.only(top: 28), - child: ButtonsWidget(), - ), Expanded( - child: TradeHistoryPanel() + child: Stack( + alignment: Alignment.topCenter, + fit: StackFit.expand, + children: [ + Positioned( + top: 28, + left: 0, + child: TradeHistoryPanel() + ), + ], + ) ) ], ), ), ); - - /*final balanceStore = Provider.of(context); - final actionListStore = Provider.of(context); - final syncStore = Provider.of(context); - final settingsStore = Provider.of(context); - final transactionDateFormat = settingsStore.getCurrentDateFormat( - formatUSA: "MMMM d, yyyy, HH:mm", - formatDefault: "d MMMM yyyy, HH:mm"); - - return Observer( - key: _listObserverKey, - builder: (_) { - final items = actionListStore.items == null - ? [] - : actionListStore.items; - final itemsCount = items.length + 2; - - return ListView.builder( - key: _listKey, - padding: EdgeInsets.only(bottom: 15), - itemCount: itemsCount, - itemBuilder: (context, index) { - if (index == 0) { - return Container( - margin: EdgeInsets.only(bottom: 20), - decoration: BoxDecoration( - color: Theme.of(context).backgroundColor, - boxShadow: [ - BoxShadow( - color: Palette.shadowGreyWithOpacity, - blurRadius: 10, - offset: Offset(0, 12)) - ]), - child: Column( - children: [ - Observer( - key: _syncingObserverKey, - builder: (_) { - final status = syncStore.status; - final statusText = status.title(); - final progress = syncStore.status.progress(); - final isFialure = status is FailedSyncStatus; - - var descriptionText = ''; - - if (status is SyncingSyncStatus) { - descriptionText = S - .of(context) - .Blocks_remaining( - syncStore.status.toString()); - } - - if (status is FailedSyncStatus) { - descriptionText = S - .of(context) - .please_try_to_connect_to_another_node; - } - - return Container( - child: Column( - children: [ - SizedBox( - height: 3, - child: LinearProgressIndicator( - backgroundColor: Palette.separator, - valueColor: - AlwaysStoppedAnimation( - Palette.cakeGreen), - value: progress, - ), - ), - SizedBox(height: 10), - Text(statusText, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: isFialure - ? Palette.failure - : Palette.cakeGreen)), - Text(descriptionText, - style: TextStyle( - fontSize: 11, - color: Palette.wildDarkBlue, - height: 2.0)) - ], - ), - ); - }), - GestureDetector( - onTapUp: (_) => balanceStore.isReversing = false, - onTapDown: (_) => balanceStore.isReversing = true, - child: Container( - padding: EdgeInsets.only(top: 40, bottom: 40), - color: Colors.transparent, - child: Column( - children: [ - Container(width: double.infinity), - Observer( - key: _balanceTitleObserverKey, - builder: (_) { - final savedDisplayMode = - settingsStore.balanceDisplayMode; - final displayMode = balanceStore - .isReversing - ? (savedDisplayMode == - BalanceDisplayMode - .availableBalance - ? BalanceDisplayMode.fullBalance - : BalanceDisplayMode - .availableBalance) - : savedDisplayMode; - - return Text(displayMode.toString(), - style: TextStyle( - color: Palette.violet, - fontSize: 16)); - }), - Observer( - key: _connectionStatusObserverKey, - builder: (_) { - final savedDisplayMode = - settingsStore.balanceDisplayMode; - var balance = '---'; - final displayMode = balanceStore - .isReversing - ? (savedDisplayMode == - BalanceDisplayMode - .availableBalance - ? BalanceDisplayMode.fullBalance - : BalanceDisplayMode - .availableBalance) - : savedDisplayMode; - - if (displayMode == - BalanceDisplayMode.availableBalance) { - balance = - balanceStore.unlockedBalance ?? - '0.0'; - } - - if (displayMode == - BalanceDisplayMode.fullBalance) { - balance = - balanceStore.fullBalance ?? '0.0'; - } - - return Text( - balance, - style: TextStyle( - color: Theme.of(context) - .primaryTextTheme - .caption - .color, - fontSize: 42), - ); - }), - Padding( - padding: EdgeInsets.only(top: 7), - child: Observer( - key: _balanceObserverKey, - builder: (_) { - final savedDisplayMode = - settingsStore.balanceDisplayMode; - final displayMode = - balanceStore.isReversing - ? (savedDisplayMode == - BalanceDisplayMode - .availableBalance - ? BalanceDisplayMode - .fullBalance - : BalanceDisplayMode - .availableBalance) - : savedDisplayMode; - final symbol = settingsStore - .fiatCurrency - .toString(); - var balance = '---'; - - if (displayMode == - BalanceDisplayMode - .availableBalance) { - balance = - '${balanceStore.fiatUnlockedBalance} $symbol'; - } - - if (displayMode == - BalanceDisplayMode.fullBalance) { - balance = - '${balanceStore.fiatFullBalance} $symbol'; - } - - return Text(balance, - style: TextStyle( - color: Palette.wildDarkBlue, - fontSize: 16)); - })) - ], - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 20, right: 20, bottom: 30), - child: Container( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: PrimaryImageButton( - image: Image.asset( - 'assets/images/send_icon.png', - height: 25, - width: 25), - text: S.of(context).send, - onPressed: () => Navigator.of(context, - rootNavigator: true) - .pushNamed(Routes.send), - color: Theme.of(context) - .primaryTextTheme - .button - .backgroundColor, - borderColor: Theme.of(context) - .primaryTextTheme - .button - .decorationColor, - )), - SizedBox(width: 10), - Expanded( - child: PrimaryImageButton( - image: Image.asset( - 'assets/images/receive_icon.png', - height: 25, - width: 25), - text: S.of(context).receive, - onPressed: () => Navigator.of(context, - rootNavigator: true) - .pushNamed(Routes.receive), - color: Theme.of(context) - .accentTextTheme - .caption - .backgroundColor, - borderColor: Theme.of(context) - .accentTextTheme - .caption - .decorationColor, - )) - ], - ), - )), - ], - ), - ); - } - - if (index == 1 && actionListStore.totalCount > 0) { - return Padding( - padding: EdgeInsets.only(right: 20, top: 10, bottom: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - PopupMenuButton( - itemBuilder: (context) => [ - PopupMenuItem( - enabled: false, - value: -1, - child: Text(S.of(context).transactions, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Theme.of(context).primaryTextTheme.caption.color))), - PopupMenuItem( - value: 0, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text(S.of(context).incoming), - Checkbox( - value: actionListStore - .transactionFilterStore - .displayIncoming, - onChanged: (value) => - actionListStore - .transactionFilterStore - .toggleIncoming(), - ) - ]))), - PopupMenuItem( - value: 1, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text(S.of(context).outgoing), - Checkbox( - value: actionListStore - .transactionFilterStore - .displayOutgoing, - onChanged: (value) => - actionListStore - .transactionFilterStore - .toggleOutgoing(), - ) - ]))), - PopupMenuItem( - value: 2, - child: - Text(S.of(context).transactions_by_date)), - PopupMenuDivider(), - PopupMenuItem( - enabled: false, - value: -1, - child: Text(S.of(context).trades, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Theme.of(context).primaryTextTheme.caption.color))), - PopupMenuItem( - value: 3, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text('XMR.TO'), - Checkbox( - value: actionListStore - .tradeFilterStore - .displayXMRTO, - onChanged: (value) => - actionListStore - .tradeFilterStore - .toggleDisplayExchange( - ExchangeProviderDescription - .xmrto), - ) - ]))), - PopupMenuItem( - value: 4, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text('Change.NOW'), - Checkbox( - value: actionListStore - .tradeFilterStore - .displayChangeNow, - onChanged: (value) => - actionListStore - .tradeFilterStore - .toggleDisplayExchange( - ExchangeProviderDescription - .changeNow), - ) - ]))), - PopupMenuItem( - value: 5, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text('MorphToken'), - Checkbox( - value: actionListStore - .tradeFilterStore - .displayMorphToken, - onChanged: (value) => - actionListStore - .tradeFilterStore - .toggleDisplayExchange( - ExchangeProviderDescription - .morphToken), - ) - ]))) - ], - child: Text(S.of(context).filters, - style: TextStyle( - fontSize: 16.0, - color: Theme.of(context) - .primaryTextTheme - .subtitle - .color)), - onSelected: (item) async { - if (item == 2) { - final List picked = - await date_rage_picker.showDatePicker( - context: context, - initialFirstDate: DateTime.now() - .subtract(Duration(days: 1)), - initialLastDate: (DateTime.now()), - firstDate: DateTime(2015), - lastDate: DateTime.now() - .add(Duration(days: 1))); - - if (picked != null && picked.length == 2) { - actionListStore.transactionFilterStore - .changeStartDate(picked.first); - actionListStore.transactionFilterStore - .changeEndDate(picked.last); - } - } - }, - ) - ]), - ); - } - - index -= 2; - - if (index < 0 || index >= items.length) { - return Container(); - } - - final item = items[index]; - - if (item is DateSectionItem) { - return DateSectionRaw(date: item.date); - } - - if (item is TransactionListItem) { - final transaction = item.transaction; - final savedDisplayMode = settingsStore.balanceDisplayMode; - final formattedAmount = - savedDisplayMode == BalanceDisplayMode.hiddenBalance - ? '---' - : transaction.amountFormatted(); - final formattedFiatAmount = - savedDisplayMode == BalanceDisplayMode.hiddenBalance - ? '---' - : transaction.fiatAmount(); - - 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 = 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(); - }); - });*/ } } diff --git a/lib/src/screens/dashboard/widgets/buttons_widget.dart b/lib/src/screens/dashboard/widgets/buttons_widget.dart deleted file mode 100644 index cef410fdf..000000000 --- a/lib/src/screens/dashboard/widgets/buttons_widget.dart +++ /dev/null @@ -1,118 +0,0 @@ -import 'dart:async'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/routes.dart'; - -class ButtonsWidget extends StatefulWidget { - @override - ButtonsWidgetState createState() => ButtonsWidgetState(); -} - -class ButtonsWidgetState extends State { - final sendImage = Image.asset('assets/images/send.png'); - final exchangeImage = Image.asset('assets/images/exchange.png'); - final buyImage = Image.asset('assets/images/coins.png'); - - double height; - bool isDraw; - - @override - void initState() { - height = 0; - isDraw = false; - super.initState(); - WidgetsBinding.instance.addPostFrameCallback(afterLayout); - } - - void afterLayout(dynamic _) { - setState(() => height = 108); - Timer(Duration(milliseconds: 250), () => - setState(() => isDraw = true) - ); - } - - @override - Widget build(BuildContext context) { - return Container( - height: 108, - padding: EdgeInsets.only(left: 44, right: 44), - alignment: Alignment.bottomCenter, - child: AnimatedContainer( - height: height, - duration: Duration(milliseconds: 500), - curve: Curves.fastOutSlowIn, - child: isDraw - ? Row( - children: [ - Flexible( - child: actionButton( - image: sendImage, - title: S.of(context).send, - route: Routes.send - ) - ), - Flexible( - child: actionButton( - image: exchangeImage, - title: S.of(context).exchange, - route: Routes.exchange - ) - ), - Flexible( - child: actionButton( - image: buyImage, - title: 'Buy', - route: '' - ) - ) - ], - ) - : Offstage(), - ), - ); - } - - Widget actionButton({ - @required Image image, - @required String title, - @required String route}) { - - return Container( - width: double.infinity, - 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: Colors.white, - shape: BoxShape.circle - ), - child: image, - ), - ), - Padding( - padding: EdgeInsets.only(top: 10), - child: Text( - title, - style: TextStyle( - fontSize: 16, - color: PaletteDark.walletCardText - ), - ), - ) - ], - ), - ); - } -} \ No newline at end of file diff --git a/lib/src/screens/dashboard/widgets/date_section_raw.dart b/lib/src/screens/dashboard/widgets/date_section_raw.dart index edbc5c854..1fc0b4452 100644 --- a/lib/src/screens/dashboard/widgets/date_section_raw.dart +++ b/lib/src/screens/dashboard/widgets/date_section_raw.dart @@ -35,11 +35,12 @@ class DateSectionRaw extends StatelessWidget { title = dateSectionDateFormat.format(date); } - return Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10), - child: Center( - child: Text(title, - style: TextStyle(fontSize: 12, color: PaletteDark.historyPanelText))), + return Container( + padding: EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20), + alignment: Alignment.center, + color: PaletteDark.historyPanel, + child: Text(title, + style: TextStyle(fontSize: 12, color: PaletteDark.historyPanelText)) ); } } diff --git a/lib/src/screens/dashboard/widgets/trade_history_panel.dart b/lib/src/screens/dashboard/widgets/trade_history_panel.dart index 2f4fad150..b1716c9de 100644 --- a/lib/src/screens/dashboard/widgets/trade_history_panel.dart +++ b/lib/src/screens/dashboard/widgets/trade_history_panel.dart @@ -1,10 +1,11 @@ -import 'dart:async'; import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; +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: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 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -15,6 +16,7 @@ import 'package:cake_wallet/routes.dart'; import 'date_section_raw.dart'; import 'trade_row.dart'; import 'transaction_raw.dart'; +import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker; class TradeHistoryPanel extends StatefulWidget { @override @@ -27,15 +29,11 @@ class TradeHistoryPanelState extends State { double panelHeight; double screenHeight; - double opacity; - bool isDraw; @override void initState() { panelHeight = 0; screenHeight = 0; - opacity = 0; - isDraw = false; super.initState(); WidgetsBinding.instance.addPostFrameCallback(afterLayout); } @@ -44,11 +42,7 @@ class TradeHistoryPanelState extends State { screenHeight = MediaQuery.of(context).size.height; setState(() { panelHeight = screenHeight; - opacity = 1; }); - Timer(Duration(milliseconds: 350), () => - setState(() => isDraw = true) - ); } @override @@ -56,123 +50,399 @@ class TradeHistoryPanelState extends State { final actionListStore = Provider.of(context); final settingsStore = Provider.of(context); final transactionDateFormat = DateFormat("HH:mm"); - final filterButton = Image.asset('assets/images/filter_button.png'); return Container( - width: double.infinity, + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, alignment: Alignment.bottomCenter, child: AnimatedContainer( - width: double.infinity, + width: MediaQuery.of(context).size.width, height: panelHeight, - duration: Duration(milliseconds: 1000), + duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn, - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), - color: PaletteDark.historyPanel.withOpacity(opacity), - ), - child: isDraw - ? Container( - padding: EdgeInsets.only(top: 20, left: 20, right: 20), - child: Column( - children: [ - Container( - width: double.infinity, - height: 36, - margin: EdgeInsets.only(bottom: 10), - child: Stack( - alignment: Alignment.center, - children: [ - Text( - S.of(context).trade_history_title, - style: TextStyle( - fontSize: 20 - ), - ), - Positioned( - right: 0, - child: GestureDetector( - onTap: () {}, - child: filterButton, - ) - ) - ], - ), - ), - Observer( + child: CustomScrollView( + slivers: [ + SliverPersistentHeader( + delegate: ButtonHeader(), + pinned: true, + floating: false, + ), + Observer( key: _listObserverKey, builder: (_) { final items = actionListStore.items == null ? [] : actionListStore.items; - final itemsCount = items.length; + final itemsCount = items.length + 1; final symbol = settingsStore.fiatCurrency.toString(); + double freeSpaceHeight = MediaQuery.of(context).size.height - 496; // FIXME - return Expanded( - child: ListView.builder( - key: _listKey, - padding: EdgeInsets.only(bottom: 15), - itemCount: itemsCount, - itemBuilder: (context, index) { + return SliverList( + key: _listKey, + delegate: SliverChildBuilderDelegate( + (context, index) { - final item = items[index]; + if (index == itemsCount - 1) { + freeSpaceHeight = freeSpaceHeight >= 0 ? freeSpaceHeight : 0; - if (item is DateSectionItem) { - return DateSectionRaw(date: item.date); - } + return Container( + height: freeSpaceHeight, + width: MediaQuery.of(context).size.width, + color: PaletteDark.historyPanel, + ); + } - if (item is TransactionListItem) { - final transaction = item.transaction; - final savedDisplayMode = settingsStore.balanceDisplayMode; - final formattedAmount = - savedDisplayMode == BalanceDisplayMode.hiddenBalance - ? '---' - : transaction.amountFormatted(); - final formattedFiatAmount = - savedDisplayMode == BalanceDisplayMode.hiddenBalance - ? '---' - : transaction.fiatAmount(symbol); + final item = items[index]; - 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 DateSectionItem) { + freeSpaceHeight -= 32; // FIXME + return DateSectionRaw(date: item.date); + } - if (item is TradeListItem) { - final trade = item.trade; - final savedDisplayMode = settingsStore.balanceDisplayMode; - final formattedAmount = trade.amount != null - ? savedDisplayMode == BalanceDisplayMode.hiddenBalance - ? '---' - : trade.amountFormatted() - : trade.amount; + if (item is TransactionListItem) { + freeSpaceHeight -= 45; // FIXME + final transaction = item.transaction; + final savedDisplayMode = settingsStore.balanceDisplayMode; + final formattedAmount = + savedDisplayMode == BalanceDisplayMode.hiddenBalance + ? '---' + : transaction.amountFormatted(); + final formattedFiatAmount = + savedDisplayMode == BalanceDisplayMode.hiddenBalance + ? '---' + : transaction.fiatAmount(symbol); - 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 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); + } - return Container(); - } - ) + if (item is TradeListItem) { + freeSpaceHeight -= 45; // FIXME + final trade = item.trade; + final savedDisplayMode = 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: PaletteDark.historyPanel + ); + }, + + childCount: itemsCount + ) ); }) - ], - ), + ], ) - : Offstage() + ), + ); + } +} + +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'); + final filterButton = Image.asset('assets/images/filter_button.png'); + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + final actionListStore = Provider.of(context); + final historyPanelWidth = MediaQuery.of(context).size.width; + + double buttonsOpacity = 1 - shrinkOffset / (maxExtent - minExtent); + double buttonsHeight = maxExtent - minExtent - shrinkOffset; + + buttonsOpacity = buttonsOpacity >= 0 ? buttonsOpacity : 0; + buttonsHeight = buttonsHeight >= 0 ? buttonsHeight : 0; + + return Stack( + fit: StackFit.expand, + overflow: Overflow.visible, + children: [ + Opacity( + opacity: buttonsOpacity, + child: Container( + height: buttonsHeight, + padding: EdgeInsets.only(left: 44, right: 44), + 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 + ) + ), + Flexible( + child: actionButton( + context: context, + image: buyImage, + title: S.of(context).buy, + route: '' + ) + ) + ], + ), + ), + ), + Positioned( + top: buttonsHeight, + left: 0, + child: Container( + width: historyPanelWidth, + height: 66, + padding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), + color: PaletteDark.historyPanel, + ), + child: Stack( + alignment: Alignment.center, + children: [ + Text( + S.of(context).trade_history_title, + style: TextStyle( + fontSize: 20, + color: Colors.white + ), + ), + Positioned( + right: 0, + child: PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + enabled: false, + value: -1, + child: Text(S.of(context).transactions, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).primaryTextTheme.caption.color))), + PopupMenuItem( + value: 0, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text(S.of(context).incoming), + Checkbox( + value: actionListStore + .transactionFilterStore + .displayIncoming, + onChanged: (value) => + actionListStore + .transactionFilterStore + .toggleIncoming(), + ) + ]))), + PopupMenuItem( + value: 1, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text(S.of(context).outgoing), + Checkbox( + value: actionListStore + .transactionFilterStore + .displayOutgoing, + onChanged: (value) => + actionListStore + .transactionFilterStore + .toggleOutgoing(), + ) + ]))), + PopupMenuItem( + value: 2, + child: + Text(S.of(context).transactions_by_date)), + PopupMenuDivider(), + PopupMenuItem( + enabled: false, + value: -1, + child: Text(S.of(context).trades, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).primaryTextTheme.caption.color))), + PopupMenuItem( + value: 3, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text('XMR.TO'), + Checkbox( + value: actionListStore + .tradeFilterStore + .displayXMRTO, + onChanged: (value) => + actionListStore + .tradeFilterStore + .toggleDisplayExchange( + ExchangeProviderDescription + .xmrto), + ) + ]))), + PopupMenuItem( + value: 4, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text('Change.NOW'), + Checkbox( + value: actionListStore + .tradeFilterStore + .displayChangeNow, + onChanged: (value) => + actionListStore + .tradeFilterStore + .toggleDisplayExchange( + ExchangeProviderDescription + .changeNow), + ) + ]))), + PopupMenuItem( + value: 5, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text('MorphToken'), + Checkbox( + value: actionListStore + .tradeFilterStore + .displayMorphToken, + onChanged: (value) => + actionListStore + .tradeFilterStore + .toggleDisplayExchange( + ExchangeProviderDescription + .morphToken), + ) + ]))) + ], + child: filterButton, + onSelected: (item) async { + if (item == 2) { + final List picked = + await date_rage_picker.showDatePicker( + context: context, + initialFirstDate: DateTime.now() + .subtract(Duration(days: 1)), + initialLastDate: (DateTime.now()), + firstDate: DateTime(2015), + lastDate: DateTime.now() + .add(Duration(days: 1))); + + if (picked != null && picked.length == 2) { + actionListStore.transactionFilterStore + .changeStartDate(picked.first); + actionListStore.transactionFilterStore + .changeEndDate(picked.last); + } + } + }, + ), + ) + ], + ), + ) + ) + ], + ); + } + + @override + double get maxExtent => 174; + + @override + double get minExtent => 66; + + @override + bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; + + Widget actionButton({ + BuildContext context, + @required Image image, + @required String title, + @required String route}) { + + return Container( + width: MediaQuery.of(context).size.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + if (route.isNotEmpty) { + Navigator.of(context, rootNavigator: true).pushNamed(route); + } + }, + child: Container( + height: 48, + width: 48, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle + ), + child: image, + ), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: Text( + title, + style: TextStyle( + fontSize: 16, + color: PaletteDark.walletCardText + ), + ), + ) + ], ), ); } diff --git a/lib/src/screens/dashboard/widgets/trade_row.dart b/lib/src/screens/dashboard/widgets/trade_row.dart index ce603c359..6927638b1 100644 --- a/lib/src/screens/dashboard/widgets/trade_row.dart +++ b/lib/src/screens/dashboard/widgets/trade_row.dart @@ -26,7 +26,8 @@ class TradeRow extends StatelessWidget { return InkWell( onTap: onTap, child: Container( - padding: EdgeInsets.only(top: 5, bottom: 5), + color: PaletteDark.historyPanel, + padding: EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), child: Row(children: [ Container( height: 36, @@ -48,11 +49,14 @@ class TradeRow extends StatelessWidget { Text('${from.toString()} → ${to.toString()}', style: TextStyle( fontSize: 16, + color: Colors.white )), formattedAmount != null ? Text(formattedAmount + ' ' + amountCrypto, style: const TextStyle( - fontSize: 16)) + fontSize: 16, + color: Colors.white + )) : Container() ]), SizedBox(height: 5), diff --git a/lib/src/screens/dashboard/widgets/transaction_raw.dart b/lib/src/screens/dashboard/widgets/transaction_raw.dart index bf970cd27..824cd167c 100644 --- a/lib/src/screens/dashboard/widgets/transaction_raw.dart +++ b/lib/src/screens/dashboard/widgets/transaction_raw.dart @@ -24,7 +24,8 @@ class TransactionRow extends StatelessWidget { return InkWell( onTap: onTap, child: Container( - padding: EdgeInsets.only(top: 5, bottom: 5), + color: PaletteDark.historyPanel, + padding: EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), child: Row(children: [ Container( height: 36, @@ -54,12 +55,15 @@ class TransactionRow extends StatelessWidget { (isPending ? S.of(context).pending : ''), style: TextStyle( fontSize: 16, + color: Colors.white )), Text(direction == TransactionDirection.incoming ? formattedAmount : '- ' + formattedAmount, style: const TextStyle( - fontSize: 16)) + fontSize: 16, + color: Colors.white + )) ]), SizedBox(height: 5,), Row( diff --git a/lib/src/screens/dashboard/widgets/wallet_card.dart b/lib/src/screens/dashboard/widgets/wallet_card.dart index d086b9c53..3177e8abe 100644 --- a/lib/src/screens/dashboard/widgets/wallet_card.dart +++ b/lib/src/screens/dashboard/widgets/wallet_card.dart @@ -159,7 +159,8 @@ class WalletCardState extends State { walletStore.name, style: TextStyle( fontSize: 20, - fontWeight: FontWeight.bold + fontWeight: FontWeight.bold, + color: Colors.white ), ), SizedBox(width: 10), @@ -243,7 +244,8 @@ class WalletCardState extends State { Text( balance, style: TextStyle( - fontSize: 28 + fontSize: 28, + color: Colors.white ), ) ], @@ -251,7 +253,8 @@ class WalletCardState extends State { Text( fiatBalance, style: TextStyle( - fontSize: 14 + fontSize: 14, + color: Colors.white ), ) ], @@ -276,7 +279,8 @@ class WalletCardState extends State { Text( descriptionText, style: TextStyle( - fontSize: 14 + fontSize: 14, + color: Colors.white ), ) ], @@ -299,6 +303,7 @@ class WalletCardState extends State { final walletStore = Provider.of(context); final rightArrow = Image.asset('assets/images/right_arrow.png'); double messageBoxHeight = 0; + double messageBoxWidth = cardWidth - 30; return Observer( key: _addressObserverKey, @@ -308,6 +313,7 @@ class WalletCardState extends State { height: cardHeight, alignment: Alignment.topCenter, child: Stack( + alignment: Alignment.topRight, children: [ Container( width: cardWidth, @@ -328,7 +334,7 @@ class WalletCardState extends State { children: [ Expanded( child: Container( - height: 72, + height: 84, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, @@ -344,10 +350,16 @@ class WalletCardState extends State { onTap: () { Clipboard.setData(ClipboardData( text: walletStore.subaddress.address)); - _addressObserverKey.currentState.setState(() => messageBoxHeight = 20); + _addressObserverKey.currentState.setState(() { + messageBoxHeight = 20; + messageBoxWidth = cardWidth; + }); Timer(Duration(milliseconds: 1000), () { try { - _addressObserverKey.currentState.setState(() => messageBoxHeight = 0); + _addressObserverKey.currentState.setState(() { + messageBoxHeight = 0; + messageBoxWidth = cardWidth - 30; + }); } catch(e) { print('${e.toString()}'); } @@ -357,6 +369,7 @@ class WalletCardState extends State { walletStore.subaddress.address, style: TextStyle( fontSize: 14, + color: Colors.white ), ), ) @@ -364,10 +377,10 @@ class WalletCardState extends State { ), ) ), - SizedBox(width: 20), + SizedBox(width: 10), Container( - width: 72, - height: 72, + width: 84, + height: 84, child: QrImage( data: walletStore.subaddress.address, backgroundColor: Colors.transparent, @@ -393,6 +406,7 @@ class WalletCardState extends State { S.current.subaddresses, style: TextStyle( fontSize: 14, + color: Colors.white ), ), rightArrow @@ -404,7 +418,7 @@ class WalletCardState extends State { ), ), AnimatedContainer( - width: cardWidth, + width: messageBoxWidth, height: messageBoxHeight, alignment: Alignment.center, duration: Duration(milliseconds: 500), diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 572ccbbbd..a7e82893f 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "XMR-Empfänger erkannt", "openalias_alert_content" : "Sie senden Geld an\n${recipient_name}", - "card_address" : "Adresse:" + "card_address" : "Adresse:", + "buy" : "Kaufen" } \ No newline at end of file diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 469b08f28..5681dc513 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "XMR Recipient Detected", "openalias_alert_content" : "You will be sending funds to\n${recipient_name}", - "card_address" : "Address:" + "card_address" : "Address:", + "buy" : "Buy" } \ No newline at end of file diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index be8257b32..260df0433 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "Destinatario XMR detectado", "openalias_alert_content" : "Enviará fondos a\n${recipient_name}", - "card_address" : "Dirección:" + "card_address" : "Dirección:", + "buy" : "Comprar" } \ No newline at end of file diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index b4a8763ec..85b6f080e 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "XMR प्राप्तकर्ता का पता लगाया", "openalias_alert_content" : "आपको धनराशि भेजी जाएगी\n${recipient_name}", - "card_address" : "पता:" + "card_address" : "पता:", + "buy" : "खरीदें" } \ No newline at end of file diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index c6e76cc1f..a291e6a12 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "XMR受信者が検出されました", "openalias_alert_content" : "に送金します\n${recipient_name}", - "card_address" : "住所:" + "card_address" : "住所:", + "buy" : "購入" } \ No newline at end of file diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 8b470908c..50acfcbb1 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "XMR 수신자 감지", "openalias_alert_content" : "당신은에 자금을 보낼 것입니다\n${recipient_name}", - "card_address" : "주소:" + "card_address" : "주소:", + "buy" : "구입" } \ No newline at end of file diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index f0916e1d9..0268e8a0e 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "XMR-ontvanger gedetecteerd", "openalias_alert_content" : "U stuurt geld naar\n${recipient_name}", - "card_address" : "Adres:" + "card_address" : "Adres:", + "buy" : "Kopen" } \ No newline at end of file diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index d08fba806..dec019a07 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "Wykryto odbiorcę XMR", "openalias_alert_content" : "Będziesz wysyłać środki na\n${recipient_name}", - "card_address" : "Adres:" + "card_address" : "Adres:", + "buy" : "Kup" } \ No newline at end of file diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 09e0a383c..fe855e87f 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "Destinatário XMR detectado", "openalias_alert_content" : "Você enviará fundos para\n${recipient_name}", - "card_address" : "Endereço:" + "card_address" : "Endereço:", + "buy" : "Comprar" } diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index cb7f935aa..5692f7421 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "Получатель XMR обнаружен", "openalias_alert_content" : "Вы будете отправлять средства\n${recipient_name}", - "card_address" : "Адрес:" + "card_address" : "Адрес:", + "buy" : "Купить" } \ No newline at end of file diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index e8a24c230..e44a993f7 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "Отримувача XMR виявлено", "openalias_alert_content" : "Ви будете відправляти кошти\n${recipient_name}", - "card_address" : "Адреса:" + "card_address" : "Адреса:", + "buy" : "Купити" } \ No newline at end of file diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 5c074a0f4..06a428fce 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -351,5 +351,6 @@ "openalias_alert_title" : "檢測到XMR收件人", "openalias_alert_content" : "您將匯款至\n${recipient_name}", - "card_address" : "地址:" + "card_address" : "地址:", + "buy" : "購買" } \ No newline at end of file From a260ed7cea4a8b58ae80e28021986ccef3015922 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Fri, 17 Apr 2020 23:27:23 +0300 Subject: [PATCH 06/51] CWA-198 | fixed dashboard_page --- lib/src/screens/dashboard/dashboard_page.dart | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index eca98a9e9..0a4e57a15 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -62,19 +62,10 @@ class DashboardPageBodyState extends State { padding: EdgeInsets.only(left: 20, top: 23), child: WalletCard(), ), - Expanded( - child: Stack( - alignment: Alignment.topCenter, - fit: StackFit.expand, - children: [ - Positioned( - top: 28, - left: 0, - child: TradeHistoryPanel() - ), - ], - ) - ) + SizedBox( + height: 28, + ), + Expanded(child: TradeHistoryPanel()) ], ), ), From b3673d7c6359e61d61643866f52d6378874fff3a Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Sat, 18 Apr 2020 12:17:52 +0300 Subject: [PATCH 07/51] CWA-198 | fixed borders of date_section_raw, trade_raw and transaction_raw --- lib/src/screens/dashboard/widgets/date_section_raw.dart | 8 +++++++- lib/src/screens/dashboard/widgets/trade_row.dart | 8 +++++++- lib/src/screens/dashboard/widgets/transaction_raw.dart | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/src/screens/dashboard/widgets/date_section_raw.dart b/lib/src/screens/dashboard/widgets/date_section_raw.dart index 1fc0b4452..595171cb4 100644 --- a/lib/src/screens/dashboard/widgets/date_section_raw.dart +++ b/lib/src/screens/dashboard/widgets/date_section_raw.dart @@ -38,7 +38,13 @@ class DateSectionRaw extends StatelessWidget { return Container( padding: EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20), alignment: Alignment.center, - color: PaletteDark.historyPanel, + decoration: BoxDecoration( + color: PaletteDark.historyPanel, + border: Border.all( + width: 1, + color: PaletteDark.historyPanel + ), + ), child: Text(title, style: TextStyle(fontSize: 12, color: PaletteDark.historyPanelText)) ); diff --git a/lib/src/screens/dashboard/widgets/trade_row.dart b/lib/src/screens/dashboard/widgets/trade_row.dart index 6927638b1..e74fe5912 100644 --- a/lib/src/screens/dashboard/widgets/trade_row.dart +++ b/lib/src/screens/dashboard/widgets/trade_row.dart @@ -26,7 +26,13 @@ class TradeRow extends StatelessWidget { return InkWell( onTap: onTap, child: Container( - color: PaletteDark.historyPanel, + decoration: BoxDecoration( + color: PaletteDark.historyPanel, + border: Border.all( + width: 0.5, + color: PaletteDark.historyPanel + ), + ), padding: EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), child: Row(children: [ Container( diff --git a/lib/src/screens/dashboard/widgets/transaction_raw.dart b/lib/src/screens/dashboard/widgets/transaction_raw.dart index 824cd167c..0aa79b2c8 100644 --- a/lib/src/screens/dashboard/widgets/transaction_raw.dart +++ b/lib/src/screens/dashboard/widgets/transaction_raw.dart @@ -24,7 +24,13 @@ class TransactionRow extends StatelessWidget { return InkWell( onTap: onTap, child: Container( - color: PaletteDark.historyPanel, + decoration: BoxDecoration( + color: PaletteDark.historyPanel, + border: Border.all( + width: 0.5, + color: PaletteDark.historyPanel + ), + ), padding: EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), child: Row(children: [ Container( From 52d5dedaf82b95f3a7cb12db4263c391d297325b Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Tue, 21 Apr 2020 17:31:25 +0300 Subject: [PATCH 08/51] CWA-198 | moved ButtonHeader class to button_header.dart, fixed containers and bounds height for date_section_raw, trade_raw and transaction_raw, changed animation time for trade_history panel --- .../dashboard/widgets/button_header.dart | 297 +++++++++++++++++ .../dashboard/widgets/date_section_raw.dart | 1 + .../widgets/trade_history_panel.dart | 301 +----------------- .../screens/dashboard/widgets/trade_row.dart | 3 +- .../dashboard/widgets/transaction_raw.dart | 3 +- 5 files changed, 308 insertions(+), 297 deletions(-) create mode 100644 lib/src/screens/dashboard/widgets/button_header.dart diff --git a/lib/src/screens/dashboard/widgets/button_header.dart b/lib/src/screens/dashboard/widgets/button_header.dart new file mode 100644 index 000000000..3daa39ec7 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/button_header.dart @@ -0,0 +1,297 @@ +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/palette.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; + +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'); + final filterButton = Image.asset('assets/images/filter_button.png'); + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + final actionListStore = Provider.of(context); + final historyPanelWidth = MediaQuery.of(context).size.width; + + double buttonsOpacity = 1 - shrinkOffset / (maxExtent - minExtent); + double buttonsHeight = maxExtent - minExtent - shrinkOffset; + + buttonsOpacity = buttonsOpacity >= 0 ? buttonsOpacity : 0; + buttonsHeight = buttonsHeight >= 0 ? buttonsHeight : 0; + + return Stack( + fit: StackFit.expand, + overflow: Overflow.visible, + children: [ + Opacity( + opacity: buttonsOpacity, + child: Container( + height: buttonsHeight, + padding: EdgeInsets.only(left: 44, right: 44), + 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 + ) + ), + Flexible( + child: actionButton( + context: context, + image: buyImage, + title: S.of(context).buy, + route: '' + ) + ) + ], + ), + ), + ), + Positioned( + top: buttonsHeight, + left: 0, + child: Container( + width: historyPanelWidth, + height: 66, + padding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), + color: PaletteDark.historyPanel, + ), + child: Stack( + alignment: Alignment.center, + children: [ + Text( + S.of(context).trade_history_title, + style: TextStyle( + fontSize: 20, + color: Colors.white + ), + ), + Positioned( + right: 0, + child: PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + enabled: false, + value: -1, + child: Text(S.of(context).transactions, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).primaryTextTheme.caption.color))), + PopupMenuItem( + value: 0, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text(S.of(context).incoming), + Checkbox( + value: actionListStore + .transactionFilterStore + .displayIncoming, + onChanged: (value) => + actionListStore + .transactionFilterStore + .toggleIncoming(), + ) + ]))), + PopupMenuItem( + value: 1, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text(S.of(context).outgoing), + Checkbox( + value: actionListStore + .transactionFilterStore + .displayOutgoing, + onChanged: (value) => + actionListStore + .transactionFilterStore + .toggleOutgoing(), + ) + ]))), + PopupMenuItem( + value: 2, + child: + Text(S.of(context).transactions_by_date)), + PopupMenuDivider(), + PopupMenuItem( + enabled: false, + value: -1, + child: Text(S.of(context).trades, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).primaryTextTheme.caption.color))), + PopupMenuItem( + value: 3, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text('XMR.TO'), + Checkbox( + value: actionListStore + .tradeFilterStore + .displayXMRTO, + onChanged: (value) => + actionListStore + .tradeFilterStore + .toggleDisplayExchange( + ExchangeProviderDescription + .xmrto), + ) + ]))), + PopupMenuItem( + value: 4, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text('Change.NOW'), + Checkbox( + value: actionListStore + .tradeFilterStore + .displayChangeNow, + onChanged: (value) => + actionListStore + .tradeFilterStore + .toggleDisplayExchange( + ExchangeProviderDescription + .changeNow), + ) + ]))), + PopupMenuItem( + value: 5, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text('MorphToken'), + Checkbox( + value: actionListStore + .tradeFilterStore + .displayMorphToken, + onChanged: (value) => + actionListStore + .tradeFilterStore + .toggleDisplayExchange( + ExchangeProviderDescription + .morphToken), + ) + ]))) + ], + child: filterButton, + onSelected: (item) async { + if (item == 2) { + final List picked = + await date_rage_picker.showDatePicker( + context: context, + initialFirstDate: DateTime.now() + .subtract(Duration(days: 1)), + initialLastDate: (DateTime.now()), + firstDate: DateTime(2015), + lastDate: DateTime.now() + .add(Duration(days: 1))); + + if (picked != null && picked.length == 2) { + actionListStore.transactionFilterStore + .changeStartDate(picked.first); + actionListStore.transactionFilterStore + .changeEndDate(picked.last); + } + } + }, + ), + ) + ], + ), + ) + ) + ], + ); + } + + @override + double get maxExtent => 174; + + @override + double get minExtent => 66; + + @override + bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; + + Widget actionButton({ + BuildContext context, + @required Image image, + @required String title, + @required String route}) { + + return Container( + width: MediaQuery.of(context).size.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + if (route.isNotEmpty) { + Navigator.of(context, rootNavigator: true).pushNamed(route); + } + }, + child: Container( + height: 48, + width: 48, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle + ), + child: image, + ), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: Text( + title, + style: TextStyle( + fontSize: 16, + color: PaletteDark.walletCardText + ), + ), + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/src/screens/dashboard/widgets/date_section_raw.dart b/lib/src/screens/dashboard/widgets/date_section_raw.dart index 595171cb4..4ec9382fd 100644 --- a/lib/src/screens/dashboard/widgets/date_section_raw.dart +++ b/lib/src/screens/dashboard/widgets/date_section_raw.dart @@ -36,6 +36,7 @@ class DateSectionRaw extends StatelessWidget { } return Container( + height: 36, padding: EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20), alignment: Alignment.center, decoration: BoxDecoration( diff --git a/lib/src/screens/dashboard/widgets/trade_history_panel.dart b/lib/src/screens/dashboard/widgets/trade_history_panel.dart index b1716c9de..99035a6d9 100644 --- a/lib/src/screens/dashboard/widgets/trade_history_panel.dart +++ b/lib/src/screens/dashboard/widgets/trade_history_panel.dart @@ -1,5 +1,4 @@ import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; -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:cake_wallet/src/stores/action_list/date_section_item.dart'; import 'package:cake_wallet/src/stores/action_list/trade_list_item.dart'; @@ -8,7 +7,6 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/generated/i18n.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; @@ -16,7 +14,7 @@ import 'package:cake_wallet/routes.dart'; import 'date_section_raw.dart'; import 'trade_row.dart'; import 'transaction_raw.dart'; -import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker; +import 'button_header.dart'; class TradeHistoryPanel extends StatefulWidget { @override @@ -58,7 +56,7 @@ class TradeHistoryPanelState extends State { child: AnimatedContainer( width: MediaQuery.of(context).size.width, height: panelHeight, - duration: Duration(milliseconds: 500), + duration: Duration(milliseconds: 1000), curve: Curves.fastOutSlowIn, child: CustomScrollView( slivers: [ @@ -75,7 +73,7 @@ class TradeHistoryPanelState extends State { : actionListStore.items; final itemsCount = items.length + 1; final symbol = settingsStore.fiatCurrency.toString(); - double freeSpaceHeight = MediaQuery.of(context).size.height - 496; // FIXME + double freeSpaceHeight = MediaQuery.of(context).size.height - 496; return SliverList( key: _listKey, @@ -95,12 +93,12 @@ class TradeHistoryPanelState extends State { final item = items[index]; if (item is DateSectionItem) { - freeSpaceHeight -= 32; // FIXME + freeSpaceHeight -= 38; return DateSectionRaw(date: item.date); } if (item is TransactionListItem) { - freeSpaceHeight -= 45; // FIXME + freeSpaceHeight -= 58; final transaction = item.transaction; final savedDisplayMode = settingsStore.balanceDisplayMode; final formattedAmount = @@ -125,7 +123,7 @@ class TradeHistoryPanelState extends State { } if (item is TradeListItem) { - freeSpaceHeight -= 45; // FIXME + freeSpaceHeight -= 58; final trade = item.trade; final savedDisplayMode = settingsStore.balanceDisplayMode; final formattedAmount = trade.amount != null @@ -159,291 +157,4 @@ class TradeHistoryPanelState extends State { ), ); } -} - -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'); - final filterButton = Image.asset('assets/images/filter_button.png'); - - @override - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - final actionListStore = Provider.of(context); - final historyPanelWidth = MediaQuery.of(context).size.width; - - double buttonsOpacity = 1 - shrinkOffset / (maxExtent - minExtent); - double buttonsHeight = maxExtent - minExtent - shrinkOffset; - - buttonsOpacity = buttonsOpacity >= 0 ? buttonsOpacity : 0; - buttonsHeight = buttonsHeight >= 0 ? buttonsHeight : 0; - - return Stack( - fit: StackFit.expand, - overflow: Overflow.visible, - children: [ - Opacity( - opacity: buttonsOpacity, - child: Container( - height: buttonsHeight, - padding: EdgeInsets.only(left: 44, right: 44), - 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 - ) - ), - Flexible( - child: actionButton( - context: context, - image: buyImage, - title: S.of(context).buy, - route: '' - ) - ) - ], - ), - ), - ), - Positioned( - top: buttonsHeight, - left: 0, - child: Container( - width: historyPanelWidth, - height: 66, - padding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 10), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)), - color: PaletteDark.historyPanel, - ), - child: Stack( - alignment: Alignment.center, - children: [ - Text( - S.of(context).trade_history_title, - style: TextStyle( - fontSize: 20, - color: Colors.white - ), - ), - Positioned( - right: 0, - child: PopupMenuButton( - itemBuilder: (context) => [ - PopupMenuItem( - enabled: false, - value: -1, - child: Text(S.of(context).transactions, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Theme.of(context).primaryTextTheme.caption.color))), - PopupMenuItem( - value: 0, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text(S.of(context).incoming), - Checkbox( - value: actionListStore - .transactionFilterStore - .displayIncoming, - onChanged: (value) => - actionListStore - .transactionFilterStore - .toggleIncoming(), - ) - ]))), - PopupMenuItem( - value: 1, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text(S.of(context).outgoing), - Checkbox( - value: actionListStore - .transactionFilterStore - .displayOutgoing, - onChanged: (value) => - actionListStore - .transactionFilterStore - .toggleOutgoing(), - ) - ]))), - PopupMenuItem( - value: 2, - child: - Text(S.of(context).transactions_by_date)), - PopupMenuDivider(), - PopupMenuItem( - enabled: false, - value: -1, - child: Text(S.of(context).trades, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Theme.of(context).primaryTextTheme.caption.color))), - PopupMenuItem( - value: 3, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text('XMR.TO'), - Checkbox( - value: actionListStore - .tradeFilterStore - .displayXMRTO, - onChanged: (value) => - actionListStore - .tradeFilterStore - .toggleDisplayExchange( - ExchangeProviderDescription - .xmrto), - ) - ]))), - PopupMenuItem( - value: 4, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text('Change.NOW'), - Checkbox( - value: actionListStore - .tradeFilterStore - .displayChangeNow, - onChanged: (value) => - actionListStore - .tradeFilterStore - .toggleDisplayExchange( - ExchangeProviderDescription - .changeNow), - ) - ]))), - PopupMenuItem( - value: 5, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text('MorphToken'), - Checkbox( - value: actionListStore - .tradeFilterStore - .displayMorphToken, - onChanged: (value) => - actionListStore - .tradeFilterStore - .toggleDisplayExchange( - ExchangeProviderDescription - .morphToken), - ) - ]))) - ], - child: filterButton, - onSelected: (item) async { - if (item == 2) { - final List picked = - await date_rage_picker.showDatePicker( - context: context, - initialFirstDate: DateTime.now() - .subtract(Duration(days: 1)), - initialLastDate: (DateTime.now()), - firstDate: DateTime(2015), - lastDate: DateTime.now() - .add(Duration(days: 1))); - - if (picked != null && picked.length == 2) { - actionListStore.transactionFilterStore - .changeStartDate(picked.first); - actionListStore.transactionFilterStore - .changeEndDate(picked.last); - } - } - }, - ), - ) - ], - ), - ) - ) - ], - ); - } - - @override - double get maxExtent => 174; - - @override - double get minExtent => 66; - - @override - bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; - - Widget actionButton({ - BuildContext context, - @required Image image, - @required String title, - @required String route}) { - - return Container( - width: MediaQuery.of(context).size.width, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - if (route.isNotEmpty) { - Navigator.of(context, rootNavigator: true).pushNamed(route); - } - }, - child: Container( - height: 48, - width: 48, - alignment: Alignment.center, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle - ), - child: image, - ), - ), - Padding( - padding: EdgeInsets.only(top: 10), - child: Text( - title, - style: TextStyle( - fontSize: 16, - color: PaletteDark.walletCardText - ), - ), - ) - ], - ), - ); - } } \ No newline at end of file diff --git a/lib/src/screens/dashboard/widgets/trade_row.dart b/lib/src/screens/dashboard/widgets/trade_row.dart index e74fe5912..1ea5f098d 100644 --- a/lib/src/screens/dashboard/widgets/trade_row.dart +++ b/lib/src/screens/dashboard/widgets/trade_row.dart @@ -26,10 +26,11 @@ class TradeRow extends StatelessWidget { return InkWell( onTap: onTap, child: Container( + height: 56, decoration: BoxDecoration( color: PaletteDark.historyPanel, border: Border.all( - width: 0.5, + width: 1, color: PaletteDark.historyPanel ), ), diff --git a/lib/src/screens/dashboard/widgets/transaction_raw.dart b/lib/src/screens/dashboard/widgets/transaction_raw.dart index 0aa79b2c8..517318260 100644 --- a/lib/src/screens/dashboard/widgets/transaction_raw.dart +++ b/lib/src/screens/dashboard/widgets/transaction_raw.dart @@ -24,10 +24,11 @@ class TransactionRow extends StatelessWidget { return InkWell( onTap: onTap, child: Container( + height: 56, decoration: BoxDecoration( color: PaletteDark.historyPanel, border: Border.all( - width: 0.5, + width: 1, color: PaletteDark.historyPanel ), ), From fa696c2a6044b6769319be9bb327af03ca856d41 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Tue, 21 Apr 2020 21:23:40 +0300 Subject: [PATCH 09/51] CWA-198 | implemented menu screen; added menu widget; added images to menu items and fixed menu actions --- assets/images/2.0x/eye.png | Bin 0 -> 873 bytes assets/images/2.0x/key.png | Bin 0 -> 667 bytes assets/images/2.0x/monero.png | Bin 0 -> 2230 bytes assets/images/2.0x/nodes.png | Bin 0 -> 1142 bytes assets/images/2.0x/open_book.png | Bin 0 -> 685 bytes assets/images/2.0x/reconnect.png | Bin 0 -> 793 bytes assets/images/2.0x/settings.png | Bin 0 -> 830 bytes assets/images/2.0x/wallet.png | Bin 0 -> 551 bytes assets/images/3.0x/eye.png | Bin 0 -> 1188 bytes assets/images/3.0x/key.png | Bin 0 -> 906 bytes assets/images/3.0x/monero.png | Bin 0 -> 3522 bytes assets/images/3.0x/nodes.png | Bin 0 -> 1472 bytes assets/images/3.0x/open_book.png | Bin 0 -> 1005 bytes assets/images/3.0x/reconnect.png | Bin 0 -> 1122 bytes assets/images/3.0x/settings.png | Bin 0 -> 1249 bytes assets/images/3.0x/wallet.png | Bin 0 -> 733 bytes assets/images/eye.png | Bin 0 -> 475 bytes assets/images/key.png | Bin 0 -> 422 bytes assets/images/monero.png | Bin 0 -> 1130 bytes assets/images/nodes.png | Bin 0 -> 633 bytes assets/images/open_book.png | Bin 0 -> 377 bytes assets/images/reconnect.png | Bin 0 -> 476 bytes assets/images/settings.png | Bin 0 -> 498 bytes assets/images/wallet.png | Bin 0 -> 365 bytes lib/palette.dart | 3 + lib/src/screens/dashboard/dashboard_page.dart | 6 +- lib/src/screens/dashboard/wallet_menu.dart | 25 ++- .../dashboard/widgets/menu_widget.dart | 205 ++++++++++++++++++ 28 files changed, 230 insertions(+), 9 deletions(-) create mode 100644 assets/images/2.0x/eye.png create mode 100644 assets/images/2.0x/key.png create mode 100644 assets/images/2.0x/monero.png create mode 100644 assets/images/2.0x/nodes.png create mode 100644 assets/images/2.0x/open_book.png create mode 100644 assets/images/2.0x/reconnect.png create mode 100644 assets/images/2.0x/settings.png create mode 100644 assets/images/2.0x/wallet.png create mode 100644 assets/images/3.0x/eye.png create mode 100644 assets/images/3.0x/key.png create mode 100644 assets/images/3.0x/monero.png create mode 100644 assets/images/3.0x/nodes.png create mode 100644 assets/images/3.0x/open_book.png create mode 100644 assets/images/3.0x/reconnect.png create mode 100644 assets/images/3.0x/settings.png create mode 100644 assets/images/3.0x/wallet.png create mode 100644 assets/images/eye.png create mode 100644 assets/images/key.png create mode 100644 assets/images/monero.png create mode 100644 assets/images/nodes.png create mode 100644 assets/images/open_book.png create mode 100644 assets/images/reconnect.png create mode 100644 assets/images/settings.png create mode 100644 assets/images/wallet.png create mode 100644 lib/src/screens/dashboard/widgets/menu_widget.dart diff --git a/assets/images/2.0x/eye.png b/assets/images/2.0x/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..4389fb7e4a4f163d74be9ce036bc27bca88951c4 GIT binary patch literal 873 zcmV-v1D5=WP) z;M`y$Heh?Y@~W|u@pyXt*-+AGTGiF{>eE%#LOe1_F(uVbZZdawcNt#K&d&O!{4-xn zL1P>6>F_d}QYt5fW5=Z z8~|$3FoWv1Gc)!9t85k)PDdKBe{@v=vpggyrMI;{pXW7SK)SzQ zgV!$jKIEHW<)4qPJp9(8I^a-sr?6158ejv*!4?kA85!IOrPNtCI=tW2`t@!v%xqxL z>0BUv?kFSFC~zjEqi7T(#8Rn?mALcx3@M!bIk#*N(5h!P@}B3oER7&R8K?2f z(bWem{r3NgNK6@5j{5liRg(mj?3$%%DyEa6y(TH->VQ{%s3P11gH7d_D%dH!JYa@J zHp8{g3*G6kp-EHEhgYk-Kr>pQNLvnrZxt4*y#Ch*m|-)5Z!9+#6DDcam`&rmx4>O9*!b6|gKOApm1&Rr+bM(L_(Ow3KfIhgV82uV`cP0os)O5^~bs z_S@&b$I(0WqqK~CKMCk5uWudsr#j`M^wH@r`SxsTz5-DG00000NkvXXu0mjfcy5n| literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/key.png b/assets/images/2.0x/key.png new file mode 100644 index 0000000000000000000000000000000000000000..439ef2f2e9d82de01a6aa48d52dfeb791d4bd66e GIT binary patch literal 667 zcmV;M0%ZM(P)_QG)6p^J9m>UQME{e#j6A0a4 zs}u>AX>}u^+L{6}vmfaN)X>|r?`=;{cOztg_MiWyXgvOkh;NaoN&uzV1H=He4m8n8 zYiqr~XfHwv2=R0>@qy^eDqkiVDXr_aa3BvQ^rjIDh4x`*u#rf>&(2`ehMb9yuGZEnyUkip=VWzpD1UQ!|s(Knj#q1o9x~@E=QU zSeb-*kn_7n5z&FH@kz+J1n=L?1?o}Bxgo{L1>Pf(hkWKf45Q@r(*icZhVlTw83|7zp8l>3A@`s}$QlyBeR0VYa9Ti3#90kOJ zh>8+X29eN$FqDK)3^jRv=e^xz!?yFv?t(w&CU4)~n|?&x243c|wShNQ z@F^Ga_xr|pEQZhcrT}vgztM8^;g#GL_V9}MQN zXW@l5mjE4ZV!IhQzMXE&dfM2P^MJ+g0h|AXM~2fTJQeHBmy8&0*IN-7Q{tGXh+yQuTC2;eLaB+TXNJ*!f zQ3gib;6bN=cgMjAO)|(QD8PIGCvsm{!poDP zrCBR}>kDipq>}AxfY-R(N*#p@N*QCwHQq&8=tj*YkZE~!df}Vqq(^wcQaqPi!{eNc zYJx0F#wx02KrnLi2iJa6)t{=*ZqNQq;aeiD6fFWqTn1Dg(vB$OENB^;1=Ta)AZ}F) zFXRnPzwkotMZhgDIT_K2v!EdKB76xv4lNhn3taqQ^=moJr4so(Gwg78&C|9b^xPl1 zuoPhSLuW3AR;r=d^@3Yb7~5!&W<7_LAi_`W#jW~a^*w_t`Hqorusyc5;+6=_fJ3-P zI}%+Uu#Mm0%zY*KN(c$Rcv|FpIh}yByF-nM8|7CZ_~LTaAklQU$6~*qOeMqB}h@VQ(3Lio| zPb~-0HNd_90##@6@J{arHGU|;sqjL_JbhmS9mEFcWy_YDcp;IYuBM47K$p&H zqSI4MG)nM8c%iY{pKBE08KAbRtDFG65>E;7gwM=|BP7_WqfUU9&{TDGdfxBc6F8+~ z zzWsGT-;cQVYrz$pl(_^G8w1E-6iD?)b={&8PYH)}#??T;{ibIi28;=tu zNFcMtxsmU+qetHFGoV%-sEGC)(pG*AH3pVsQVZXz2aLK3o~aw031hgmt^LuyC&E86 z2gpini>nym!?{Fe022k9d8u49K2hfwV9=L9Yx?f(E^{utKdhka8$x@GM&mj|lH97@|ukrG7V@%V0%6X8YH5uwZK z#K-|FBU}b8QxsSOxOC#z(glTpRo`)hp3H56dYf=a9Q zSC80(p^V3uB(+(ayderHe1szsQ6ps4)KxHhYG4DXN8W&2XCTr{h(KhvT^BG+0SG1aMJDoJ?ff zuEZ0uilSo=bAj0tImoi?g1)#SnV48a;d@3ahE9Yl1yp@*J|1RR{TV*MDM%0Ex4gh9 zKUO>C566=N1gpL{0|RIq@*NdgdiqfMEC!t#I&a~1zi#lXfDoJw$59b^d^iae1EAwtiVxTP`PK?q+-QWOx5Rfczf#?nA1z7%gv zN^-R6*QcLlL?50gCTGM&K|&DKs^|Q3pM@# zdNp2_s0q;B_ncX}&2~F)X*&tw?R4IJ^XAQ)?>z*P)vfPy3UJl{i~?fa3ByWtW}*oe zsqLJ4y49+IF_V$Pm;*I3Qmt0TeCwP~-wI(aS3_e82C=D(S${P>zK3g@M`febPRibQ zv>vks@nQSqlt2qzN(y}b*`tyOzIimNl{%#bdP)6V?^aoXQtyO09!;2)oULvi6??#0 zj46KJ|5=pgXvcY%250$wepyyg+66JjhcAdlWtk+`(y^f5|* zjc5YzGh)NZ2%jccZmz9Tj6Zl{9u`KvdQUDCbpl}^^fgMTP!E$*O!m!}h00s?WSn$jM z`U!%L5f@~0Sa24EJ|tZe)bYk7ySPL43(n$-U{_Z~qqV;&@E0BM!N^nADWD&YYyd>elfRDLSp0)2p;Dr8%M9+YjRoXS2)l9iJ}M zwVI>>T({8BaneKuN$}W?bzl)DytHrLDt&ob>tuk=bd4O%Ne+00OrgwnOh#w{(?KxC z&4p^=5WBg=lgNm~ccBmA72eJ}(b#nyKQudCBmqt=LJ-7CUO3G%sQ}$}r)jK7EB4mBWncZVZA({cPc41wV=;C#i_uDhS?gkca&#kJ7yeZrc7n^v9# zj}k#+hjj632gyW~fp%}7C3^KJq6Ur2Ht?)YNCZ}jNk+;9`Ts&q>K-Ec#2p*V9d6g7 z0TFcM$$*Vgnf<^fh+Wt66pJ#~a3Gv92x*bTKPAOvBlT%|Ivq%q>g4lv5N^>?GZL=l z(cWvl3%%kgda5aY(Fi~CZKojV*&%A3zRLTQx$2^Yj-!>!AVrnDQguxt_5+K&o|)Kf z(c6)(<&#u1$s_LbwpPHi>w zgIbt=ysovbbjXEBf_S~Om~p!qRM;2$q+z2C+$5a2d3v7z2WU14aT2KS=Kufz07*qo IM6N<$f|<1$m;e9( literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/open_book.png b/assets/images/2.0x/open_book.png new file mode 100644 index 0000000000000000000000000000000000000000..84c2428ceafb068d393abe0657e28fbba7bbc609 GIT binary patch literal 685 zcmV;e0#f~nP)|**D1e z2BJ_j_%}r=4L#2=NB5y9SNzm`;*y zyN+WAF?H>ZB*yqC;tR)V{pgO)rPe{PLYZs;DSOCi7`7aa>u%X=!OCG53XMTzuNXM# z4EHr+)SQ)opgkhVO5}KW`gYE(DT92J3zKt-S;P!V`O1n6dSqzu_3<2p^J_ImD!(l~A$H0$T^ zgfBOwd_mu|*1qAKTv7u|pOwP|x7{V|oDxzh7?n^9M;$hIre`oOxntsRH~D)AIa;5Z z^}(`gWL8}%j|?0S&#zzU*5vG(TRt*G?5B}#|KQ!uv{-{wra|$~+`QNX7J#1=rdODN zCizY3*hDbVzD4I3>yD0S zQX&9nv-i1KKh7G*aSKX*T-ToQ)9&c%R#G~Ev{w^MqabxCIG-O%ng9em#5{>f159cc z%H*BR+F9PsR;WCtp#bHPyGDHvR-eujtrgECbvMkiJ$p=?{QBen+uT&F!c*fvf*}mJ TC-&y~00000NkvXXu0mjfmKZTM literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/reconnect.png b/assets/images/2.0x/reconnect.png new file mode 100644 index 0000000000000000000000000000000000000000..dda61e3160333fed0ba32909393d0a0cb383a66f GIT binary patch literal 793 zcmV+!1LpjRP)hNye3-%1rDGL&cDW@d>OOpj5)fc`8}@tci!rE9Wp@dJQ~takkdc=x?wz)o_9>!X(f?&dZU6HoU(KE zfh1h@?^;B7xtt);$^zKoyy^6noS$3Kk4Lmo$}#Q0&AZb>Yg2s8u~n4>EF5mY`5U_^ zKqgQbek5tGR5}lASn*My+IXvEmU@f}JqXLSIA_lQ6kom=OIM;X2MwZZc>*f(&2*0o7dj zAb~vMCnb}L6hLQgtxlk(T|N}K&*!(sw3VTGlUnKa`!~SVY>NfDO|`BDJid~T1ptx8z0>~N}xE61Et6_}?eJKUIFx2<1>(QRkQ^-cH( X0lRkqhFGY~00000NkvXXu0mjfqpEG0 literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/settings.png b/assets/images/2.0x/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..53918cb0ab0ea5934c5d9effb65d7eb71f99557d GIT binary patch literal 830 zcmV-E1Ht@>P)BD1Hg9F~*K{&b+mGaIQaDb}>G7r%@Uy z_oxovy6!!Ox!_IBGD28Zv%H}ja?bBC+HGTsLfzDSZcIlpD10ZQ5o z#CbM*Vg(+uP#Ip27qvq+CFEN;PU!zcxFh2HV9iK?#0GQ(sGDU%)HQpPkW<=HDMxlh zgv(}m8YF?bu%bSIGML7w&WF}~TUUsqpsh|vn9iBkn7rI&JoxK~#7F#g{!& z!ax+q_q~MF93eOGqY&-j1j-2vGmdBn4i;8It7d>IQppj*3BW4QaRcKGQdl`**S8r6 zk>R7sCch$io4ncg-{kGSU0_RI9j}atmqLglO9=#+fMJZ9wUc0%56H{gU^b-NHB$fu z@R9RM^Zvr$_FlIK(}q|F510^hmKFeI>f2ms+6T2NTV3qI>`OY4?Y8QrDoYXSyGwmH zqJ~y5TQ{fQn?AS;;xS zN;$Z>Q7V9bfz@?9bDxjuBrI~ovHd=sP+{`fTG(+`0;1_g!L1$d=E?=^AlmwcLe%mR zAcWhxJFiJI_gWwY1T13!AdZPt6nZRUemU>Q0?;t}Bq_bKzyWB$?We@P5LU*E<5_@s p1SuZPl2B0!GywPE_UtqH{0}ggkdHPh+9d!0002ovPDHLkV1ljaE&3?Y3HJA;gm8Jk6y{OU9A`i`f`c$C$d~INx_S7HaI4nAm{*qst5_jmvD1 z!Ul`mOv{oxL^gmF=doBG3uo9g!Ff&gdc~-Q7#mPJx=i(Av9eZiDQozxidd|H zYy1CWnV~-@8Y&O>st75I+ZziFW&k4t_K$yU3C8oGt^&p3QiZp#o?V2^^#L0((?7v% z$S~VIjn~f)nFgT-&WZ3@Sxu#inLIgLOA$YmTM&Y^sY z1;ci_-NpBBUerCZFud1pXSn0I$~lZR#`*TguRqelvd%+|fUIzw#ULZb8c@Q-j%A%` zlqY0&*5*!C#k=h`+>LGe-Hjp+Lg$L#kWWXKSt&$0Y>_Y{c!2Wf+R%vOh1=wOa=}LX z#(Ru7zA8a(i-lwCX$$qnb(_8t+PL0C#N+f%m!*^BZnTz1)}w^p=lj5J z?kUHql|zKu3;7UeQ2sY!4vEIbV3KMOInFUotXlB3*kNQE>Am%2b;#SjMaVj8Lbeq?{LS0FmR&= zGuLD5;P`4;U1g6?x(NGqXGRdgGI)(jjKXsup>YTQP{}h|g zjD(CKm;6eBD;>bvXnqu7u7Vbw&4bnJo`jpT+Glqm-nsiNMUW6K zM1BA1y-8RqS#1B%AJc$1Vb9>mH^^eOMZouY1t7sm70ieVSJ##>aM7t;5 zz?5_K*r=4>zzha@7BbFlFo3C)!^{H6>Tt>_)j^qn)$0*%GcyS=MxMafC;tM9FiIZX zr`@Vn=ntg`7$)ydg?JR)q!wV9Ja_=jqq!rNR02$sr!D8}R&_Anlz0x9P8%BeMe>A1 z5im*~?Gkgo5=Ne|Gy*1l9(P>M!IQhOt9+~g-Q?-?f#D_{cTzPh#L7srg!eY}QDH{g zOAD{RHa3QxW+hR97%3nR@=>P`8Q*&yH-$Xm+9cLY-X-hHi#*}K2xuXXldrwIRfmG` zHv+~NDMk1KZYp^K*F^r`mhw-TTNKtbkavU9)&w%|$d;XL=8en(=wtv4BKxMk;GADX z`ja^%ET+>_zIp3s`|+JCFpTs9gn*>~22cc4QpkoCf{K6vtPoPAkY82qZk@skfg`DI gg73L`mc&``8z<{RghAD(qW}N^07*qoM6N<$f=OtSjQ{`u literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/monero.png b/assets/images/3.0x/monero.png new file mode 100644 index 0000000000000000000000000000000000000000..94eed5046a10c8a49079efe200956479e142fd7e GIT binary patch literal 3522 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 literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/nodes.png b/assets/images/3.0x/nodes.png new file mode 100644 index 0000000000000000000000000000000000000000..29caea1114edfd1cef0f6070f5fc899a885369ea GIT binary patch literal 1472 zcmV;x1wZ*fW(K_bR*VDkjn5)vomu>`RU2md4v;6+bfK54aUcTG)IS9eu?-HKw|-#=-pTCJsw znZ@5msWWYizqvB^h)TlNWr*se)Nuv68f;Tng(2)}Z>-LDFs>q@gVSyP(aKW52DGV^vvrpbWq6&1GFubKr zt+qrC{QY0gBLO73{`%*9jU>>zgmw^rwmS$Mlhj@O!pltvERTb=idbYbkSpcdd=9QB1FnM4=%0Nq)c zYlmUDO!iVisIA#TK9)F<=wbspLsh&?dF3x+%=P?O?q@q}U9pW`qD#3H?i`%9j5Vv$ zVwB3`o^VWbDO*S2fwZ>QoC7W2@ND6B=mI5ft`oX4vjHho>G3Gqpw`Kv5`>~ z;e4R=A5;L)Ks1o#fRs|sj2Td1eDn}UChYZg`2|sC;bnH5ERB#)4|u5+Js#0Oid*F< z+CcYb-iN;|xXx;HrH6n~YSP#&^7lwR?GaV@v3H5GFHFxP-J{uY|5N_vhh9*s(h)l(kx8nK)O;&id4Fpo7Rbm9dNb8c9F7+ z9Wd!ZK^7*e1Co9|DN^`wd-0JyRwc75?Lbvzq$(#$IUqG2S&5I@?PK%>EUC0y6;6m9 z5E~CU6tmGPx_~Y<%eZNs5N%?q@zNGJD^pFnv7Hepv*sl?G-!dd{y%9Xh7pKn4+bQC z5Ff~*VYA7NYr}Gm|Cd1fiqYj3;Pt%0bR@X>^Es*w%dQbh8ATvE&PM3%CJr35gz+&X z?R23`Iua507`3a(DcVn>qcQV&ywiHf7o|$U4UOcsCwiCTA|zU3ob5!nl!OopU`+Vf zB?B%&GBjKQ*iYI?8i>TVl;}h$KJ&?Z;o$7(5lJAsJ*}2f0&Jj{zM-MPxzhTb+c%e~ zS}>)=Ev3U-@hxQxkP-g!ajWubU|zfX`MZBoSztf8qQKl>2Dg-4ISU0#tlJU9H!2g6 zc-(kuhh3suN+rBmtQt~EIV@xmiN>LmQiDy+rw4&jKS<6mFB6tsO&aW_Gmgym=IxtL aG5$X{zd+s-k}7xr0000? literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/open_book.png b/assets/images/3.0x/open_book.png new file mode 100644 index 0000000000000000000000000000000000000000..3e41ebc25a85c330b774578e2695951bf26f9d10 GIT binary patch literal 1005 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 LNkvXXu0mjfc7{ks literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/wallet.png b/assets/images/3.0x/wallet.png new file mode 100644 index 0000000000000000000000000000000000000000..afc427964d9f9772b05c62201740fee193e50561 GIT binary patch literal 733 zcmV<30wVp1P)r=p-U8T^Xa_JSBUY2tQ&TSdR0kv05FZ`P$s`;|0sl z!Eved%)7zq4*12tKKJ?qj-h#FD-TajTxCylL^WKah9EjDAowvH{Lg3`ZTs;}J~+`5 zqR@3fQs(YFjJ50P8~}q5yoJ(~k*Ld~5x~3=!i{byDh?#_(hj$o0(2uy2!a9d*1jSU z5B$!LsWobZ00mDIH#|M<#O=lixS}2(1=9ookHYh4+c*Jn?gbQ$i2}Nu^!#}_}yg@j|q!e8ZR6;aQF3@&eA8Q$p|ok~cqWNSMDNvQItsvxQ}gDcoyj1!HOQ{Z&_Wvo7mI~&V~;`*zIwy5p%@4`YO zZogQ>>JlNPT&3jWyHL1;-yJ(nb=KD-5jVWuJ9^4P<$@;sah%U-pS{ijC$Zv4ZKH?#)L|EgYyZ1#)QgXq6w8+Ss0ZLW5e+T@CIUqu|eMepTH|@WZ4;K zmOFC(bUMiA33eNU*opfsHim0J? zjMyS$?v>*Uc(Np``YM6gAXiVFg5J1(RcV^RSg@^ z#a41JrF|^iVa4k$g_G9}e2L`h_Hn2NGEpX8K&eP%taEMIEH)h=?kKoiL3JB6Zzc$u zCGukB+`j*X3)Lc;aP31T9#kzrU5YhDLgoNQANOy~QyC92S)Aul}_VRE1F-X^UPkRK=5?})PAVEGzYVgs)?gRX1d;)+NzKd<0 Rbsqo#002ovPDHLkV1hK|#CZS! literal 0 HcmV?d00001 diff --git a/assets/images/key.png b/assets/images/key.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb694f8dfda61145831a5b6ca7021da8ff1c3cd GIT binary patch literal 422 zcmV;X0a^ZuP)KK*SaWyhG{ZZfx5ar~L77*a(~uW!e1SG4yj(K9n8NS8}D8>32& zPW-n)XWfy@p}K4t$8)kK6oLOSV**~QiIq~hI7J-Tifdar3%~vWCQw0SE5IC_B>L&x zGFZ>Uu-o+50kEK|{+DHS)?F0Cx)L&e!er{CNfLcG8jI1XCpI<;U_tHmqk4U|4P?bl zFx~EgVpE#;M<@|DwM~_$m%Y{nR8VdX7-DQ>!z>b_d;QwRt>AMNk~ zlkgRTpzt4?I0(y%S;7bkg(8*}Y6s%} z-Molp#OA}iG&YcBnc78fK?UgP=*797W;GYBgE&ISvqi%Ypl4zL|IX9W4y}ua zEcuMYZBGGu2D($}RaQHAx{1bs-dqmZQQ()~fckpi(>vgP8E}h1t15>Ns_B1lY9ty3 z=sEZuUqCM&VedBz7`+PU+8@4nbR9Uh$Pr_MMkVU;m)eK7@)&9~)M2HSJdzHF7``#LzXClDNT;f;Y2|12aMYzawy~jPcY_@6K3o{ItSc$p}7k2`$ zpEz|nh-@MjUH}R?`?f!Olb=}9R4+dY3vPr-F4CsCnyYU(#SdNjIwB%j-ZMY78fkDQ zjL$g2eNf1UESE_xqW)uGw56hxWxM{G>m1{$xXRnK?xVX+;~DPabXXOkM$f`AHcfSP zkkAht2lO=$N?*vSCnbrJbtbukVpWPS&Ni&anuMn2*f#}ud=uY|Ysa1Bq&YNyb%})6 zNl17vSMaaU=qOQG&m*+#09uT5TYw$o>^9AGy~s(+no_a?-cFH3KKO@qki1v9)zV$d zceyZ6vR~x|FYq}NQiJcMwu|A zJxP3_@P=ORS6tQ z|G1)k^}na_eFa8sozfFhiL?ef`zsADvqJ%@*Xc)UlB6cN;-=tfTX~@w`(c>H!n| ztyZU=1YW;p~(*xKbw9Ge(zz?+L{5lubj# zxZiDrLXrhNuf-i&XW)taJMiJ?M-MGLQPzg&+9J;8q!Vk*kcgV>bT6+mFvfi6y)8Dh z#=gABb2ViN1@~dO)&-@0NgTL<&P+^<2|S{h*>rzrBaH5jaI#_7EW96-9qfwm=fm}RyDFM^e@g%t0+7s_ zu9nQy)Cr3DFzsdPeupVmjM_UuR5PbVuQH=Eg zSV^y`AgHmTVE86flj@h_tiq{1TxYi3rA5JkQoH9MIkqG@|G=?jBJj#(4}P^3A=ZDS zoW|g=eBUK36z^pSkUikM$vEGGsjDa*l?iF2m4y?npR9~*&iiyOn?##-0Dxqjj4iD@ z)a03IQvY0XrfA{hVB^`82{Q$Ddbl}W_Wdfg?eW#kOVt!8H8Ee`yFcwp# zQag_s#t-0s5H|(Zd*6;zOLPOZ~} literal 0 HcmV?d00001 diff --git a/assets/images/settings.png b/assets/images/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..dbfee77ec49bfa95b19712ba492b1a7ef087b262 GIT binary patch literal 498 zcmVM78Ti=`9VX?8D>pM`7bpl}OdbR8uh!j+E|T zGQ#JKjTvd?Z#dc(ZV9`Kj`C#8sUf<*X_Pwa1PGQ24(%X%wJP3Toy-FYnQYcW)*c#n#19S#-Mqf<}?f;j}B@BHVIflz_X-K{Mm9Br3n(x9}~b!jIufJ)&B?IwYN z4OeI-l9<|h4|;=18(cbJk_9rCo8cTJ*w18~b^F*A(3HZoXSH61<4-5b`xqEFdpPEN z2{hKIWT7@4qrz}n0BA-#NNkas=ZA9++Yc6pc|?hUg?=~EqeY5|{i9$ej$Co@ynH%o on1GFau(SGFzi-O3n}!kj1*(C#uHDM`5C8xG07*qoM6N<$f~HTk9 zw07GkkPAduRDT7Ltk-TP3b}HshTQ$4leHf;=6MJcJ1CAKeOI0Vl+j#7HY8FH00000 LNkvXXu0mjfy>yQ0 literal 0 HcmV?d00001 diff --git a/lib/palette.dart b/lib/palette.dart index ce7d9e28b..8e08253f8 100644 --- a/lib/palette.dart +++ b/lib/palette.dart @@ -85,4 +85,7 @@ class PaletteDark { static const Color historyPanel = Color.fromRGBO(33, 43, 73, 1.0); static const Color historyPanelText = Color.fromRGBO(91, 112, 146, 1.0); static const Color historyPanelButton = Color.fromRGBO(39, 53, 96, 1.0); + static const Color menuHeader = Color.fromRGBO(41, 52, 84, 1.0); + static const Color menuList = Color.fromRGBO(48, 59, 95, 1.0); + static const Color menuDivider = Color.fromRGBO(48, 59, 95, 1.0); } \ No newline at end of file diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 0a4e57a15..792097214 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -4,6 +4,7 @@ import 'package:cake_wallet/palette.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'; class DashboardPage extends BasePage { final _bodyKey = GlobalKey(); @@ -52,7 +53,10 @@ class DashboardPageBodyState extends State { highlightColor: Colors.transparent, splashColor: Colors.transparent, padding: EdgeInsets.all(0), - onPressed: () {}, + onPressed: () => showDialog( + builder: (_) => MenuWidget(), + context: context + ), child: menuButton), ), ), diff --git a/lib/src/screens/dashboard/wallet_menu.dart b/lib/src/screens/dashboard/wallet_menu.dart index 1e48ee325..ecc80e700 100644 --- a/lib/src/screens/dashboard/wallet_menu.dart +++ b/lib/src/screens/dashboard/wallet_menu.dart @@ -10,12 +10,22 @@ class WalletMenu { final List items = [ S.current.reconnect, - S.current.rescan, S.current.wallets, + S.current.nodes, S.current.show_seed, S.current.show_keys, - S.current.accounts, - S.current.address_book_menu + S.current.address_book_menu, + S.current.settings_title + ]; + + final List images = [ + Image.asset('assets/images/reconnect.png'), + Image.asset('assets/images/wallet.png'), + Image.asset('assets/images/nodes.png'), + Image.asset('assets/images/eye.png'), + Image.asset('assets/images/key.png'), + Image.asset('assets/images/open_book.png'), + Image.asset('assets/images/settings.png'), ]; final BuildContext context; @@ -26,11 +36,10 @@ class WalletMenu { _presentReconnectAlert(context); break; case 1: - Navigator.of(context).pushNamed(Routes.rescan); + Navigator.of(context).pushNamed(Routes.walletList); break; case 2: - Navigator.of(context).pushNamed(Routes.walletList); - + // FIXME: apply Nodes break; case 3: Navigator.of(context).pushNamed(Routes.auth, @@ -49,10 +58,10 @@ class WalletMenu { : null); break; case 5: - Navigator.of(context).pushNamed(Routes.accountList); + Navigator.of(context).pushNamed(Routes.addressBook); break; case 6: - Navigator.of(context).pushNamed(Routes.addressBook); + Navigator.of(context).pushNamed(Routes.settings); break; default: break; diff --git a/lib/src/screens/dashboard/widgets/menu_widget.dart b/lib/src/screens/dashboard/widgets/menu_widget.dart new file mode 100644 index 000000000..a37e505d2 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/menu_widget.dart @@ -0,0 +1,205 @@ +import 'dart:async'; +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart'; +import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; +import 'package:provider/provider.dart'; + +class MenuWidget extends StatefulWidget { + @override + MenuWidgetState createState() => MenuWidgetState(); +} + +class MenuWidgetState extends State { + final moneroIcon = Image.asset('assets/images/monero.png'); + double menuWidth; + double screenWidth; + double opacity; + bool isDraw; + + @override + void initState() { + menuWidth = 0; + screenWidth = 0; + opacity = 0; + isDraw = false; + super.initState(); + WidgetsBinding.instance.addPostFrameCallback(afterLayout); + } + + void afterLayout(dynamic _) { + screenWidth = MediaQuery.of(context).size.width; + setState(() { + menuWidth = screenWidth; + opacity = 1; + }); + Timer(Duration(milliseconds: 350), () => + setState(() => isDraw = true) + ); + } + + @override + Widget build(BuildContext context) { + final walletMenu = WalletMenu(context); + final walletStore = Provider.of(context); + final itemCount = walletMenu.items.length; + + return GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: Container( + color: Colors.transparent, + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0), + child: Container( + decoration: BoxDecoration(color: PaletteDark.historyPanel.withOpacity(0.75)), + child: Padding( + padding: EdgeInsets.only(left: 40), + child: GestureDetector( + onTap: () => null, + child: Container( + width: double.infinity, + height: double.infinity, + alignment: Alignment.centerRight, + child: AnimatedContainer( + alignment: Alignment.centerLeft, + width: menuWidth, + height: double.infinity, + duration: Duration(milliseconds: 500), + curve: Curves.fastOutSlowIn, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(24), bottomLeft: Radius.circular(24)), + color: PaletteDark.menuList.withOpacity(opacity) + ), + child: isDraw + ? ListView.separated( + itemBuilder: (_, index) { + + if (index == 0) { + return Container( + height: 144, + padding: EdgeInsets.only(left: 24, top: 69, right: 24, bottom: 35), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(24)), + color: PaletteDark.menuHeader + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + moneroIcon, + SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + walletStore.name, + style: TextStyle( + color: Colors.white, + decoration: TextDecoration.none, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ), + Text( + walletStore.account.label, + style: TextStyle( + color: PaletteDark.walletCardText, + decoration: TextDecoration.none, + fontFamily: 'Lato', + fontSize: 12 + ), + ) + ], + ) + ) + ], + ), + ); + } + + index -= 1; + final item = walletMenu.items[index]; + final image = walletMenu.images[index] ?? Offstage(); + + return GestureDetector( + onTap: () { + Navigator.of(context).pop(); + walletMenu.action(index); + }, + child: index == itemCount - 1 + ? Container( + height: 144, + padding: EdgeInsets.only(left: 24, right: 24, top: 35, bottom: 69), + alignment: Alignment.topLeft, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)), + color: PaletteDark.menuList, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 16), + Expanded( + child: Text( + item, + style: TextStyle( + decoration: TextDecoration.none, + color: Colors.white, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ) + ) + ], + ), + ) + : Container( + height: 91, + padding: EdgeInsets.only(left: 24, right: 24), + color: PaletteDark.menuList, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 16), + Expanded( + child: Text( + item, + style: TextStyle( + decoration: TextDecoration.none, + color: Colors.white, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ) + ) + ], + ), + ), + ); + }, + separatorBuilder: (_, index) => + Divider( + height: 1, + color: PaletteDark.walletCardText, + ), + itemCount: itemCount + 1) + : Offstage() + ), + ), + ) + ), + ), + ), + ), + ); + } +} \ No newline at end of file From f5e1635380dee7237edaabc39c3bb7210fe83c9c Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Wed, 22 Apr 2020 19:40:16 +0300 Subject: [PATCH 10/51] CWA-200 | calculated list tile heights for large screens --- .../dashboard/widgets/menu_widget.dart | 329 +++++++++++------- 1 file changed, 194 insertions(+), 135 deletions(-) diff --git a/lib/src/screens/dashboard/widgets/menu_widget.dart b/lib/src/screens/dashboard/widgets/menu_widget.dart index a37e505d2..6621cb22a 100644 --- a/lib/src/screens/dashboard/widgets/menu_widget.dart +++ b/lib/src/screens/dashboard/widgets/menu_widget.dart @@ -13,27 +13,53 @@ class MenuWidget extends StatefulWidget { class MenuWidgetState extends State { final moneroIcon = Image.asset('assets/images/monero.png'); + final largeScreen = 731; + double menuWidth; double screenWidth; + double screenHeight; double opacity; bool isDraw; + double headerHeight; + double tileHeight; + double fromTopEdge; + double fromBottomEdge; + @override void initState() { menuWidth = 0; screenWidth = 0; + screenHeight = 0; opacity = 0; isDraw = false; + + headerHeight = 120; + tileHeight = 75; + fromTopEdge = 50; + fromBottomEdge = 30; + super.initState(); WidgetsBinding.instance.addPostFrameCallback(afterLayout); } void afterLayout(dynamic _) { screenWidth = MediaQuery.of(context).size.width; + screenHeight = MediaQuery.of(context).size.height; + setState(() { menuWidth = screenWidth; opacity = 1; + + if (screenHeight > largeScreen) { + final scale = screenHeight / largeScreen; + tileHeight *= scale; + headerHeight *= scale; + fromTopEdge *= scale; + fromBottomEdge *= scale; + } }); + Timer(Duration(milliseconds: 350), () => setState(() => isDraw = true) ); @@ -53,150 +79,183 @@ class MenuWidgetState extends State { filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0), child: Container( decoration: BoxDecoration(color: PaletteDark.historyPanel.withOpacity(0.75)), - child: Padding( - padding: EdgeInsets.only(left: 40), - child: GestureDetector( - onTap: () => null, - child: Container( - width: double.infinity, - height: double.infinity, - alignment: Alignment.centerRight, - child: AnimatedContainer( - alignment: Alignment.centerLeft, - width: menuWidth, - height: double.infinity, - duration: Duration(milliseconds: 500), - curve: Curves.fastOutSlowIn, + child: Row( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(left: 24), + child: isDraw + ? Container( + height: 60, + width: 4, decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(24), bottomLeft: Radius.circular(24)), - color: PaletteDark.menuList.withOpacity(opacity) + borderRadius: BorderRadius.all(Radius.circular(2)), + color: PaletteDark.walletCardText ), - child: isDraw - ? ListView.separated( - itemBuilder: (_, index) { + ) + : Container( + height: 60, + width: 4, + ) + ), + SizedBox(width: 12), + Expanded( + child: GestureDetector( + onTap: () => null, + child: Container( + width: double.infinity, + height: double.infinity, + alignment: Alignment.centerRight, + child: AnimatedContainer( + alignment: Alignment.centerLeft, + width: menuWidth, + height: double.infinity, + duration: Duration(milliseconds: 500), + curve: Curves.fastOutSlowIn, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(24), bottomLeft: Radius.circular(24)), + color: PaletteDark.menuList.withOpacity(opacity) + ), + child: isDraw + ? ListView.separated( + itemBuilder: (_, index) { - if (index == 0) { - return Container( - height: 144, - padding: EdgeInsets.only(left: 24, top: 69, right: 24, bottom: 35), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(24)), - color: PaletteDark.menuHeader - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - moneroIcon, - SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, + if (index == 0) { + return Container( + height: headerHeight, + padding: EdgeInsets.only( + left: 24, + top: fromTopEdge, + right: 24, + bottom: fromBottomEdge), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(24)), + color: PaletteDark.menuHeader + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, children: [ - Text( - walletStore.name, - style: TextStyle( - color: Colors.white, - decoration: TextDecoration.none, - fontFamily: 'Lato', - fontSize: 20, - fontWeight: FontWeight.bold - ), - ), - Text( - walletStore.account.label, - style: TextStyle( - color: PaletteDark.walletCardText, - decoration: TextDecoration.none, - fontFamily: 'Lato', - fontSize: 12 - ), + moneroIcon, + SizedBox(width: 16), + Expanded( + child: Container( + height: 40, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + walletStore.name, + style: TextStyle( + color: Colors.white, + decoration: TextDecoration.none, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ), + Text( + walletStore.account.label, + style: TextStyle( + color: PaletteDark.walletCardText, + decoration: TextDecoration.none, + fontFamily: 'Lato', + fontSize: 12 + ), + ) + ], + ), + ) ) ], - ) - ) - ], - ), - ); - } + ), + ); + } - index -= 1; - final item = walletMenu.items[index]; - final image = walletMenu.images[index] ?? Offstage(); + index -= 1; + final item = walletMenu.items[index]; + final image = walletMenu.images[index] ?? Offstage(); - return GestureDetector( - onTap: () { - Navigator.of(context).pop(); - walletMenu.action(index); - }, - child: index == itemCount - 1 - ? Container( - height: 144, - padding: EdgeInsets.only(left: 24, right: 24, top: 35, bottom: 69), - alignment: Alignment.topLeft, - decoration: BoxDecoration( - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)), - color: PaletteDark.menuList, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image, - SizedBox(width: 16), - Expanded( - child: Text( - item, - style: TextStyle( - decoration: TextDecoration.none, - color: Colors.white, - fontFamily: 'Lato', - fontSize: 20, - fontWeight: FontWeight.bold - ), - ) + return GestureDetector( + onTap: () { + Navigator.of(context).pop(); + walletMenu.action(index); + }, + child: index == itemCount - 1 + ? Container( + height: headerHeight, + padding: EdgeInsets.only( + left: 24, + right: 24, + top: fromBottomEdge, + bottom: fromTopEdge), + alignment: Alignment.topLeft, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)), + color: PaletteDark.menuList, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 16), + Expanded( + child: Text( + item, + style: TextStyle( + decoration: TextDecoration.none, + color: Colors.white, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ) + ) + ], + ), ) - ], - ), - ) - : Container( - height: 91, - padding: EdgeInsets.only(left: 24, right: 24), - color: PaletteDark.menuList, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image, - SizedBox(width: 16), - Expanded( - child: Text( - item, - style: TextStyle( - decoration: TextDecoration.none, - color: Colors.white, - fontFamily: 'Lato', - fontSize: 20, - fontWeight: FontWeight.bold - ), - ) - ) - ], - ), - ), - ); - }, - separatorBuilder: (_, index) => - Divider( - height: 1, - color: PaletteDark.walletCardText, - ), - itemCount: itemCount + 1) - : Offstage() - ), - ), - ) - ), + : Container( + height: tileHeight, + padding: EdgeInsets.only(left: 24, right: 24), + color: PaletteDark.menuList, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 16), + Expanded( + child: Text( + item, + style: TextStyle( + decoration: TextDecoration.none, + color: Colors.white, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ) + ) + ], + ), + ), + ); + }, + separatorBuilder: (_, index) => + Divider( + height: 1, + color: PaletteDark.walletCardText, + ), + itemCount: itemCount + 1) + : Offstage() + ), + ), + ) + ) + ], + ) ), ), ), From 07aaf7716711eecd1025b3a34ff1a09477caf582 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Thu, 23 Apr 2020 21:36:52 +0300 Subject: [PATCH 11/51] CWA-201 | added wallet tiles to wallet list page; added colors and images to wallet menu --- assets/images/2.0x/load.png | Bin 0 -> 1722 bytes assets/images/2.0x/scanner.png | Bin 0 -> 1374 bytes assets/images/2.0x/trash.png | Bin 0 -> 913 bytes assets/images/3.0x/load.png | Bin 0 -> 2760 bytes assets/images/3.0x/scanner.png | Bin 0 -> 1950 bytes assets/images/3.0x/trash.png | Bin 0 -> 1278 bytes assets/images/load.png | Bin 0 -> 831 bytes assets/images/scanner.png | Bin 0 -> 771 bytes assets/images/trash.png | Bin 0 -> 506 bytes .../screens/wallet_list/wallet_list_page.dart | 334 +++++++++++++----- lib/src/screens/wallet_list/wallet_menu.dart | 36 ++ 11 files changed, 286 insertions(+), 84 deletions(-) create mode 100644 assets/images/2.0x/load.png create mode 100644 assets/images/2.0x/scanner.png create mode 100644 assets/images/2.0x/trash.png create mode 100644 assets/images/3.0x/load.png create mode 100644 assets/images/3.0x/scanner.png create mode 100644 assets/images/3.0x/trash.png create mode 100644 assets/images/load.png create mode 100644 assets/images/scanner.png create mode 100644 assets/images/trash.png diff --git a/assets/images/2.0x/load.png b/assets/images/2.0x/load.png new file mode 100644 index 0000000000000000000000000000000000000000..a7b64ee0447d60d623da8d669a6fd22eeb0aea50 GIT binary patch literal 1722 zcmV;r21WUaP)ItH^G$pBx|ul>v^B!{i9Lk(`f41C@G_JWTdk z1{kyqaFp!I!w4nh1S)eO#U9nBFSnFRrQ4Aq%E%Az#^jgkkpPC`nsJBu>+k(VKS z*a31cC#%nWt5D?vD{UJ=vkw^}l>w;y%M_0x`sT{&+G>ioXowAtqI<31<~Sd(J|=$; zGKBXKpn|VcJc`yIJlSJmAv$WZAwY<-F>@PyJ*9hm(FtdFM zr&$GT1C$V5&jTwj7F4dCqMZ+U1?7D5Y_gx+%4=zty%xKAC1;TTCY1FyfUTUpWK~qU zV&wHFRjO8pPD~C5$vLQXs*d;+_89^@5kKa&tQcvX{~Pkb&!kLv<_r0S#y#Lu*rx~l zfY93$4^WgVqqav#p857S@B#io4q!VHU-*{Ei&fSEU**Tj``p9^?xA?iDC7ES)9fK1 z%*z0ig_k2lWxk?#PyN(g-X&$+KUEav1>UYOm3kkcE3B2%O6y^;gIvn{en)}eH3V#M zNQiGB9^x6~Ai0Z*52A@CnkX7#=Kzj#8QvI%w9fwkG@t?H_W5> z(#W$z)ApzD2dv~n6aduiUWCdEv>xKO?2-)a3Er&lN7c18J-xuXb_WUoDld^DiA>qw zEsIsJ7&m}Sd~x9}7w58q8JPZ%@R%8IG^0kB$_@H+Sd@wT-q-2GNY6BcM4If47cIwj zt8@?OMf9uA?(%m2Aji-Ura%5u(vCO_4#D^#fk->TV@or=8^yqO)W$4C2YGoCNeT_X zx49MJ8t+oxH6Of#0zkzjWG_ONY%^dZ5vu_p>IclFSchtq)fEPp``5GZdK3(5Q+Jfl zK5FLMo}d_EEy5`4Se9{Fx{WCR1sVv>k0BaDwy&;4b#?fY+*pu_uZbp_Xrc*UOf)Pm zyShSIA!HL$4n!pG#7;+~G5{49|KNF4&;6PFo?J&mcGd4Gr^Mv#o5x*k1DI$-eprHNpaZBHp;c|+)rD^lXhl`giXj6lEpiqc zJ{=i@ZAi3drv9m)-W4A6qwPi5V(E0WZLeBe4_XI@K$?-?Q2i3?ZAY%GtH&p~7l ziC@^^E*ql>b$IuHzYu;71Mz`UjUSN$a-NV}NS>3X9F06e@e>ex$XZr_?Md}`^#EDh z`GB7?xdL!Tjf-bA4uy6 zJwUPCXiT8zg<WsMm=j-&;Rg*+Rt2|ejX;b`S<{W)UL2PntCUB z9VxTDxWJpq4mLXMQC?=|7vPROL;dbzU2h`?Oz2x+GN1vTLFlO1tBD6y!ZiWwotqBigxpsF4dwaCC+kA;G=v+O+sIAI%gY7F0cr8MVGIfz Q5C8xG07*qoM6N<$f&)V-VE_OC literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/scanner.png b/assets/images/2.0x/scanner.png new file mode 100644 index 0000000000000000000000000000000000000000..e32b970ae89138514128c8e85c4bb765da49d5d0 GIT binary patch literal 1374 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 O0000(Mv5CSylV@9JfKq7IT^wyT? zjBW2|&z5a>a3Zj0U7;IWAvkTO8Tvtjv#B+s1o=zq!;_rfne=@Meo*0G!0~ele(aR< z8HA%^ZQQ?b{QM082_*pPT>gR+fW2fT`&d9|Sld+S8Z1aS!-{XNDbkIcCS((oa3BdF zGD!fDNdkyW5aE0y_ny*{1j~hzMw(llG zAWL^I?(H9zX5Er!eSI5R@3k}R2BtQ802MxRKcOE>>AE^H!*zdX(iTb@-OKde@Z7#!8uHdDw>tv+ z)dz@b`~`Tm2JzWsUhuVi<}LYLSX}qALz>JYzaVJL7WDg3PIIoDK<(t3Bsu`YT8a7= zFozMr%JGps#|!&yv|h!Q~JadJbLZUVtT{bd^R0*FlLCMYB{Zr8P&&(Pz@<4Io1kyEqx^?(NR}`PQz3+0ny5+B*#%a?tg=^T=G#r-x-=r zTx+X2b|>A-LOIr|M6onW41-tG=A($^&_Au~4TO-?LYQOwo0&rxa`3=M0DTW5+w4Jg z`)`{6Z4+JzVJN`^Up;`v&$aJONGjlC^BNj!%S(GmIN!k!$}@-E&fNxj0agRkXZnK) z`v$oy%)Q*aAn#0dcr7Ku4jq38hCCmzgD|*_*63y;O-V*32_P~_0Fg18B9QxAx>yKf zkZbl;5I#?%gO!2WQSGbAY@!ta_TYeY;*c%sv+jVY2|Ag$4+o+!Y33#YoWhFtLsFTV zAd>*rpm(xOxUn)FXq*pV)y8G{(G2$efXb$u@PzK~S+n2dS*Nnn>{~!MSC{IbUK<88 z?-F{#*A!tm_XZ9`(gPwh2wM>HX+au!xmZ=>%t!?yx&VaEK`RH3#^Kh6Av8gK%qNV7 zAqb$a!v7COzz_t`$BfcyEMYXG_W@#R^BU}398J);`w>nR)UTj_f`NkE<4&e2I>3XN zs(c^pGvU6&(-u2AOT_@W+atX+8}XSN(&-ewLApEEH+zrD1bWLkWHFp$powqf&RWZW z`OP%~*uXI$skdAOn6JsUfH;_RgmB@LknQlN4y~Xy#_$n!P4-sl$SI) z^ogLM2tXYgu2feJ(u&zeF(UGMW4}MK%|~%sL1aSr0hz(3()gx{pwa_4O!^6#@Bbr(mdod)SPQBGy^`Wh@u&G zgsi1Gi~!^{taiD1Rr{-RCGj&zHX8Q(lL)3XG+?Bs%qbIfa@?BoZO{AD2L!RN~9nivR!s07*qoM6N<$g3>*d(EtDd literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/trash.png b/assets/images/3.0x/trash.png new file mode 100644 index 0000000000000000000000000000000000000000..86a73d9314f7a76d935b457f19491a59db322769 GIT binary patch literal 1278 zcmV3r7nO1mqa3@D@Px`jQ~_SkfCZ0vDu4}*pu*Fc?Y!w(5@1V!vY5w3yki$Pw< z9>;rodyi1SJ1D_6{yFkDKKjr21SO~uz;cFiETM$=(9a#xSPq;sP=a~^Y+t=X0&e7m zVl;I@vqX~x+#HlbZm$(;RE3F?M|x}etmun6jg*cQ;bA2vbVP)HZFK!eLZw_u0> z_t>r|XuJ*C;}^GZ=onzIjRTrB4CB%gU+ow`Xfzs)Mx&t{(Z#uauoj#VoEW!~UXGXm zGn*#}&inh2Tp4$X`5-nY(v~L1Ar^>A3NWYTeq!HMQUJnyAPCVcAP$ul@F$?`8r!*r zLkzE8=5WcbI0)C1BaKuHMks1|?_51~GWQHCH$4GS=+ z4?zhv1n@zq&j&^sf*^CX05v}pX#rB)GeS9h0?fh-GN{k21@Ivj+%WLnr@=S`L29_6 z2K7;sPS#`rB^xEB3nB<2DgZN^XgueqB7j&X)RALV1R)MWIidxS-fgkUvJ{*4J(1G!5Yp7l0X1`8KJQC-BkoAhm8R#h0TzQB!~#`5;0(Vh`p$CyM~g!Bo?;VrHy>}r zRpu06O0mFLP`Hx<)EEQQrATUaL7D{MctKgHX#vJ_K8w586Dt5A6LT8_Vkct=naC-? znA?_O_OJ3tZmStgkeaI^eE&4T*$io@%sIwczC6+AftDln2vfr~E@R`PjXlo#@=lPe zj?cQU~5(20{7U8 oaD(k%VQGi3-AwkdzxS;C1x=A0?-@sFZU6uP07*qoM6N<$g8tMlSO5S3 literal 0 HcmV?d00001 diff --git a/assets/images/load.png b/assets/images/load.png new file mode 100644 index 0000000000000000000000000000000000000000..30281cf3ce0c8e48cd280b11a6f63249a8f225f8 GIT binary patch literal 831 zcmV-F1Hk-=P)C&sOs9@udAx7yG4prE|=Q}&tVu| z!6_-1Fl&M|44D8%;4_?;atNai7_&+5D6(J_8 z;Ve9Y7HG7phvfHiWIDoZ6|}({=!Un@0|%`(*I@uMW(mg3^nZuAL{QKS9D{20@zKoS z3r!o{@ja&8))~iflD->S2fLslz)NBQW$R&FCQqdXI$zwiPhj$b0e6!>0!ttRHz|J@ zFkZdsUrV1Z+N7rnARQ2Z7eudj!9Y3#CuM4Vf)y|VqyEaE04~8clOOl|;3}pWi75Kq zN{M@*dAy4;&FxIhGcM|^h8oOmDY5WM;nhlZ5%lW8 z=50bf=MRYcE+2+gD(}dQ{-s!!dHVSU%j7T02{GSJ(hPIN-H37&N*GF`x{sS<;Q;BA-NBbT#P94{a8RLQ7rXrw|9za!=xtGQzx@s&BP3!#) zg1!m+0?al27|>P&u99%+*Oe~wER!bv4GNZkDbl~3D`Xob|3TVKd7IBzUns|+l6*hu zE!sTsjdhng?OzLBaKFG$LPWofBuby(+|-|t{Ch-?ZvEanP1`Yvps-D-(I-d};az{d zQYV^=yJ>YfQW8Otf6XlQ%j6jx)U#e9YB~X2gmx2z8lRIQ^b<3>j1k26Dp~*l002ov JPDHLkV1l|GXaxWO literal 0 HcmV?d00001 diff --git a/assets/images/scanner.png b/assets/images/scanner.png new file mode 100644 index 0000000000000000000000000000000000000000..dda28983a1067b9f538d207eb88252aac15e5b5c GIT binary patch literal 771 zcmV+e1N{7nP)leK~#7F?N`xp z+b|4;dLBRH@x0;dz0ognE1EM5r45KPMIotpmS z-QgsHAOL{?NEO8J-k1CUMZ6Y8@k%3tZB%;9`kkIU_)|1A5?I%DLjN9f6Y&h>m|C^Y z(Rg@fTC4FT#fZZJ@n}UK1c~?o?_cOY0}gbOO(L?7UJ7AcGHsdel-xGvN@DI{b)+1a zAlrEod-79w6;myaflA>`nP9AD`KjMqe96Eo)3a_b8bgtrJ$MIQqv{h^bDj=CoxoT?Lii&|t`#jAu6^3=WJ{9QvQ zn&Q>M*R;1=FeLO56B-B~4xKHHj6Mf!m=MloM%HEcsF=6NQD|m4xiqAuR%To$cM(8;Fi-(r?n zcQ7(n37L}|;P=ZYi~oYRaLL!jBlU^QeSqm#!gt8kN@kak0sr32Ekysr=YN5Yz>Dwx z2h=nYWX}(Z{CfnXJ=#+X`{QXm*qgPZp;xqjjX&OO^L)jI0m1+P002ovPDHLkV1f>k BRw4iZ literal 0 HcmV?d00001 diff --git a/assets/images/trash.png b/assets/images/trash.png new file mode 100644 index 0000000000000000000000000000000000000000..990140214f7d09918510499d90a9982e6afc6d31 GIT binary patch literal 506 zcmVE#0w*0w5 z1vpZN$wn;T+1BIrm#AoP!=DrCvf)S!p%5>^Dxr_KlZErB^2q4{b$P*GqRCb8df4&j z66-)b?@uTc;1;97dIGkoim{V$i1LR-8@FaiVINS6+p}W--g{eo5xL8$P3?6zg=70a zFctwy{DPxwz+ol1r=zx0wn+i9lYySl?;>HFEg(S93ura{#sqXCZ=fe7U{(ZDbc!~s z2_TU-(6ibUkkY0R@QxV*BnEm?;qFl?!0qvbnV`oAUtO^P&k#FPKp7v41bmW-N)D6q zQ7V8!hR<`=)tm@7VS#{Ir=cx)9hC^!U>Z`|)B;H4!{ws6+fBwtu>d*Pt^Inmd>=4e wzK+7(`tmyeuKfT@xxo_b&x?2tk5m3X07#hDM*b*$yZ`_I07*qoM6N<$f(?h;7ytkO literal 0 HcmV?d00001 diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index da41eb8de..4d5f1f262 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -6,22 +6,15 @@ import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/domain/common/wallet_description.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/stores/wallet_list/wallet_list_store.dart'; import 'package:cake_wallet/src/screens/wallet_list/wallet_menu.dart'; -import 'package:cake_wallet/src/widgets/picker.dart'; class WalletListPage extends BasePage { - @override - bool get isModalBackButton => true; @override - String get title => S.current.wallet_list_title; - - @override - AppBarStyle get appBarStyle => AppBarStyle.withShadow; + ObstructingPreferredSizeWidget appBar(BuildContext context) => null; @override Widget body(BuildContext context) => WalletListBody(); @@ -33,92 +26,265 @@ class WalletListBody extends StatefulWidget { } class WalletListBodyState extends State { + final moneroIcon = Image.asset('assets/images/monero.png', height: 24, width: 24); WalletListStore _walletListStore; - void presetMenuForWallet(WalletDescription wallet, bool isCurrentWallet, - BuildContext bodyContext) { - final walletMenu = WalletMenu(bodyContext); - final items = walletMenu.generateItemsForWalletMenu(isCurrentWallet); - - showDialog( - context: bodyContext, - builder: (_) => Picker( - items: items, - selectedAtIndex: -1, - title: S.of(context).wallet_menu, - onItemSelected: (String item) => walletMenu.action( - walletMenu.listItems.indexOf(item), wallet, isCurrentWallet)), - ); - } - @override Widget build(BuildContext context) { _walletListStore = Provider.of(context); - return ScrollableWithBottomSection( - content: Container( - padding: EdgeInsets.all(20), - child: Observer( - builder: (_) => ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (_, index) => Divider( - color: Theme.of(context).dividerTheme.color, height: 1.0), - itemCount: _walletListStore.wallets.length, - itemBuilder: (__, index) { - final wallet = _walletListStore.wallets[index]; - final isCurrentWallet = + return SafeArea( + child: Container( + padding: EdgeInsets.only(top: 32), + color: PaletteDark.menuHeader, + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.only(bottom: 20), + content: Container( + child: Observer( + builder: (_) => ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (_, index) => Divider( + color: PaletteDark.menuHeader, height: 16), + itemCount: _walletListStore.wallets.length, + itemBuilder: (__, index) { + final wallet = _walletListStore.wallets[index]; + final screenWidth = MediaQuery.of(context).size.width; + + final isCurrentWallet = _walletListStore.isCurrentWallet(wallet); - return InkWell( - onTap: () => - presetMenuForWallet(wallet, isCurrentWallet, context), - child: Container( - padding: EdgeInsets.only(left: 10.0, right: 10.0), - child: ListTile( - title: Text( - wallet.name, - style: TextStyle( - color: isCurrentWallet - ? Palette.cakeGreen - : Theme.of(context) - .primaryTextTheme - .headline - .color, - fontSize: 18.0, - fontWeight: FontWeight.w600), + final walletMenu = WalletMenu(context); + final items = walletMenu.generateItemsForWalletMenu(isCurrentWallet); + final colors = walletMenu.generateColorsForWalletMenu(isCurrentWallet); + final images = walletMenu.generateImagesForWalletMenu(isCurrentWallet); + + return Container( + height: 108, + width: double.infinity, + child: CustomScrollView( + scrollDirection: Axis.horizontal, + slivers: [ + SliverPersistentHeader( + pinned: false, + floating: true, + delegate: WalletTile( + min: screenWidth - 228, + max: screenWidth, + image: moneroIcon, + walletName: wallet.name, + walletAddress: '', + isCurrent: isCurrentWallet ), - trailing: isCurrentWallet - ? Icon( - Icons.check, - color: Palette.cakeGreen, - size: 20.0, - ) - : null))); - }), - ), - ), - bottomSection: Column(children: [ - PrimaryIconButton( - onPressed: () => Navigator.of(context).pushNamed(Routes.newWallet), - iconData: Icons.add, - color: Theme.of(context).primaryTextTheme.button.backgroundColor, - borderColor: + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + + final item = items[index]; + final color = colors[index]; + final image = images[index]; + + final content = Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + image, + SizedBox(height: 5), + Text( + item, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: Colors.white + ), + ) + ], + ), + ); + + if (index == 0) { + return GestureDetector( + onTap: () => walletMenu.action( + walletMenu.listItems.indexOf(item), wallet, isCurrentWallet), + child: Container( + height: 108, + width: 108, + color: PaletteDark.menuHeader, + child: Container( + padding: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12) + ), + color: color + ), + child: content, + ), + ), + ); + } + + return GestureDetector( + onTap: () => walletMenu.action( + walletMenu.listItems.indexOf(item), wallet, isCurrentWallet), + child: Container( + height: 108, + width: 108, + padding: EdgeInsets.only(left: 5, right: 5), + color: color, + child: content, + ), + ); + }, + childCount: items.length + ) + ) + ], + ), + ); + }), + ), + ), + bottomSection: Column(children: [ + PrimaryIconButton( + onPressed: () => Navigator.of(context).pushNamed(Routes.newWallet), + iconData: Icons.add, + color: Theme.of(context).primaryTextTheme.button.backgroundColor, + borderColor: Theme.of(context).primaryTextTheme.button.decorationColor, - iconColor: Palette.violet, - iconBackgroundColor: Theme.of(context).primaryIconTheme.color, - text: S.of(context).wallet_list_create_new_wallet), - SizedBox(height: 10.0), - PrimaryIconButton( - onPressed: () => - Navigator.of(context).pushNamed(Routes.restoreWalletOptions), - iconData: Icons.refresh, - text: S.of(context).wallet_list_restore_wallet, - color: Theme.of(context).accentTextTheme.button.backgroundColor, - borderColor: + iconColor: Palette.violet, + iconBackgroundColor: Theme.of(context).primaryIconTheme.color, + text: S.of(context).wallet_list_create_new_wallet), + SizedBox(height: 10.0), + PrimaryIconButton( + onPressed: () => + Navigator.of(context).pushNamed(Routes.restoreWalletOptions), + iconData: Icons.refresh, + text: S.of(context).wallet_list_restore_wallet, + color: Theme.of(context).accentTextTheme.button.backgroundColor, + borderColor: Theme.of(context).accentTextTheme.button.decorationColor, - iconColor: Theme.of(context).primaryTextTheme.caption.color, - iconBackgroundColor: Theme.of(context).accentIconTheme.color) - ])); + iconColor: Theme.of(context).primaryTextTheme.caption.color, + iconBackgroundColor: Theme.of(context).accentIconTheme.color) + ])), + ) + ); } } + +class WalletTile extends SliverPersistentHeaderDelegate { + WalletTile({ + @required this.min, + @required this.max, + @required this.image, + @required this.walletName, + @required this.walletAddress, + @required this.isCurrent + }); + + final double min; + final double max; + final Image image; + final String walletName; + final String walletAddress; + final bool isCurrent; + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + + double opacity = 1 - shrinkOffset / (max - min); + opacity = opacity >= 0 ? opacity : 0; + + double panelWidth = 12 * opacity; + panelWidth = panelWidth < 12 ? 0 : 12; + + final currentColor = isCurrent + ? Colors.white + : PaletteDark.menuHeader; + + return Stack( + fit: StackFit.expand, + overflow: Overflow.visible, + children: [ + Positioned( + top: 0, + right: max - 4, + child: Container( + height: 108, + width: 4, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topRight: Radius.circular(4), bottomRight: Radius.circular(4)), + color: currentColor + ), + ), + ), + Positioned( + top: 0, + right: 12, + child: Container( + height: 108, + width: max - 16, + padding: EdgeInsets.only(left: 20, right: 20), + color: PaletteDark.menuHeader, + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 10), + Text( + walletName, + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Colors.white + ), + ) + ], + ) + ], + ), + ), + ), + Positioned( + top: 0, + right: 0, + child: Opacity( + opacity: opacity, + child: Container( + height: 108, + width: panelWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(12), bottomLeft: Radius.circular(12)), + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + PaletteDark.walletCardTopEndSync, + PaletteDark.walletCardBottomEndSync + ] + ) + ), + ), + ) + ), + ], + ); + } + + @override + double get maxExtent => max; + + @override + double get minExtent => min; + + @override + bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; + +} diff --git a/lib/src/screens/wallet_list/wallet_menu.dart b/lib/src/screens/wallet_list/wallet_menu.dart index 0cb278047..1dcf27921 100644 --- a/lib/src/screens/wallet_list/wallet_menu.dart +++ b/lib/src/screens/wallet_list/wallet_menu.dart @@ -18,6 +18,20 @@ class WalletMenu { S.current.rescan ]; + final List listColors = [ + Colors.blue, + Colors.orange, + Colors.red, + Colors.green + ]; + + final List listImages = [ + Image.asset('assets/images/load.png', height: 32, width: 32, color: Colors.white), + Image.asset('assets/images/eye.png', height: 32, width: 32, color: Colors.white), + Image.asset('assets/images/trash.png', height: 32, width: 32, color: Colors.white), + Image.asset('assets/images/scanner.png', height: 32, width: 32, color: Colors.white) + ]; + List generateItemsForWalletMenu(bool isCurrentWallet) { final items = List(); @@ -29,6 +43,28 @@ class WalletMenu { return items; } + List generateColorsForWalletMenu(bool isCurrentWallet) { + final colors = List(); + + if (!isCurrentWallet) colors.add(listColors[0]); + if (isCurrentWallet) colors.add(listColors[1]); + if (!isCurrentWallet) colors.add(listColors[2]); + if (isCurrentWallet) colors.add(listColors[3]); + + return colors; + } + + List generateImagesForWalletMenu(bool isCurrentWallet) { + final images = List(); + + if (!isCurrentWallet) images.add(listImages[0]); + if (isCurrentWallet) images.add(listImages[1]); + if (!isCurrentWallet) images.add(listImages[2]); + if (isCurrentWallet) images.add(listImages[3]); + + return images; + } + void action(int index, WalletDescription wallet, bool isCurrentWallet) { final _walletListStore = Provider.of(context); From 28d8cd43dca3f3027cd2076e74490fdf27299cd8 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Thu, 23 Apr 2020 22:26:37 +0300 Subject: [PATCH 12/51] CWA-201 | added scroll controller to wallet list page --- .../screens/wallet_list/wallet_list_page.dart | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index 4d5f1f262..62591f7f3 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -28,6 +28,7 @@ class WalletListBody extends StatefulWidget { class WalletListBodyState extends State { final moneroIcon = Image.asset('assets/images/monero.png', height: 24, width: 24); WalletListStore _walletListStore; + ScrollController scrollController = ScrollController(); @override Widget build(BuildContext context) { @@ -64,6 +65,7 @@ class WalletListBodyState extends State { width: double.infinity, child: CustomScrollView( scrollDirection: Axis.horizontal, + controller: scrollController, slivers: [ SliverPersistentHeader( pinned: false, @@ -105,8 +107,11 @@ class WalletListBodyState extends State { if (index == 0) { return GestureDetector( - onTap: () => walletMenu.action( - walletMenu.listItems.indexOf(item), wallet, isCurrentWallet), + onTap: () { + scrollController.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); + walletMenu.action( + walletMenu.listItems.indexOf(item), wallet, isCurrentWallet); + }, child: Container( height: 108, width: 108, @@ -127,8 +132,11 @@ class WalletListBodyState extends State { } return GestureDetector( - onTap: () => walletMenu.action( - walletMenu.listItems.indexOf(item), wallet, isCurrentWallet), + onTap: () { + scrollController.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); + walletMenu.action( + walletMenu.listItems.indexOf(item), wallet, isCurrentWallet); + }, child: Container( height: 108, width: 108, From 6a799df7dafbeca8594ab0f639afa0dd7270d253 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Fri, 24 Apr 2020 15:01:19 +0300 Subject: [PATCH 13/51] CWA-201 | moved WalletTile class to wallet_tile.dart; changed design for PrimaryImageButton; changed background color for wallet_list_page; added short address to current wallet in the wallet_tile --- assets/images/2.0x/eye_action.png | Bin 0 -> 831 bytes assets/images/2.0x/new_wallet.png | Bin 0 -> 270 bytes assets/images/2.0x/restore_wallet.png | Bin 0 -> 451 bytes assets/images/3.0x/eye_action.png | Bin 0 -> 1307 bytes assets/images/3.0x/new_wallet.png | Bin 0 -> 474 bytes assets/images/3.0x/restore_wallet.png | Bin 0 -> 586 bytes assets/images/eye_action.png | Bin 0 -> 481 bytes assets/images/new_wallet.png | Bin 0 -> 182 bytes assets/images/restore_wallet.png | Bin 0 -> 271 bytes .../screens/wallet_list/wallet_list_page.dart | 240 +++++------------- lib/src/screens/wallet_list/wallet_menu.dart | 2 +- .../wallet_list/widgets/wallet_tile.dart | 135 ++++++++++ lib/src/widgets/primary_button.dart | 33 ++- 13 files changed, 216 insertions(+), 194 deletions(-) create mode 100644 assets/images/2.0x/eye_action.png create mode 100644 assets/images/2.0x/new_wallet.png create mode 100644 assets/images/2.0x/restore_wallet.png create mode 100644 assets/images/3.0x/eye_action.png create mode 100644 assets/images/3.0x/new_wallet.png create mode 100644 assets/images/3.0x/restore_wallet.png create mode 100644 assets/images/eye_action.png create mode 100644 assets/images/new_wallet.png create mode 100644 assets/images/restore_wallet.png create mode 100644 lib/src/screens/wallet_list/widgets/wallet_tile.dart diff --git a/assets/images/2.0x/eye_action.png b/assets/images/2.0x/eye_action.png new file mode 100644 index 0000000000000000000000000000000000000000..e05bb87d6238e213275483b086d33588088c7336 GIT binary patch literal 831 zcmV-F1Hk-=P)`u_@1oj5*21+MzH(V0%89B{3IWlIbHTgA z$-a|703;|96p>*VhG7_nVHk#Cyg3#$0|4&Ah2=w#Du`?4!nq^IAV2xKSS)_gYa}>a z1^E)h2RT6xKYIwW4&vyR={bEZJO_hriPrHQG8j_>(7K^qRTKs0OdS%;o>Q7R+>(8+oFK-0M& zYC{RzwF&n9|2jonxHQn?d-}BN_b#rdvxXjid)$qN2h*3rRZpLG{myI?wrOb~+z)u@ z*eCS;fSlB(s)h~^K}D+D;1)Vo30;zrkP4zUopP7sgFz@+5aBsyY-{Y1t|e#-BI}k~d69BON-%Q~R$|yzXjl!w5*P9!?5VYBzGXdh zX;EX~oDWY2BOdw8@A!b>HS|YZ4Rpt9+ZS~_1>`*_#UmcT-j?Hi@HCtcn0`F&uj%xh zA4u>{aYb<}TXp2Zu@&B|@P`q04%`~jshj!f=*^&J2J002ov JPDHLkV1j4icX|K- literal 0 HcmV?d00001 diff --git a/assets/images/2.0x/new_wallet.png b/assets/images/2.0x/new_wallet.png new file mode 100644 index 0000000000000000000000000000000000000000..1b92d6b2e6d7189d8b158a351dae6592c8b5156d GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9E$svykh8Km+7D9BhG z(gU|_@4MHdA2#i2CV1;f#Hz1wBY`_SrR6Ey(ld(mTcc_Oy7_@H-Sm@dhg#Sh96&Go`T|7YBThoi0aM zc0JNIhLre@d<$;D$>vfC`h<$26CxkD+8|ykI`aec-9E#P zx+zI;Qq~*Tc~#af>b$w?}@9fw%S4P8%*HON=u$c{A15jl|W tjNTwFz9p=LL~?AyqAC~GT1x!7e*k5uB9%Z$-H!kO002ovPDHLkV1fq1yV(E$ literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/eye_action.png b/assets/images/3.0x/eye_action.png new file mode 100644 index 0000000000000000000000000000000000000000..a45123d4dd38194bf49cd15be26b9b170b0ee9d5 GIT binary patch literal 1307 zcmV+$1?2jPP)VL$yIZBTZCY6EkFcmt^uSe-!X1a>EoJwciY=uRMKf}7k>4QscB@4!U5jkGyih#<&1*i3(}$X za_i+Yzm6eN26I4T^aTaOmoyBwUar0TKgQ@#!5hBx^2y6rjEk+8lHMY|U^6clUUnEi z&dY)_p_+ma(#*=sg_jwnQ&UJA+_3KF?}DBh>p7)Ud)d$w(-T6C-#{kKR0z@2*@6DE zg_k8{BF-UWL?qJ`+##LH%NZrY-_d+mDh^|I1VZClA)T)p1%+J2aCjOJ4i7@Qxq=Kk z&B7t1CaI3VC5CncLald@VT&X3eBymyLk5Q-(h_8AJ+tkolO4XrVW;nKL|-0qPGC41 zvQ!?v@j2vbJ+pg7U!NY8d(9xt_ezdS9JEuCSFnOCuI;AL-`SnU0SIk^^oV>z(je59 zPmpKPqH~FUT+k6D=xJjMsg#6JOC02>T6Fe}w5n$rE6C%JnvxJ2J*`Qzvxv?D{pr;s zK`5sNY`b&n1LX7lb9OCy9s1Kd?4c6{4{VOP7rvPdbXi37ra0YE0toX>nryn>h-Cjb zMiJ5N(4SNX%%IQZzTVS)<5O6r(&XUUEJCgpfMk#1Uul0-X3d&`Iv&n&DC$d`}L2%(LX3(I}pp!HOY2E zmlX2sHHF^I{WJX^e7SE9{Lk-{k88I5<6p=#00Sb6FHMcj#bx9kG-iAc@vjmkZy9mo`+RP5<<*9%i+ZA1;+$poLUHK*Yf9VBz@BB?+ zN0=sy1A2KXAV-H_6S-cJvfkF3zmNCU8hTU_og4)YdbpPIYVKR@H`en1cn-a^P)2ml zp+^zXsktDNw!06*EJ)ZKAq3QYSlh-QjzsH)cu9=)Mj@Z$)yvu%!<8&wWG~ zG4CP<;P=kZA^b7bt%-YuSVC}fE@c3r@!e24o*mDk%}jJ-OrXPM;Oyl(E1OsR>Vy#a2kCQ;(`I+K;Ig6ehWNowlHK zo}d44zxUn;3Jd$CkgkWx!GEW8_(v4T_LwxOaO7jLlLDcizQwrUG{e&e*&Ej(59=r> zq>BX&dsqjrj@=BEX2x_}4cEShlT!-Pp{8JTme23{xSBSa=-|Ve=G6cEhnikC+I&9H zJ&la19a+YaQc&pe9HQnQV>Gm37=~dOhG7_nVHk#C7=~dOhG7_nVHn2y;s<``VI!;A R6#f7J002ovPDHLkV1o7ya_0a5 literal 0 HcmV?d00001 diff --git a/assets/images/3.0x/new_wallet.png b/assets/images/3.0x/new_wallet.png new file mode 100644 index 0000000000000000000000000000000000000000..0590e02aea11c99fceef690bd2e4bee12ef6182f GIT binary patch literal 474 zcmV<00VV#4P)4my0u{PSCjBz7UHjWD>nE85JR>(H%05*^fU<2F$H_#2r2Dm|S0@&d9V#)(GO)l3I_};q*ye5~Q zOOxD%C=&o);h4}hfZtqR6#jErQSfs)QRpX0R6z=O5W^oe+dZ58UUt8I?AacRqWGko zu!xdv!PX+39oqxt;6%s{!x%1#9n{K*ghZ930WK)etcrL3%Nrv)C>i9RSDoZ?Kp; zBE}A61b*za4^KDP$r1yjlNGpC6C%$kogkdE zyCB9MCDWc~TRUZ2>c>!iLW`udg7$$12HFhIL${xW1pP#4O<{7@R(0h0R+0m?lnKPs zo5`W7h@E9K8VF>Ws5vx#7c^Gy*tW00e{@j8BV{Qvl;eY6H!Y#GU5I zkFIb$5oK4OWaErsqmq8}5fD}>g*9wX(s7dS7;(H`w1XHr-Z5JCovq2GzaM9&?G2mk;807*qoM6N<$g1ad8#{d8T literal 0 HcmV?d00001 diff --git a/assets/images/eye_action.png b/assets/images/eye_action.png new file mode 100644 index 0000000000000000000000000000000000000000..5ffd96f5589e3f6827cabe9e461d597d6451700b GIT binary patch literal 481 zcmV<70UrK|P)1ttb^lUD89XGrzO{_ zzEmzYxdfZdMRbB`Kxw%NIQ4<#sKgrr@eEF%Q48wPitTY}Qt4*960_&rJF+z}-@QIo z#!^XE1$;De&b@>C@P%^rF?P2Lynt7TTP<@|=J|VeB;G5f=c8dIchn{v#Ac7-{nAez zSg|v>beCZG_=Jw3pS%gg`3Uv}$DQ6Q&V{oGwrfSFsUp-bBJN@dF-U?|3DhV)(}T5G zH7eKl*2l<_e&G5sdV_H@x^%GRF_kT{1_ch5?JpEd->Lrn&-hc= z`^AnX*(SCX!CyFsxY75AH4ot=K9FQ Zed`0y%oVfleFhrK;OXk;vd$@?2>@aLJGlS= literal 0 HcmV?d00001 diff --git a/assets/images/restore_wallet.png b/assets/images/restore_wallet.png new file mode 100644 index 0000000000000000000000000000000000000000..a16b4744f5056b9166db38b6b719ddf617f92c19 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CH!3HFy_x^nYq&N#aB8wRqxP?KOkzv*x37{Zj zage(c!@6@aFM%AEbVpxD28NCO+sOnzeX zXzjr{%p7|*uor$VneSk8pi-;N1lccdp?9ua3NevI#)< OGI+ZBxvX { final moneroIcon = Image.asset('assets/images/monero.png', height: 24, width: 24); + final newWalletImage = Image.asset('assets/images/new_wallet.png', height: 12, width: 12, color: PaletteDark.historyPanel); + final restoreWalletImage = Image.asset('assets/images/restore_wallet.png', height: 12, width: 12, color: Colors.white,); WalletListStore _walletListStore; ScrollController scrollController = ScrollController(); @override Widget build(BuildContext context) { + final walletStore = Provider.of(context); _walletListStore = Provider.of(context); return SafeArea( child: Container( padding: EdgeInsets.only(top: 32), - color: PaletteDark.menuHeader, + color: PaletteDark.historyPanel, child: ScrollableWithBottomSection( contentPadding: EdgeInsets.only(bottom: 20), content: Container( @@ -46,7 +51,7 @@ class WalletListBodyState extends State { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), separatorBuilder: (_, index) => Divider( - color: PaletteDark.menuHeader, height: 16), + color: PaletteDark.historyPanel, height: 16), itemCount: _walletListStore.wallets.length, itemBuilder: (__, index) { final wallet = _walletListStore.wallets[index]; @@ -55,6 +60,13 @@ class WalletListBodyState extends State { final isCurrentWallet = _walletListStore.isCurrentWallet(wallet); + String shortAddress = ''; + + if (isCurrentWallet) { + shortAddress = walletStore.subaddress.address; + shortAddress = shortAddress.replaceRange(4, shortAddress.length - 4, '...'); + } + final walletMenu = WalletMenu(context); final items = walletMenu.generateItemsForWalletMenu(isCurrentWallet); final colors = walletMenu.generateColorsForWalletMenu(isCurrentWallet); @@ -75,7 +87,7 @@ class WalletListBodyState extends State { max: screenWidth, image: moneroIcon, walletName: wallet.name, - walletAddress: '', + walletAddress: shortAddress, isCurrent: isCurrentWallet ), ), @@ -87,49 +99,7 @@ class WalletListBodyState extends State { final color = colors[index]; final image = images[index]; - final content = Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - image, - SizedBox(height: 5), - Text( - item, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - color: Colors.white - ), - ) - ], - ), - ); - - if (index == 0) { - return GestureDetector( - onTap: () { - scrollController.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); - walletMenu.action( - walletMenu.listItems.indexOf(item), wallet, isCurrentWallet); - }, - child: Container( - height: 108, - width: 108, - color: PaletteDark.menuHeader, - child: Container( - padding: EdgeInsets.only(left: 5, right: 5), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(12), - bottomLeft: Radius.circular(12) - ), - color: color - ), - child: content, - ), - ), - ); - } + final radius = index == 0 ? 12.0 : 0.0; return GestureDetector( onTap: () { @@ -140,9 +110,34 @@ class WalletListBodyState extends State { child: Container( height: 108, width: 108, - padding: EdgeInsets.only(left: 5, right: 5), - color: color, - child: content, + color: PaletteDark.historyPanel, + child: Container( + padding: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(radius), + bottomLeft: Radius.circular(radius) + ), + color: color + ), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + image, + SizedBox(height: 5), + Text( + item, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: Colors.white + ), + ) + ], + ), + ), + ), ), ); }, @@ -156,143 +151,22 @@ class WalletListBodyState extends State { ), ), bottomSection: Column(children: [ - PrimaryIconButton( - onPressed: () => Navigator.of(context).pushNamed(Routes.newWallet), - iconData: Icons.add, - color: Theme.of(context).primaryTextTheme.button.backgroundColor, - borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor, - iconColor: Palette.violet, - iconBackgroundColor: Theme.of(context).primaryIconTheme.color, - text: S.of(context).wallet_list_create_new_wallet), + PrimaryImageButton( + onPressed: () => Navigator.of(context).pushNamed(Routes.newWallet), + image: newWalletImage, + text: S.of(context).wallet_list_create_new_wallet, + color: Colors.white, + textColor: PaletteDark.historyPanel), SizedBox(height: 10.0), - PrimaryIconButton( - onPressed: () => - Navigator.of(context).pushNamed(Routes.restoreWalletOptions), - iconData: Icons.refresh, - text: S.of(context).wallet_list_restore_wallet, - color: Theme.of(context).accentTextTheme.button.backgroundColor, - borderColor: - Theme.of(context).accentTextTheme.button.decorationColor, - iconColor: Theme.of(context).primaryTextTheme.caption.color, - iconBackgroundColor: Theme.of(context).accentIconTheme.color) + PrimaryImageButton( + onPressed: () => + Navigator.of(context).pushNamed(Routes.restoreWalletOptions), + image: restoreWalletImage, + text: S.of(context).wallet_list_restore_wallet, + color: PaletteDark.historyPanelButton, + textColor: Colors.white) ])), ) ); } } - -class WalletTile extends SliverPersistentHeaderDelegate { - WalletTile({ - @required this.min, - @required this.max, - @required this.image, - @required this.walletName, - @required this.walletAddress, - @required this.isCurrent - }); - - final double min; - final double max; - final Image image; - final String walletName; - final String walletAddress; - final bool isCurrent; - - @override - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - - double opacity = 1 - shrinkOffset / (max - min); - opacity = opacity >= 0 ? opacity : 0; - - double panelWidth = 12 * opacity; - panelWidth = panelWidth < 12 ? 0 : 12; - - final currentColor = isCurrent - ? Colors.white - : PaletteDark.menuHeader; - - return Stack( - fit: StackFit.expand, - overflow: Overflow.visible, - children: [ - Positioned( - top: 0, - right: max - 4, - child: Container( - height: 108, - width: 4, - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topRight: Radius.circular(4), bottomRight: Radius.circular(4)), - color: currentColor - ), - ), - ), - Positioned( - top: 0, - right: 12, - child: Container( - height: 108, - width: max - 16, - padding: EdgeInsets.only(left: 20, right: 20), - color: PaletteDark.menuHeader, - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image, - SizedBox(width: 10), - Text( - walletName, - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.white - ), - ) - ], - ) - ], - ), - ), - ), - Positioned( - top: 0, - right: 0, - child: Opacity( - opacity: opacity, - child: Container( - height: 108, - width: panelWidth, - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(12), bottomLeft: Radius.circular(12)), - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - PaletteDark.walletCardTopEndSync, - PaletteDark.walletCardBottomEndSync - ] - ) - ), - ), - ) - ), - ], - ); - } - - @override - double get maxExtent => max; - - @override - double get minExtent => min; - - @override - bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; - -} diff --git a/lib/src/screens/wallet_list/wallet_menu.dart b/lib/src/screens/wallet_list/wallet_menu.dart index 1dcf27921..a6f512e02 100644 --- a/lib/src/screens/wallet_list/wallet_menu.dart +++ b/lib/src/screens/wallet_list/wallet_menu.dart @@ -27,7 +27,7 @@ class WalletMenu { final List listImages = [ Image.asset('assets/images/load.png', height: 32, width: 32, color: Colors.white), - Image.asset('assets/images/eye.png', height: 32, width: 32, color: Colors.white), + Image.asset('assets/images/eye_action.png', height: 32, width: 32, color: Colors.white), Image.asset('assets/images/trash.png', height: 32, width: 32, color: Colors.white), Image.asset('assets/images/scanner.png', height: 32, width: 32, color: Colors.white) ]; diff --git a/lib/src/screens/wallet_list/widgets/wallet_tile.dart b/lib/src/screens/wallet_list/widgets/wallet_tile.dart new file mode 100644 index 000000000..cef7ea7e1 --- /dev/null +++ b/lib/src/screens/wallet_list/widgets/wallet_tile.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:cake_wallet/palette.dart'; + +class WalletTile extends SliverPersistentHeaderDelegate { + WalletTile({ + @required this.min, + @required this.max, + @required this.image, + @required this.walletName, + @required this.walletAddress, + @required this.isCurrent + }); + + final double min; + final double max; + final Image image; + final String walletName; + final String walletAddress; + final bool isCurrent; + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + + double opacity = 1 - shrinkOffset / (max - min); + opacity = opacity >= 0 ? opacity : 0; + + double panelWidth = 12 * opacity; + panelWidth = panelWidth < 12 ? 0 : 12; + + final currentColor = isCurrent + ? Colors.white + : PaletteDark.historyPanel; + + return Stack( + fit: StackFit.expand, + overflow: Overflow.visible, + children: [ + Positioned( + top: 0, + right: max - 4, + child: Container( + height: 108, + width: 4, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topRight: Radius.circular(4), bottomRight: Radius.circular(4)), + color: currentColor + ), + ), + ), + Positioned( + top: 0, + right: 12, + child: Container( + height: 108, + width: max - 16, + padding: EdgeInsets.only(left: 20, right: 20), + color: PaletteDark.historyPanel, + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 10), + Text( + walletName, + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Colors.white + ), + ) + ], + ), + isCurrent ? SizedBox(height: 5) : Offstage(), + isCurrent + ? Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(width: 34), + Text( + walletAddress, + style: TextStyle( + fontSize: 12, + color: PaletteDark.walletCardText + ), + ) + ], + ) + : Offstage() + ], + ), + ), + ), + Positioned( + top: 0, + right: 0, + child: Opacity( + opacity: opacity, + child: Container( + height: 108, + width: panelWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(12), bottomLeft: Radius.circular(12)), + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + PaletteDark.walletCardTopEndSync, + PaletteDark.walletCardBottomEndSync + ] + ) + ), + ), + ) + ), + ], + ); + } + + @override + double get maxExtent => max; + + @override + double get minExtent => min; + + @override + bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; + +} \ No newline at end of file diff --git a/lib/src/widgets/primary_button.dart b/lib/src/widgets/primary_button.dart index d87838830..21adfde8d 100644 --- a/lib/src/widgets/primary_button.dart +++ b/lib/src/widgets/primary_button.dart @@ -143,29 +143,42 @@ class PrimaryImageButton extends StatelessWidget { {@required this.onPressed, @required this.image, @required this.text, - this.color = Palette.purple, - this.borderColor = Palette.deepPink, - this.iconColor = Colors.black}); + @required this.color, + @required this.textColor}); final VoidCallback onPressed; final Image image; final Color color; - final Color borderColor; - final Color iconColor; + final Color textColor; final String text; @override Widget build(BuildContext context) { return ButtonTheme( minWidth: double.infinity, - height: 58.0, + height: 52.0, child: FlatButton( onPressed: onPressed, color: color, shape: RoundedRectangleBorder( - side: BorderSide(color: borderColor), - borderRadius: BorderRadius.circular(12.0)), - child: Row( + borderRadius: BorderRadius.circular(26.0)), + child:Center( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + image, + SizedBox(width: 15), + Text( + text, + style: TextStyle( + fontSize: 15, + color: textColor + ), + ) + ], + ), + ) + /*Row( children: [ Container( width: 28.0, @@ -192,7 +205,7 @@ class PrimaryImageButton extends StatelessWidget { ) ])) ], - ), + ),*/ )); } } From df64e7b5e14b3ad6921af59e56e0c940cf55f13c Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Fri, 24 Apr 2020 20:34:32 +0300 Subject: [PATCH 14/51] CWA-201 | applied new design to primary button and seed page; added base alert dialog and reconnect alert dialog --- assets/images/2.0x/crypto_lock.png | Bin 0 -> 187826 bytes assets/images/3.0x/crypto_lock.png | Bin 0 -> 385472 bytes assets/images/crypto_lock.png | Bin 0 -> 58192 bytes lib/palette.dart | 1 - .../screens/address_book/contact_page.dart | 8 +- lib/src/screens/base_page.dart | 29 ++- lib/src/screens/dashboard/wallet_menu.dart | 17 +- .../widgets/reconnect_alert_dialog.dart | 34 +++ .../screens/disclaimer/disclaimer_page.dart | 4 +- .../exchange_trade/exchange_confirm_page.dart | 12 +- lib/src/screens/nodes/new_node_page.dart | 10 +- lib/src/screens/seed/seed_page.dart | 244 +++++++++--------- .../seed_language/seed_language_page.dart | 4 +- .../screens/wallet_list/wallet_list_page.dart | 6 +- lib/src/screens/welcome/welcome_page.dart | 8 +- lib/src/widgets/base_alert_dialog.dart | 169 ++++++++++++ lib/src/widgets/nav_bar.dart | 10 +- lib/src/widgets/primary_button.dart | 15 +- lib/src/widgets/seed_widget.dart | 9 +- 19 files changed, 403 insertions(+), 177 deletions(-) create mode 100644 assets/images/2.0x/crypto_lock.png create mode 100644 assets/images/3.0x/crypto_lock.png create mode 100644 assets/images/crypto_lock.png create mode 100644 lib/src/screens/dashboard/widgets/reconnect_alert_dialog.dart create mode 100644 lib/src/widgets/base_alert_dialog.dart diff --git a/assets/images/2.0x/crypto_lock.png b/assets/images/2.0x/crypto_lock.png new file mode 100644 index 0000000000000000000000000000000000000000..c93941b77513d13532c3687d0ab1f42fc85c1ad5 GIT binary patch literal 187826 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