mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-22 15:19:02 +00:00
Cw 372 improve monero haven account selection picker (#939)
* refactor: Improve Monero/Haven account selection picker * feat: If the amount would be wrapped, instead display it under the account name * fix: balance str * refactor: add theme changes * refactor: remove duplicate observer
This commit is contained in:
parent
c01321008b
commit
cb0ca169fb
3 changed files with 182 additions and 172 deletions
|
@ -1,176 +1,94 @@
|
||||||
|
import 'package:cake_wallet/src/widgets/picker_inner_wrapper_widget.dart';
|
||||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||||
import 'package:cake_wallet/src/screens/monero_accounts/widgets/account_tile.dart';
|
import 'package:cake_wallet/src/screens/monero_accounts/widgets/account_tile.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
|
||||||
|
|
||||||
class MoneroAccountListPage extends StatelessWidget {
|
class MoneroAccountListPage extends StatelessWidget {
|
||||||
MoneroAccountListPage({required this.accountListViewModel})
|
MoneroAccountListPage({required this.accountListViewModel});
|
||||||
: backgroundHeight = 194,
|
|
||||||
thumbHeight = 72,
|
|
||||||
isAlwaysShowScrollThumb = false,
|
|
||||||
controller = ScrollController() {
|
|
||||||
controller.addListener(() {
|
|
||||||
final scrollOffsetFromTop = controller.hasClients
|
|
||||||
? (controller.offset / controller.position.maxScrollExtent * (backgroundHeight - thumbHeight))
|
|
||||||
: 0.0;
|
|
||||||
accountListViewModel.setScrollOffsetFromTop(scrollOffsetFromTop);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final MoneroAccountListViewModel accountListViewModel;
|
final MoneroAccountListViewModel accountListViewModel;
|
||||||
|
final ScrollController controller = ScrollController();
|
||||||
ScrollController controller;
|
|
||||||
double backgroundHeight;
|
|
||||||
double thumbHeight;
|
|
||||||
bool isAlwaysShowScrollThumb;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertBackground(
|
double itemHeight = 80;
|
||||||
child: Column(
|
double buttonHeight = 62;
|
||||||
|
|
||||||
|
return Observer(builder: (_) {
|
||||||
|
final accounts = accountListViewModel.accounts;
|
||||||
|
|
||||||
|
return PickerInnerWrapperWidget(
|
||||||
|
title: S.of(context).choose_account,
|
||||||
|
itemsHeight: (itemHeight * accounts.length) + buttonHeight,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Stack(
|
child: Scrollbar(
|
||||||
alignment: Alignment.center,
|
controller: controller,
|
||||||
children: <Widget>[
|
child: ListView.separated(
|
||||||
Column(
|
padding: EdgeInsets.zero,
|
||||||
|
controller: controller,
|
||||||
|
separatorBuilder: (context, index) => const SectionDivider(),
|
||||||
|
itemCount: accounts.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final account = accounts[index];
|
||||||
|
|
||||||
|
return AccountTile(
|
||||||
|
isCurrent: account.isSelected,
|
||||||
|
accountName: account.label,
|
||||||
|
accountBalance: account.balance ?? '0.00',
|
||||||
|
currency: accountListViewModel.currency.toString(),
|
||||||
|
onTap: () {
|
||||||
|
if (account.isSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
accountListViewModel.select(account);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
onEdit: () async => await Navigator.of(context)
|
||||||
|
.pushNamed(Routes.accountCreation, arguments: account));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () async =>
|
||||||
|
await Navigator.of(context).pushNamed(Routes.accountCreation),
|
||||||
|
child: Container(
|
||||||
|
height: buttonHeight,
|
||||||
|
color: Theme.of(context).cardColor,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Center(
|
||||||
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Icon(
|
||||||
padding: EdgeInsets.only(left: 24, right: 24),
|
Icons.add,
|
||||||
child: Text(
|
color: Colors.white,
|
||||||
S.of(context).choose_account,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontFamily: 'Lato',
|
|
||||||
decoration: TextDecoration.none,
|
|
||||||
color: Colors.white
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
padding: EdgeInsets.only(left: 5),
|
||||||
child: GestureDetector(
|
child: Text(
|
||||||
onTap: () => null,
|
S.of(context).create_new_account,
|
||||||
child: ClipRRect(
|
style: TextStyle(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
fontSize: 15,
|
||||||
child: Container(
|
fontWeight: FontWeight.w600,
|
||||||
height: 296,
|
fontFamily: 'Lato',
|
||||||
color: Theme.of(context).textTheme!.displayLarge!.decorationColor!,
|
color: Colors.white,
|
||||||
child: Column(
|
decoration: TextDecoration.none,
|
||||||
children: <Widget>[
|
|
||||||
Expanded(
|
|
||||||
child: Observer(
|
|
||||||
builder: (_) {
|
|
||||||
final accounts = accountListViewModel.accounts;
|
|
||||||
isAlwaysShowScrollThumb = accounts == null
|
|
||||||
? false
|
|
||||||
: accounts.length > 3;
|
|
||||||
|
|
||||||
return Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
ListView.separated(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
controller: controller,
|
|
||||||
separatorBuilder: (context, index) =>
|
|
||||||
const SectionDivider(),
|
|
||||||
itemCount: accounts.length ?? 0,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final account = accounts[index];
|
|
||||||
|
|
||||||
return AccountTile(
|
|
||||||
isCurrent: account.isSelected,
|
|
||||||
accountName: account.label,
|
|
||||||
accountBalance: account.balance ?? '0.00',
|
|
||||||
currency: accountListViewModel
|
|
||||||
.currency.toString(),
|
|
||||||
onTap: () {
|
|
||||||
if (account.isSelected) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
accountListViewModel
|
|
||||||
.select(account);
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
onEdit: () async =>
|
|
||||||
await Navigator.of(context)
|
|
||||||
.pushNamed(
|
|
||||||
Routes.accountCreation,
|
|
||||||
arguments: account));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
isAlwaysShowScrollThumb
|
|
||||||
? CakeScrollbar(
|
|
||||||
backgroundHeight: backgroundHeight,
|
|
||||||
thumbHeight: thumbHeight,
|
|
||||||
fromTop: accountListViewModel
|
|
||||||
.scrollOffsetFromTop
|
|
||||||
)
|
|
||||||
: Offstage(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () async => await Navigator.of(context)
|
|
||||||
.pushNamed(Routes.accountCreation),
|
|
||||||
child: Container(
|
|
||||||
height: 62,
|
|
||||||
color: Theme.of(context).cardColor,
|
|
||||||
padding: EdgeInsets.only(left: 24, right: 24),
|
|
||||||
child: Center(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(
|
|
||||||
Icons.add,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(left: 5),
|
|
||||||
child: Text(
|
|
||||||
S.of(context).create_new_account,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontFamily: 'Lato',
|
|
||||||
color: Colors.white,
|
|
||||||
decoration: TextDecoration.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
|
),
|
||||||
AlertCloseButton()
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
),
|
);
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AccountTile extends StatelessWidget {
|
class AccountTile extends StatelessWidget {
|
||||||
AccountTile({
|
AccountTile(
|
||||||
required this.isCurrent,
|
{required this.isCurrent,
|
||||||
required this.accountName,
|
required this.accountName,
|
||||||
this.accountBalance,
|
this.accountBalance,
|
||||||
required this.currency,
|
required this.currency,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
required this.onEdit
|
required this.onEdit});
|
||||||
});
|
|
||||||
|
|
||||||
final bool isCurrent;
|
final bool isCurrent;
|
||||||
final String accountName;
|
final String accountName;
|
||||||
|
@ -32,11 +31,13 @@ class AccountTile extends StatelessWidget {
|
||||||
height: 77,
|
height: 77,
|
||||||
padding: EdgeInsets.only(left: 24, right: 24),
|
padding: EdgeInsets.only(left: 24, right: 24),
|
||||||
color: color,
|
color: color,
|
||||||
child: Row(
|
child: Wrap(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
direction: Axis.horizontal,
|
||||||
|
alignment: WrapAlignment.spaceBetween,
|
||||||
|
runAlignment: WrapAlignment.center,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Container(
|
||||||
flex: 2,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
accountName,
|
accountName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -49,19 +50,19 @@ class AccountTile extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (accountBalance != null)
|
if (accountBalance != null)
|
||||||
Expanded(
|
Container(
|
||||||
child: Text(
|
child: Text(
|
||||||
'${accountBalance.toString()} $currency',
|
'${accountBalance.toString()} $currency',
|
||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontFamily: 'Lato',
|
fontFamily: 'Lato',
|
||||||
color: Theme.of(context).textTheme!.headlineMedium!.color!,
|
color: Theme.of(context).textTheme!.headlineMedium!.color!,
|
||||||
decoration: TextDecoration.none,
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
91
lib/src/widgets/picker_inner_wrapper_widget.dart
Normal file
91
lib/src/widgets/picker_inner_wrapper_widget.dart
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
|
||||||
|
|
||||||
|
class PickerInnerWrapperWidget extends StatelessWidget {
|
||||||
|
PickerInnerWrapperWidget(
|
||||||
|
{required this.children, this.title, this.itemsHeight});
|
||||||
|
|
||||||
|
final List<Widget> children;
|
||||||
|
final String? title;
|
||||||
|
final double? itemsHeight;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final mq = MediaQuery.of(context);
|
||||||
|
final bottom = mq.viewInsets.bottom;
|
||||||
|
final height = mq.size.height - bottom;
|
||||||
|
|
||||||
|
double containerHeight = height * 0.65;
|
||||||
|
if (bottom > 0) {
|
||||||
|
// increase a bit or it gets too squished in the top
|
||||||
|
containerHeight = height * 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title != null) {
|
||||||
|
return PickerWrapperWidget(
|
||||||
|
hasTitle: true,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Text(
|
||||||
|
title!,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).textTheme.displayLarge!.decorationColor!,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxHeight:
|
||||||
|
itemsHeight != null && itemsHeight! <= containerHeight
|
||||||
|
? itemsHeight!
|
||||||
|
: containerHeight,
|
||||||
|
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PickerWrapperWidget(
|
||||||
|
hasTitle: false,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).textTheme.displayLarge!.decorationColor!,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxHeight: containerHeight,
|
||||||
|
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue