Rework settings pickers (#398)

Updated pickers and settings screen

Omar Hatem committed Jun 29, 2022 at 14:38 UTC dc623f3293fba818c937f79af5b8d63bcb58b689
78 files changed +601 -358
assets/images/flags/aus.png
Binary files /dev/null and b/assets/images/flags/aus.png differ
assets/images/flags/bgr.png
Binary files /dev/null and b/assets/images/flags/bgr.png differ
assets/images/flags/bra.png
Binary files /dev/null and b/assets/images/flags/bra.png differ
assets/images/flags/cad.png
Binary files /dev/null and b/assets/images/flags/cad.png differ
assets/images/flags/che.png
Binary files /dev/null and b/assets/images/flags/che.png differ
assets/images/flags/chn.png
Binary files /dev/null and b/assets/images/flags/chn.png differ
assets/images/flags/czk.png
Binary files /dev/null and b/assets/images/flags/czk.png differ
assets/images/flags/deu.png
Binary files /dev/null and b/assets/images/flags/deu.png differ
assets/images/flags/dnk.png
Binary files /dev/null and b/assets/images/flags/dnk.png differ
assets/images/flags/esp.png
Binary files /dev/null and b/assets/images/flags/esp.png differ
assets/images/flags/eur.png
Binary files /dev/null and b/assets/images/flags/eur.png differ
assets/images/flags/fra.png
Binary files /dev/null and b/assets/images/flags/fra.png differ
assets/images/flags/gbr.png
Binary files /dev/null and b/assets/images/flags/gbr.png differ
assets/images/flags/hkg.png
Binary files /dev/null and b/assets/images/flags/hkg.png differ
assets/images/flags/hrv.png
Binary files /dev/null and b/assets/images/flags/hrv.png differ
assets/images/flags/hun.png
Binary files /dev/null and b/assets/images/flags/hun.png differ
assets/images/flags/idn.png
Binary files /dev/null and b/assets/images/flags/idn.png differ
assets/images/flags/ind.png
Binary files /dev/null and b/assets/images/flags/ind.png differ
assets/images/flags/isl.png
Binary files /dev/null and b/assets/images/flags/isl.png differ
assets/images/flags/isr.png
Binary files /dev/null and b/assets/images/flags/isr.png differ
assets/images/flags/ita.png
Binary files /dev/null and b/assets/images/flags/ita.png differ
assets/images/flags/jpn.png
Binary files /dev/null and b/assets/images/flags/jpn.png differ
assets/images/flags/kor.png
Binary files /dev/null and b/assets/images/flags/kor.png differ
assets/images/flags/mex.png
Binary files /dev/null and b/assets/images/flags/mex.png differ
assets/images/flags/mys.png
Binary files /dev/null and b/assets/images/flags/mys.png differ
assets/images/flags/nld.png
Binary files /dev/null and b/assets/images/flags/nld.png differ
assets/images/flags/nor.png
Binary files /dev/null and b/assets/images/flags/nor.png differ
assets/images/flags/nzl.png
Binary files /dev/null and b/assets/images/flags/nzl.png differ
assets/images/flags/phl.png
Binary files /dev/null and b/assets/images/flags/phl.png differ
assets/images/flags/pol.png
Binary files /dev/null and b/assets/images/flags/pol.png differ
assets/images/flags/prt.png
Binary files /dev/null and b/assets/images/flags/prt.png differ
assets/images/flags/rou.png
Binary files /dev/null and b/assets/images/flags/rou.png differ
assets/images/flags/rus.png
Binary files /dev/null and b/assets/images/flags/rus.png differ
assets/images/flags/saf.png
Binary files /dev/null and b/assets/images/flags/saf.png differ
assets/images/flags/sgp.png
Binary files /dev/null and b/assets/images/flags/sgp.png differ
assets/images/flags/swe.png
Binary files /dev/null and b/assets/images/flags/swe.png differ
assets/images/flags/tha.png
Binary files /dev/null and b/assets/images/flags/tha.png differ
assets/images/flags/ukr.png
Binary files /dev/null and b/assets/images/flags/ukr.png differ
assets/images/flags/usa.png
Binary files /dev/null and b/assets/images/flags/usa.png differ
assets/images/flags/ven.png
Binary files /dev/null and b/assets/images/flags/ven.png differ
assets/images/search_icon.png
Binary files /dev/null and b/assets/images/search_icon.png differ
lib/di.dart
-3
@@ -38,7 +38,6 @@ import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
38 import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
39 import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
40 import 'package:cake_wallet/src/screens/send/send_template_page.dart';
41 -import 'package:cake_wallet/src/screens/settings/change_language.dart';
41 import 'package:cake_wallet/src/screens/settings/settings.dart';
42 import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
43 import 'package:cake_wallet/src/screens/support/support_page.dart';
@@ -507,8 +506,6 @@ Future setup(
506
507 getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
508
510 - getIt.registerFactory(() => LanguageListPage(getIt.get<SettingsStore>()));
511 -
509 getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>(
510 (type, _) => WalletRestoreViewModel(getIt.get<AppStore>(),
511 getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
lib/entities/fiat_currency.dart
+37 -34
@@ -1,43 +1,46 @@
1 import 'package:cw_core/enumerable_item.dart';
2
3 class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
4 - const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol);
4 + const FiatCurrency({String symbol, this.countryCode, this.fullName}) : super(title: symbol, raw: symbol);
5 +
6 + final String countryCode;
7 + final String fullName;
8
9 static List<FiatCurrency> get all => _all.values.toList();
10
8 - static const aud = FiatCurrency(symbol: 'AUD');
9 - static const bgn = FiatCurrency(symbol: 'BGN');
10 - static const brl = FiatCurrency(symbol: 'BRL');
11 - static const cad = FiatCurrency(symbol: 'CAD');
12 - static const chf = FiatCurrency(symbol: 'CHF');
13 - static const cny = FiatCurrency(symbol: 'CNY');
14 - static const czk = FiatCurrency(symbol: 'CZK');
15 - static const eur = FiatCurrency(symbol: 'EUR');
16 - static const dkk = FiatCurrency(symbol: 'DKK');
17 - static const gbp = FiatCurrency(symbol: 'GBP');
18 - static const hkd = FiatCurrency(symbol: 'HKD');
19 - static const hrk = FiatCurrency(symbol: 'HRK');
20 - static const huf = FiatCurrency(symbol: 'HUF');
21 - static const idr = FiatCurrency(symbol: 'IDR');
22 - static const ils = FiatCurrency(symbol: 'ILS');
23 - static const inr = FiatCurrency(symbol: 'INR');
24 - static const isk = FiatCurrency(symbol: 'ISK');
25 - static const jpy = FiatCurrency(symbol: 'JPY');
26 - static const krw = FiatCurrency(symbol: 'KRW');
27 - static const mxn = FiatCurrency(symbol: 'MXN');
28 - static const myr = FiatCurrency(symbol: 'MYR');
29 - static const nok = FiatCurrency(symbol: 'NOK');
30 - static const nzd = FiatCurrency(symbol: 'NZD');
31 - static const php = FiatCurrency(symbol: 'PHP');
32 - static const pln = FiatCurrency(symbol: 'PLN');
33 - static const ron = FiatCurrency(symbol: 'RON');
34 - static const rub = FiatCurrency(symbol: 'RUB');
35 - static const sek = FiatCurrency(symbol: 'SEK');
36 - static const sgd = FiatCurrency(symbol: 'SGD');
37 - static const thb = FiatCurrency(symbol: 'THB');
38 - static const usd = FiatCurrency(symbol: 'USD');
39 - static const zar = FiatCurrency(symbol: 'ZAR');
40 - static const vef = FiatCurrency(symbol: 'VEF');
11 + static const aud = FiatCurrency(symbol: 'AUD', countryCode: "aus", fullName: "Australian Dollar");
12 + static const bgn = FiatCurrency(symbol: 'BGN', countryCode: "bgr", fullName: "Bulgarian Lev");
13 + static const brl = FiatCurrency(symbol: 'BRL', countryCode: "bra", fullName: "Brazilian Real");
14 + static const cad = FiatCurrency(symbol: 'CAD', countryCode: "cad", fullName: "Canadian Dollar");
15 + static const chf = FiatCurrency(symbol: 'CHF', countryCode: "che", fullName: "Swiss Franc");
16 + static const cny = FiatCurrency(symbol: 'CNY', countryCode: "chn", fullName: "Chinese Yuan");
17 + static const czk = FiatCurrency(symbol: 'CZK', countryCode: "czk", fullName: "Czech Koruna");
18 + static const eur = FiatCurrency(symbol: 'EUR', countryCode: "eur", fullName: "Euro");
19 + static const dkk = FiatCurrency(symbol: 'DKK', countryCode: "dnk", fullName: "Danish Krone");
20 + static const gbp = FiatCurrency(symbol: 'GBP', countryCode: "gbr", fullName: "Pound sterling");
21 + static const hkd = FiatCurrency(symbol: 'HKD', countryCode: "hkg", fullName: "Hong Kong Dollar");
22 + static const hrk = FiatCurrency(symbol: 'HRK', countryCode: "hrv", fullName: "Croatian Kuna");
23 + static const huf = FiatCurrency(symbol: 'HUF', countryCode: "hun", fullName: "Hungarian Forint");
24 + static const idr = FiatCurrency(symbol: 'IDR', countryCode: "idn", fullName: "Indonesian Rupiah");
25 + static const ils = FiatCurrency(symbol: 'ILS', countryCode: "isr", fullName: "Israeli New Shekel");
26 + static const inr = FiatCurrency(symbol: 'INR', countryCode: "ind", fullName: "Indian Rupee");
27 + static const isk = FiatCurrency(symbol: 'ISK', countryCode: "isl", fullName: "Icelandic Króna");
28 + static const jpy = FiatCurrency(symbol: 'JPY', countryCode: "jpn", fullName: "Japanese Yen equals");
29 + static const krw = FiatCurrency(symbol: 'KRW', countryCode: "kor", fullName: "South Korean won");
30 + static const mxn = FiatCurrency(symbol: 'MXN', countryCode: "mex", fullName: "Mexican Peso");
31 + static const myr = FiatCurrency(symbol: 'MYR', countryCode: "mys", fullName: "Malaysian Ringgit");
32 + static const nok = FiatCurrency(symbol: 'NOK', countryCode: "nor", fullName: "Norwegian Krone");
33 + static const nzd = FiatCurrency(symbol: 'NZD', countryCode: "nzl", fullName: "New Zealand Dollar");
34 + static const php = FiatCurrency(symbol: 'PHP', countryCode: "phl", fullName: "Philippine peso");
35 + static const pln = FiatCurrency(symbol: 'PLN', countryCode: "pol", fullName: "Poland złoty");
36 + static const ron = FiatCurrency(symbol: 'RON', countryCode: "rou", fullName: "Romanian Leu");
37 + static const rub = FiatCurrency(symbol: 'RUB', countryCode: "rus", fullName: "Russian Ruble");
38 + static const sek = FiatCurrency(symbol: 'SEK', countryCode: "swe", fullName: "Swedish Krona");
39 + static const sgd = FiatCurrency(symbol: 'SGD', countryCode: "sgp", fullName: "Singapore Dollar");
40 + static const thb = FiatCurrency(symbol: 'THB', countryCode: "tha", fullName: "Thai Baht");
41 + static const usd = FiatCurrency(symbol: 'USD', countryCode: "usa", fullName: "United States Dollar");
42 + static const zar = FiatCurrency(symbol: 'ZAR', countryCode: "saf", fullName: "South African Rand");
43 + static const vef = FiatCurrency(symbol: 'VEF', countryCode: "ven", fullName: "Venezuelan Bolívar");
44
45 static final _all = {
46 FiatCurrency.aud.raw: FiatCurrency.aud,
lib/entities/language_service.dart
+19
@@ -20,6 +20,25 @@ class LanguageService {
20 'hr': 'Hrvatski (Croatian)',
21 'it': 'Italiano (Italian)'
22 };
23 +
24 + static const Map<String, String> localeCountryCode = {
25 + 'en': 'usa',
26 + 'de': 'deu',
27 + 'es': 'esp',
28 + 'fr': 'fra',
29 + 'hi': 'ind',
30 + 'ja': 'jpn',
31 + 'ko': 'kor',
32 + 'nl': 'nld',
33 + 'pl': 'pol',
34 + 'pt': 'prt',
35 + 'ru': 'rus',
36 + 'uk': 'ukr',
37 + 'zh': 'chn',
38 + 'hr': 'hrv',
39 + 'it': 'ita'
40 + };
41 +
42 static final list = <String, String> {};
43
44 static void loadLocaleList() {
lib/router.dart
-5
@@ -47,7 +47,6 @@ import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_c
47 import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
48 import 'package:cake_wallet/src/screens/contact/contact_page.dart';
49 import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
50 -import 'package:cake_wallet/src/screens/settings/change_language.dart';
50 import 'package:cake_wallet/src/screens/restore/restore_wallet_from_seed_details.dart';
51 import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
52 import 'package:cake_wallet/src/screens/settings/settings.dart';
@@ -359,10 +358,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
358 case Routes.faq:
359 return MaterialPageRoute<void>(builder: (_) => getIt.get<FaqPage>());
360
362 - case Routes.changeLanguage:
363 - return MaterialPageRoute<void>(
364 - builder: (_) => getIt.get<LanguageListPage>());
365 -
361 case Routes.preSeed:
362 return MaterialPageRoute<void>(
363 builder: (_) =>
lib/routes.dart
-1
@@ -41,7 +41,6 @@ class Routes {
41 static const unlock = '/auth_not_closable';
42 static const rescan = '/rescan';
43 static const faq = '/faq';
44 - static const changeLanguage = '/change_language';
44 static const newWalletType = '/new_wallet_type';
45 static const sendTemplate = '/send_template';
46 static const exchangeTemplate = '/exchange_template';
lib/src/screens/settings/change_language.dart deleted
-63
@@ -1,63 +0,0 @@
1 -import 'package:cake_wallet/src/screens/settings/widgets/language_row.dart';
2 -import 'package:cake_wallet/src/widgets/standard_list.dart';
3 -import 'package:cake_wallet/store/settings_store.dart';
4 -import 'package:cake_wallet/utils/show_pop_up.dart';
5 -import 'package:flutter/material.dart';
6 -import 'package:flutter/cupertino.dart';
7 -import 'package:flutter_mobx/flutter_mobx.dart';
8 -import 'package:cake_wallet/generated/i18n.dart';
9 -import 'package:cake_wallet/entities/language_service.dart';
10 -import 'package:cake_wallet/src/screens/base_page.dart';
11 -import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
12 -
13 -class LanguageListPage extends BasePage {
14 - LanguageListPage(this.settingsStore);
15 -
16 - final SettingsStore settingsStore;
17 -
18 - @override
19 - String get title => S.current.settings_change_language;
20 -
21 - @override
22 - Widget body(BuildContext context) {
23 - return Container(
24 - padding: EdgeInsets.only(top: 10.0),
25 - child: SectionStandardList(
26 - sectionCount: 1,
27 - context: context,
28 - itemCounter: (int sectionIndex) => LanguageService.list.values.length,
29 - itemBuilder: (_, sectionIndex, index) {
30 - return Observer(builder: (BuildContext context) {
31 - final item = LanguageService.list.values.elementAt(index);
32 - final code = LanguageService.list.keys.elementAt(index);
33 - final isCurrent = code == settingsStore.languageCode ?? false;
34 -
35 - return LanguageRow(
36 - title: item,
37 - isSelected: isCurrent,
38 - handler: (context) async {
39 - if (!isCurrent) {
40 - await showPopUp<void>(
41 - context: context,
42 - builder: (BuildContext context) {
43 - return AlertWithTwoActions(
44 - alertTitle: S.of(context).change_language,
45 - alertContent:
46 - S.of(context).change_language_to(item),
47 - rightButtonText: S.of(context).change,
48 - leftButtonText: S.of(context).cancel,
49 - actionRightButton: () {
50 - settingsStore.languageCode = code;
51 - Navigator.of(context).pop();
52 - },
53 - actionLeftButton: () =>
54 - Navigator.of(context).pop());
55 - });
56 - }
57 - },
58 - );
59 - });
60 - },
61 - ));
62 - }
63 -}
lib/src/screens/settings/settings.dart
+10
@@ -1,4 +1,6 @@
1 +import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
2 import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
3 +import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
4 import 'package:cake_wallet/view_model/settings/version_list_item.dart';
5 import 'package:flutter/material.dart';
6 import 'package:flutter/cupertino.dart';
@@ -46,6 +48,10 @@ class SettingsPage extends BasePage {
48 selectedItem: item.selectedItem(),
49 items: item.items,
50 onItemSelected: (dynamic value) => item.onItemSelected(value),
51 + images: item.images,
52 + searchHintText: item.searchHintText,
53 + isGridView: item.isGridView,
54 + matchingCriteria: (dynamic value, String searchText) => item.matchingCriteria(value, searchText),
55 );
56 });
57 }
@@ -80,6 +86,10 @@ class SettingsPage extends BasePage {
86 });
87 }
88
89 + if (item is ChoicesListItem) {
90 + return SettingsChoicesCell(item);
91 + }
92 +
93 return Container();
94 });
95 }
lib/src/screens/settings/widgets/language_row.dart deleted
-30
@@ -1,30 +0,0 @@
1 -import 'package:cake_wallet/palette.dart';
2 -import 'package:flutter/material.dart';
3 -import 'package:cake_wallet/src/widgets/standard_list.dart';
4 -
5 -class LanguageRow extends StandardListRow {
6 - LanguageRow({@required String title, @required this.isSelected, @required Function(BuildContext context) handler}) :
7 - super(title: title, isSelected: isSelected, onTap: handler);
8 -
9 - @override
10 - final bool isSelected;
11 -
12 - @override
13 - Widget buildCenter(BuildContext context, {@required bool hasLeftOffset}) {
14 - return Expanded(
15 - child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
16 - if (hasLeftOffset) SizedBox(width: 10),
17 - Text(title,
18 - style: TextStyle(
19 - fontSize: 14,
20 - fontWeight: FontWeight.w500,
21 - color: titleColor(context)))
22 - ]));
23 - }
24 -
25 - @override
26 - Widget buildTrailing(BuildContext context) =>
27 - isSelected
28 - ? Icon(Icons.done, color: Palette.blueCraiola)
29 - : Offstage();
30 -}
\ No newline at end of file
lib/src/screens/settings/widgets/settings_choices_cell.dart new
+71
@@ -0,0 +1,71 @@
1 +import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
2 +import 'package:flutter/material.dart';
3 +
4 +class SettingsChoicesCell extends StatelessWidget {
5 + const SettingsChoicesCell(this.choicesListItem, {Key key}) : super(key: key);
6 +
7 + final ChoicesListItem choicesListItem;
8 +
9 + @override
10 + Widget build(BuildContext context) {
11 + return Container(
12 + color: Theme.of(context).backgroundColor,
13 + padding: EdgeInsets.all(24),
14 + child: Column(
15 + mainAxisSize: MainAxisSize.min,
16 + crossAxisAlignment: CrossAxisAlignment.start,
17 + children: [
18 + Row(
19 + children: [
20 + Text(
21 + choicesListItem.title,
22 + style: TextStyle(
23 + fontSize: 14,
24 + fontWeight: FontWeight.normal,
25 + color: Theme.of(context).primaryTextTheme.title.color,
26 + ),
27 + ),
28 + ],
29 + ),
30 + const SizedBox(height: 24),
31 + Center(
32 + child: SingleChildScrollView(
33 + scrollDirection: Axis.horizontal,
34 + child: Container(
35 + decoration: BoxDecoration(
36 + borderRadius: BorderRadius.circular(30),
37 + color: Theme.of(context).accentTextTheme.display2.color,
38 + ),
39 + child: Row(
40 + mainAxisAlignment: MainAxisAlignment.center,
41 + children: choicesListItem.items.map((dynamic e) {
42 + final isSelected = choicesListItem.selectedItem == e;
43 + return GestureDetector(
44 + onTap: () {
45 + choicesListItem.onItemSelected?.call(e);
46 + },
47 + child: Container(
48 + padding: EdgeInsets.symmetric(horizontal: 32, vertical: 8),
49 + decoration: BoxDecoration(
50 + borderRadius: BorderRadius.circular(30),
51 + color: isSelected ? Theme.of(context).accentTextTheme.body2.color : null,
52 + ),
53 + child: Text(
54 + choicesListItem.displayItem?.call(e) ?? e.toString(),
55 + style: TextStyle(
56 + color: isSelected ? Colors.white : Theme.of(context).primaryTextTheme.caption.color,
57 + fontWeight: isSelected ? FontWeight.w700 : FontWeight.normal,
58 + ),
59 + ),
60 + ),
61 + );
62 + }).toList(),
63 + ),
64 + ),
65 + ),
66 + ),
67 + ],
68 + ),
69 + );
70 + }
71 +}
lib/src/screens/settings/widgets/settings_picker_cell.dart
+30 -19
@@ -2,7 +2,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
2 import 'package:flutter/material.dart';
3 import 'package:cake_wallet/src/widgets/picker.dart';
4 import 'package:cake_wallet/src/widgets/standard_list.dart';
5 -import 'package:cake_wallet/generated/i18n.dart';
5
6 class SettingsPickerCell<ItemType> extends StandardListRow {
7 SettingsPickerCell(
@@ -10,29 +9,43 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
9 @required this.displayItem,
10 this.selectedItem,
11 this.items,
12 + this.images,
13 + this.searchHintText,
14 + this.isGridView = false,
15 + this.matchingCriteria,
16 this.onItemSelected})
17 : super(
15 - title: title,
16 - isSelected: false,
17 - onTap: (BuildContext context) async {
18 - final selectedAtIndex = items.indexOf(selectedItem);
18 + title: title,
19 + isSelected: false,
20 + onTap: (BuildContext context) async {
21 + final selectedAtIndex = items.indexOf(selectedItem);
22
20 - await showPopUp<void>(
21 - context: context,
22 - builder: (_) => Picker(
23 - items: items,
24 - displayItem: displayItem,
25 - selectedAtIndex: selectedAtIndex,
26 - title: S.current.please_select,
27 - mainAxisAlignment: MainAxisAlignment.center,
28 - onItemSelected: (ItemType item) =>
29 - onItemSelected?.call(item)));
30 - });
23 + await showPopUp<void>(
24 + context: context,
25 + builder: (_) => Picker(
26 + items: items,
27 + displayItem: displayItem,
28 + selectedAtIndex: selectedAtIndex,
29 + mainAxisAlignment: MainAxisAlignment.start,
30 + onItemSelected: (ItemType item) => onItemSelected?.call(item),
31 + images: images,
32 + isSeparated: false,
33 + hintText: searchHintText,
34 + isGridView: isGridView,
35 + matchingCriteria: matchingCriteria,
36 + ),
37 + );
38 + },
39 + );
40
41 final ItemType selectedItem;
42 final List<ItemType> items;
43 final void Function(ItemType item) onItemSelected;
44 final String Function(ItemType item) displayItem;
45 + final List<Image> images;
46 + final String searchHintText;
47 + final bool isGridView;
48 + final bool Function(ItemType, String) matchingCriteria;
49
50 @override
51 Widget buildTrailing(BuildContext context) {
@@ -40,9 +53,7 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
53 displayItem?.call(selectedItem) ?? selectedItem.toString(),
54 textAlign: TextAlign.right,
55 style: TextStyle(
43 - fontSize: 14.0,
44 - fontWeight: FontWeight.w500,
45 - color: Theme.of(context).primaryTextTheme.overline.color),
56 + fontSize: 14.0, fontWeight: FontWeight.w500, color: Theme.of(context).primaryTextTheme.overline.color),
57 );
58 }
59 }
lib/src/widgets/alert_background.dart
+13 -9
@@ -10,15 +10,19 @@ class AlertBackground extends StatelessWidget {
10
11 @override
12 Widget build(BuildContext context) {
13 - return Container(
14 - height: double.infinity,
15 - width: double.infinity,
16 - color: Colors.transparent,
17 - child: BackdropFilter(
18 - filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
19 - child: Container(
20 - decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
21 - child: child,
13 + return Scaffold(
14 + resizeToAvoidBottomInset: false,
15 + backgroundColor: Colors.transparent,
16 + body: Container(
17 + height: double.infinity,
18 + width: double.infinity,
19 + color: Colors.transparent,
20 + child: BackdropFilter(
21 + filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
22 + child: Container(
23 + decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
24 + child: child,
25 + ),
26 ),
27 ),
28 );
lib/src/widgets/picker.dart
+245 -147
@@ -2,7 +2,6 @@ import 'dart:ui';
2 import 'package:flutter/cupertino.dart';
3 import 'package:flutter/material.dart';
4 import 'package:cake_wallet/src/widgets/alert_background.dart';
5 -import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
5 import 'package:cake_wallet/src/widgets/alert_close_button.dart';
6 import 'package:cake_wallet/palette.dart';
7
@@ -10,13 +9,19 @@ class Picker<Item extends Object> extends StatefulWidget {
9 Picker({
10 @required this.selectedAtIndex,
11 @required this.items,
13 - @required this.title,
12 @required this.onItemSelected,
13 + this.title,
14 this.displayItem,
15 this.images,
16 this.description,
17 this.mainAxisAlignment = MainAxisAlignment.start,
19 - });
18 + this.isGridView = false,
19 + this.isSeparated = true,
20 + this.hintText,
21 + this.matchingCriteria,
22 + }) : assert(hintText == null ||
23 + matchingCriteria !=
24 + null); // make sure that if the search field is enabled then there is a searching criteria provided
25
26 final int selectedAtIndex;
27 final List<Item> items;
@@ -26,6 +31,10 @@ class Picker<Item extends Object> extends StatefulWidget {
31 final Function(Item) onItemSelected;
32 final MainAxisAlignment mainAxisAlignment;
33 final String Function(Item) displayItem;
34 + final bool isGridView;
35 + final bool isSeparated;
36 + final String hintText;
37 + final bool Function(Item, String) matchingCriteria;
38
39 @override
40 PickerState createState() => PickerState<Item>(items, images, onItemSelected);
@@ -35,8 +44,10 @@ class PickerState<Item> extends State<Picker> {
44 PickerState(this.items, this.images, this.onItemSelected);
45
46 final Function(Item) onItemSelected;
38 - final List<Item> items;
39 - final List<Image> images;
47 + List<Item> items;
48 + List<Image> images;
49 +
50 + final TextEditingController searchController = TextEditingController();
51
52 final closeButton = Image.asset(
53 'assets/images/close.png',
@@ -44,161 +55,248 @@ class PickerState<Item> extends State<Picker> {
55 );
56 ScrollController controller = ScrollController();
57
47 - final double backgroundHeight = 193;
48 - final double thumbHeight = 72;
49 - double fromTop = 0;
50 -
58 @override
52 - Widget build(BuildContext context) {
53 - controller.addListener(() {
54 - fromTop = controller.hasClients
55 - ? (controller.offset /
56 - controller.position.maxScrollExtent *
57 - (backgroundHeight - thumbHeight))
58 - : 0;
59 + void initState() {
60 + super.initState();
61 +
62 + searchController.addListener(() {
63 + items = [];
64 + images = [];
65 + for (int i=0;i<widget.items.length;i++) {
66 + if (widget.matchingCriteria?.call(widget.items[i], searchController.text) ?? true) {
67 + items.add(widget.items[i] as Item);
68 + images.add(widget.images[i]);
69 + }
70 + }
71 setState(() {});
72 });
73 + }
74
62 - final isShowScrollThumb = items != null ? items.length > 3 : false;
63 -
75 + @override
76 + Widget build(BuildContext context) {
77 return AlertBackground(
65 - child: Stack(
66 - alignment: Alignment.center,
67 - children: <Widget>[
68 - Column(
69 - mainAxisSize: MainAxisSize.min,
70 - children: <Widget>[
71 - Container(
72 - padding: EdgeInsets.only(left: 24, right: 24),
73 - child: Text(
74 - widget.title,
75 - textAlign: TextAlign.center,
76 - style: TextStyle(
77 - fontSize: 18,
78 - fontFamily: 'Lato',
79 - fontWeight: FontWeight.bold,
80 - decoration: TextDecoration.none,
81 - color: Colors.white),
82 - ),
83 - ),
84 - Padding(
85 - padding: EdgeInsets.only(left: 24, right: 24, top: 24),
86 - child: GestureDetector(
87 - onTap: () => null,
88 - child: ClipRRect(
89 - borderRadius: BorderRadius.all(Radius.circular(14)),
90 - child: Container(
91 - height: 233,
78 + child: Stack(
79 + alignment: Alignment.center,
80 + children: <Widget>[
81 + Column(
82 + mainAxisSize: MainAxisSize.min,
83 + children: <Widget>[
84 + if (widget.title?.isNotEmpty ?? false)
85 + Container(
86 + padding: EdgeInsets.symmetric(horizontal: 24),
87 + child: Text(
88 + widget.title,
89 + textAlign: TextAlign.center,
90 + style: TextStyle(
91 + fontSize: 18,
92 + fontFamily: 'Lato',
93 + fontWeight: FontWeight.bold,
94 + decoration: TextDecoration.none,
95 + color: Colors.white,
96 + ),
97 + ),
98 + ),
99 + Padding(
100 + padding: EdgeInsets.only(left: 24, right: 24, top: 24),
101 + child: GestureDetector(
102 + onTap: () => null,
103 + child: ClipRRect(
104 + borderRadius: BorderRadius.all(Radius.circular(30)),
105 + child: Container(
106 color: Theme.of(context).accentTextTheme.title.color,
93 - child: Stack(
94 - alignment: Alignment.center,
95 - children: <Widget>[
96 - ListView.separated(
97 - padding: EdgeInsets.all(0),
98 - controller: controller,
99 - separatorBuilder: (context, index) => Divider(
100 - color: Theme.of(context)
101 - .accentTextTheme
102 - .title
103 - .backgroundColor,
107 + child: ConstrainedBox(
108 + constraints: BoxConstraints(
109 + maxHeight: MediaQuery.of(context).size.height * 0.65,
110 + ),
111 + child: Column(
112 + mainAxisSize: MainAxisSize.min,
113 + children: [
114 + if (widget.hintText != null)
115 + Padding(
116 + padding: const EdgeInsets.all(16),
117 + child: TextFormField(
118 + controller: searchController,
119 + style: TextStyle(color: Theme.of(context).primaryTextTheme.title.color),
120 + decoration: InputDecoration(
121 + hintText: widget.hintText,
122 + prefixIcon: Image.asset("assets/images/search_icon.png"),
123 + filled: true,
124 + fillColor: Theme.of(context).accentTextTheme.display2.color,
125 + alignLabelWithHint: false,
126 + contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
127 + enabledBorder: OutlineInputBorder(
128 + borderRadius: BorderRadius.circular(14),
129 + borderSide: const BorderSide(
130 + color: Colors.transparent,
131 + )),
132 + focusedBorder: OutlineInputBorder(
133 + borderRadius: BorderRadius.circular(14),
134 + borderSide: const BorderSide(
135 + color: Colors.transparent,
136 + )),
137 + ),
138 + ),
139 + ),
140 + Divider(
141 + color: Theme.of(context).accentTextTheme.title.backgroundColor,
142 height: 1,
143 ),
106 - itemCount: items == null ? 0 : items.length,
107 - itemBuilder: (context, index) {
108 - final item = items[index];
109 - final image =
110 - images != null ? images[index] : null;
111 - final isItemSelected =
112 - index == widget.selectedAtIndex;
113 -
114 - final color = isItemSelected
115 - ? Theme.of(context).textTheme.body2.color
116 - : Theme.of(context)
117 - .accentTextTheme
118 - .title
119 - .color;
120 - final textColor = isItemSelected
121 - ? Palette.blueCraiola
122 - : Theme.of(context)
123 - .primaryTextTheme
124 - .title
125 - .color;
126 -
127 - return GestureDetector(
128 - onTap: () {
129 - if (onItemSelected == null) {
130 - return;
131 - }
132 - Navigator.of(context).pop();
133 - onItemSelected(item);
134 - },
135 - child: Container(
136 - height: 77,
137 - padding: EdgeInsets.only(left: 24, right: 24),
138 - color: color,
139 - child: Row(
140 - mainAxisSize: MainAxisSize.max,
141 - mainAxisAlignment: widget.mainAxisAlignment,
142 - crossAxisAlignment:
143 - CrossAxisAlignment.center,
144 - children: <Widget>[
145 - image ?? Offstage(),
146 - Padding(
147 - padding: EdgeInsets.only(
148 - left: image != null ? 12 : 0),
149 - child: Text(
150 - widget.displayItem?.call(item) ??
151 - item.toString(),
152 - style: TextStyle(
153 - fontSize: 18,
154 - fontFamily: 'Lato',
155 - fontWeight: FontWeight.w600,
156 - color: textColor,
157 - decoration: TextDecoration.none,
144 + if (widget.selectedAtIndex != -1) buildSelectedItem(),
145 + Flexible(
146 + child: Stack(
147 + alignment: Alignment.center,
148 + children: <Widget>[
149 + (items?.length ?? 0) > 3 ? Scrollbar(
150 + controller: controller,
151 + child: itemsList(),
152 + ) : itemsList(),
153 + (widget.description?.isNotEmpty ?? false)
154 + ? Positioned(
155 + bottom: 24,
156 + left: 24,
157 + right: 24,
158 + child: Text(
159 + widget.description,
160 + textAlign: TextAlign.center,
161 + style: TextStyle(
162 + fontSize: 12,
163 + fontWeight: FontWeight.w500,
164 + fontFamily: 'Lato',
165 + decoration: TextDecoration.none,
166 + color: Theme.of(context).primaryTextTheme.title.color,
167 + ),
168 ),
159 - ),
160 - )
161 - ],
162 - ),
163 - ),
164 - );
165 - },
166 - ),
167 - ((widget.description != null) &&
168 - (widget.description.isNotEmpty))
169 - ? Positioned(
170 - bottom: 24,
171 - left: 24,
172 - right: 24,
173 - child: Text(
174 - widget.description,
175 - textAlign: TextAlign.center,
176 - style: TextStyle(
177 - fontSize: 12,
178 - fontWeight: FontWeight.w500,
179 - fontFamily: 'Lato',
180 - decoration: TextDecoration.none,
181 - color: Theme.of(context)
182 - .primaryTextTheme
183 - .title
184 - .color),
185 - ))
186 - : Offstage(),
187 - isShowScrollThumb
188 - ? CakeScrollbar(
189 - backgroundHeight: backgroundHeight,
190 - thumbHeight: thumbHeight,
191 - fromTop: fromTop)
192 - : Offstage(),
193 - ],
194 - )),
169 + )
170 + : Offstage(),
171 + ],
172 + ),
173 + ),
174 + ],
175 + ),
176 + ),
177 + ),
178 + ),
179 ),
180 + )
181 + ],
182 + ),
183 + AlertCloseButton(image: closeButton)
184 + ],
185 + ),
186 + );
187 + }
188 +
189 + Widget itemsList() {
190 + return Container(
191 + color: Theme.of(context).accentTextTheme.headline6.backgroundColor,
192 + child: widget.isGridView
193 + ? GridView.builder(
194 + padding: EdgeInsets.zero,
195 + controller: controller,
196 + itemCount: items == null || items.isEmpty ? 0 : items.length,
197 + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
198 + crossAxisCount: 2,
199 + crossAxisSpacing: 2,
200 + childAspectRatio: 3,
201 ),
202 + itemBuilder: (context, index) => buildItem(index),
203 )
204 + : ListView.separated(
205 + padding: EdgeInsets.zero,
206 + controller: controller,
207 + shrinkWrap: true,
208 + separatorBuilder: (context, index) => widget.isSeparated
209 + ? Divider(
210 + color: Theme.of(context).accentTextTheme.title.backgroundColor,
211 + height: 1,
212 + )
213 + : const SizedBox(),
214 + itemCount: items == null || items.isEmpty ? 0 : items.length,
215 + itemBuilder: (context, index) => buildItem(index),
216 + ),
217 + );
218 + }
219 +
220 + Widget buildItem(int index) {
221 + /// don't show selected item in the list view
222 + if (widget.items[widget.selectedAtIndex] == items[index] && !widget.isGridView) {
223 + return const SizedBox();
224 + }
225 +
226 + final item = items[index];
227 + final image = images != null ? images[index] : null;
228 +
229 + return GestureDetector(
230 + onTap: () {
231 + if (onItemSelected == null) {
232 + return;
233 + }
234 + Navigator.of(context).pop();
235 + onItemSelected(item);
236 + },
237 + child: Container(
238 + height: 55,
239 + color: Theme.of(context).accentTextTheme.headline6.color,
240 + padding: EdgeInsets.only(left: 24, right: 24),
241 + child: Row(
242 + mainAxisSize: MainAxisSize.max,
243 + mainAxisAlignment: widget.mainAxisAlignment,
244 + crossAxisAlignment: CrossAxisAlignment.center,
245 + children: <Widget>[
246 + image ?? Offstage(),
247 + Expanded(
248 + child: Padding(
249 + padding: EdgeInsets.only(left: image != null ? 12 : 0),
250 + child: Text(
251 + widget.displayItem?.call(item) ?? item.toString(),
252 + style: TextStyle(
253 + fontSize: 14,
254 + fontFamily: 'Lato',
255 + fontWeight: FontWeight.w600,
256 + color: Theme.of(context).primaryTextTheme.title.color,
257 + decoration: TextDecoration.none,
258 + ),
259 + ),
260 + ),
261 + ),
262 ],
263 ),
200 - AlertCloseButton(image: closeButton)
201 - ],
202 - ));
264 + ),
265 + );
266 + }
267 +
268 + Widget buildSelectedItem() {
269 + final item = widget.items[widget.selectedAtIndex];
270 + final image = images != null ? widget.images[widget.selectedAtIndex] : null;
271 +
272 + return Container(
273 + height: 55,
274 + color: Theme.of(context).accentTextTheme.headline6.color,
275 + padding: EdgeInsets.only(left: 24, right: 24),
276 + child: Row(
277 + mainAxisSize: MainAxisSize.max,
278 + mainAxisAlignment: widget.mainAxisAlignment,
279 + crossAxisAlignment: CrossAxisAlignment.center,
280 + children: <Widget>[
281 + image ?? Offstage(),
282 + Expanded(
283 + child: Padding(
284 + padding: EdgeInsets.only(left: image != null ? 12 : 0),
285 + child: Text(
286 + widget.displayItem?.call(item) ?? item.toString(),
287 + style: TextStyle(
288 + fontSize: 16,
289 + fontFamily: 'Lato',
290 + fontWeight: FontWeight.w700,
291 + color: Theme.of(context).primaryTextTheme.title.color,
292 + decoration: TextDecoration.none,
293 + ),
294 + ),
295 + ),
296 + ),
297 + Icon(Icons.check_circle, color: Theme.of(context).accentTextTheme.body2.color),
298 + ],
299 + ),
300 + );
301 }
302 }
lib/src/widgets/standard_list.dart
+9 -5
@@ -37,11 +37,15 @@ class StandardListRow extends StatelessWidget {
37 return Expanded(
38 child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
39 if (hasLeftOffset) SizedBox(width: 10),
40 - Text(title,
41 - style: TextStyle(
42 - fontSize: 14,
43 - fontWeight: FontWeight.normal,
44 - color: titleColor(context)))
40 + Expanded(
41 + child: Text(title,
42 + style: TextStyle(
43 + fontSize: 14,
44 + fontWeight: FontWeight.normal,
45 + color: titleColor(context),
46 + ),
47 + ),
48 + )
49 ]));
50 }
51
lib/src/widgets/standart_switch.dart
+1 -1
@@ -24,7 +24,7 @@ class StandartSwitchState extends State<StandartSwitch> {
24 height: 28,
25 decoration: BoxDecoration(
26 color: widget.value
27 - ? Colors.green
27 + ? Theme.of(context).accentTextTheme.body2.color
28 : Theme.of(context).accentTextTheme.display4.color,
29 borderRadius: BorderRadius.all(Radius.circular(14.0))),
30 child: Container(
lib/themes/bright_theme.dart
+8
@@ -78,6 +78,14 @@ class BrightTheme extends ThemeBase {
78 decorationColor: Colors.white, // menu background
79 )
80 ),
81 + scrollbarTheme: ScrollbarThemeData(
82 + thumbColor: MaterialStateProperty.all(Palette.moderatePurpleBlue),
83 + trackColor: MaterialStateProperty.all(Palette.periwinkleCraiola),
84 + radius: Radius.circular(3),
85 + thickness: MaterialStateProperty.all(6),
86 + isAlwaysShown: true,
87 + crossAxisMargin: 6,
88 + ),
89 primaryTextTheme: TextTheme(
90 title: TextStyle(
91 color: Palette.darkBlueCraiola, // title color
lib/themes/dark_theme.dart
+8
@@ -77,6 +77,14 @@ class DarkTheme extends ThemeBase {
77 decorationColor: PaletteDark.deepPurpleBlue, // menu background
78 )
79 ),
80 + scrollbarTheme: ScrollbarThemeData(
81 + thumbColor: MaterialStateProperty.all(PaletteDark.wildBlueGrey),
82 + trackColor: MaterialStateProperty.all(PaletteDark.violetBlue),
83 + radius: Radius.circular(3),
84 + thickness: MaterialStateProperty.all(6),
85 + isAlwaysShown: true,
86 + crossAxisMargin: 6,
87 + ),
88 primaryTextTheme: TextTheme(
89 title: TextStyle(
90 color: Colors.white, // title color
lib/themes/light_theme.dart
+8
@@ -78,6 +78,14 @@ class LightTheme extends ThemeBase {
78 decorationColor: Colors.white, // menu background
79 )
80 ),
81 + scrollbarTheme: ScrollbarThemeData(
82 + thumbColor: MaterialStateProperty.all(Palette.moderatePurpleBlue),
83 + trackColor: MaterialStateProperty.all(Palette.periwinkleCraiola),
84 + radius: Radius.circular(3),
85 + thickness: MaterialStateProperty.all(6),
86 + isAlwaysShown: true,
87 + crossAxisMargin: 6,
88 + ),
89 primaryTextTheme: TextTheme(
90 title: TextStyle(
91 color: Palette.darkBlueCraiola, // title color
lib/themes/theme_list.dart
+1 -1
@@ -4,7 +4,7 @@ import 'package:cake_wallet/themes/light_theme.dart';
4 import 'package:cake_wallet/themes/theme_base.dart';
5
6 class ThemeList {
7 - static final all = [lightTheme, brightTheme, darkTheme];
7 + static final all = [brightTheme, lightTheme, darkTheme];
8
9 static final lightTheme = LightTheme(raw: 0);
10 static final brightTheme = BrightTheme(raw: 1);
lib/view_model/settings/choices_list_item.dart new
+25
@@ -0,0 +1,25 @@
1 +import 'package:flutter/foundation.dart';
2 +import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
3 +import 'package:flutter/material.dart';
4 +
5 +class ChoicesListItem<ItemType> extends SettingsListItem {
6 + ChoicesListItem(
7 + {@required String title,
8 + @required this.selectedItem,
9 + @required this.items,
10 + this.displayItem,
11 + void Function(ItemType item) onItemSelected})
12 + : _onItemSelected = onItemSelected,
13 + super(title);
14 +
15 + final ItemType selectedItem;
16 + final List<ItemType> items;
17 + final String Function(ItemType item) displayItem;
18 + final void Function(ItemType item) _onItemSelected;
19 +
20 + void onItemSelected(dynamic item) {
21 + if (item is ItemType) {
22 + _onItemSelected?.call(item);
23 + }
24 + }
25 +}
lib/view_model/settings/picker_list_item.dart
+18 -1
@@ -1,5 +1,6 @@
1 import 'package:flutter/foundation.dart';
2 import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
3 +import 'package:flutter/material.dart';
4
5 class PickerListItem<ItemType> extends SettingsListItem {
6 PickerListItem(
@@ -7,18 +8,34 @@ class PickerListItem<ItemType> extends SettingsListItem {
8 @required this.selectedItem,
9 @required this.items,
10 this.displayItem,
10 - void Function(ItemType item) onItemSelected})
11 + this.images,
12 + this.searchHintText,
13 + this.isGridView = false,
14 + void Function(ItemType item) onItemSelected,
15 + bool Function(ItemType item, String searchText) matchingCriteria})
16 : _onItemSelected = onItemSelected,
17 + _matchingCriteria = matchingCriteria,
18 super(title);
19
20 final ItemType Function() selectedItem;
21 final List<ItemType> items;
22 final String Function(ItemType item) displayItem;
23 final void Function(ItemType item) _onItemSelected;
24 + final List<Image> images;
25 + final String searchHintText;
26 + final bool isGridView;
27 + final bool Function(ItemType, String) _matchingCriteria;
28
29 void onItemSelected(dynamic item) {
30 if (item is ItemType) {
31 _onItemSelected?.call(item);
32 }
33 }
34 +
35 + bool matchingCriteria(dynamic item, String searchText) {
36 + if (item is ItemType) {
37 + return _matchingCriteria?.call(item, searchText);
38 + }
39 + return true;
40 + }
41 }
lib/view_model/settings/settings_view_model.dart
+51 -23
@@ -1,6 +1,7 @@
1 +import 'package:cake_wallet/di.dart';
2 +import 'package:cake_wallet/entities/language_service.dart';
3 import 'package:cake_wallet/store/yat/yat_store.dart';
2 -import 'package:cake_wallet/utils/show_pop_up.dart';
3 -import 'package:cake_wallet/view_model/settings/link_list_item.dart';
4 +import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
5 import 'package:flutter/cupertino.dart';
6 import 'package:mobx/mobx.dart';
7 import 'package:package_info/package_info.dart';
@@ -75,7 +76,7 @@ abstract class SettingsViewModelBase with Store {
76 //var connectYatUrl = YatLink.baseUrl + YatLink.signInSuffix;
77 //final connectYatUrlParameters =
78 // _yatStore.defineQueryParameters();
78 -
79 +
80 //if (connectYatUrlParameters.isNotEmpty) {
81 // connectYatUrl += YatLink.queryParameter + connectYatUrlParameters;
82 //}
@@ -83,7 +84,7 @@ abstract class SettingsViewModelBase with Store {
84 //var manageYatUrl = YatLink.baseUrl + YatLink.managePath;
85 //final manageYatUrlParameters =
86 // _yatStore.defineQueryParameters();
86 -
87 +
88 //if (manageYatUrlParameters.isNotEmpty) {
89 // manageYatUrl += YatLink.queryParameter + manageYatUrlParameters;
90 //}
@@ -91,27 +92,41 @@ abstract class SettingsViewModelBase with Store {
92 //var createNewYatUrl = YatLink.startFlowUrl;
93 //final createNewYatUrlParameters =
94 // _yatStore.defineQueryParameters();
94 -
95 +
96 //if (createNewYatUrlParameters.isNotEmpty) {
97 // createNewYatUrl += '?sub1=' + createNewYatUrlParameters;
98 //}
99
99 -
100 +
101 sections = [
102 [
102 - PickerListItem(
103 - title: S.current.settings_display_balance_as,
104 - items: BalanceDisplayMode.all,
105 - selectedItem: () => balanceDisplayMode,
106 - onItemSelected: (BalanceDisplayMode mode) =>
107 - _settingsStore.balanceDisplayMode = mode),
103 + SwitcherListItem(
104 + title: S.current.settings_display_balance,
105 + value: () => balanceDisplayMode == BalanceDisplayMode.displayableBalance,
106 + onValueChange: (_, bool value) {
107 + if (value) {
108 + _settingsStore.balanceDisplayMode = BalanceDisplayMode.displayableBalance;
109 + } else {
110 + _settingsStore.balanceDisplayMode = BalanceDisplayMode.hiddenBalance;
111 + }
112 + },
113 + ),
114 if (!isHaven)
115 PickerListItem(
116 title: S.current.settings_currency,
117 + searchHintText: S.current.search_currency,
118 items: FiatCurrency.all,
119 selectedItem: () => fiatCurrency,
120 onItemSelected: (FiatCurrency currency) =>
114 - setFiatCurrency(currency)),
121 + setFiatCurrency(currency),
122 + images: FiatCurrency.all.map(
123 + (e) => Image.asset("assets/images/flags/${e.countryCode}.png"))
124 + .toList(),
125 + isGridView: true,
126 + matchingCriteria: (FiatCurrency currency, String searchText) {
127 + return currency.title.toLowerCase().contains(searchText) || currency.fullName.toLowerCase().contains(searchText);
128 + },
129 + ),
130 PickerListItem(
131 title: S.current.settings_fee_priority,
132 items: priorityForWalletType(wallet.type),
@@ -150,10 +165,23 @@ abstract class SettingsViewModelBase with Store {
165 }
166 });
167 }),
153 - RegularListItem(
154 - title: S.current.settings_change_language,
155 - handler: (BuildContext context) =>
156 - Navigator.of(context).pushNamed(Routes.changeLanguage),
168 + PickerListItem(
169 + title: S.current.settings_change_language,
170 + searchHintText: S.current.search_language,
171 + items: LanguageService.list.keys.toList(),
172 + displayItem: (dynamic code) {
173 + return LanguageService.list[code];
174 + },
175 + selectedItem: () => getIt.get<SettingsStore>().languageCode,
176 + onItemSelected: (String code) {
177 + getIt.get<SettingsStore>().languageCode = code;
178 + },
179 + images: LanguageService.list.keys.map(
180 + (e) => Image.asset("assets/images/flags/${LanguageService.localeCountryCode[e]}.png"))
181 + .toList(),
182 + matchingCriteria: (String code, String searchText) {
183 + return LanguageService.list[code].toLowerCase().contains(searchText);
184 + },
185 ),
186 SwitcherListItem(
187 title: S.current.settings_allow_biometrical_authentication,
@@ -180,12 +208,12 @@ abstract class SettingsViewModelBase with Store {
208 setAllowBiometricalAuthentication(value);
209 }
210 }),
183 - PickerListItem(
184 - title: S.current.color_theme,
185 - items: ThemeList.all,
186 - selectedItem: () => theme,
187 - onItemSelected: (ThemeBase theme) =>
188 - _settingsStore.currentTheme = theme)
211 + ChoicesListItem(
212 + title: S.current.color_theme,
213 + items: ThemeList.all,
214 + selectedItem: theme,
215 + onItemSelected: (ThemeBase theme) => _settingsStore.currentTheme = theme,
216 + ),
217 ],
218 //[
219 //if (_yatStore.emoji.isNotEmpty) ...[
pubspec_base.yaml
+1
@@ -76,6 +76,7 @@ flutter:
76
77 assets:
78 - assets/images/
79 + - assets/images/flags/
80 - assets/node_list.yml
81 - assets/haven_node_list.yml
82 - assets/bitcoin_electrum_server_list.yml
res/values/strings_de.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Knoten",
229 "settings_current_node" : "Aktueller Knoten",
230 "settings_wallets" : "Wallets",
231 - "settings_display_balance_as" : "Kontostand anzeigen in",
231 + "settings_display_balance" : "Kontostand anzeigen",
232 "settings_currency" : "Währung",
233 "settings_fee_priority" : "Gebührenpriorität",
234 "settings_save_recipient_address" : "Empfängeradresse speichern",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!",
531 "learn_more" : "Erfahren Sie mehr",
532 "search": "Suche",
533 + "search_language": "Sprache suchen",
534 + "search_currency": "Währung suchen",
535 "new_template" : "neue Vorlage",
536 "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin"
537 }
res/values/strings_en.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Nodes",
229 "settings_current_node" : "Current node",
230 "settings_wallets" : "Wallets",
231 - "settings_display_balance_as" : "Display balance as",
231 + "settings_display_balance" : "Display balance",
232 "settings_currency" : "Currency",
233 "settings_fee_priority" : "Fee priority",
234 "settings_save_recipient_address" : "Save recipient address",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!",
531 "learn_more" : "Learn More",
532 "search": "Search",
533 + "search_language": "Search language",
534 + "search_currency": "Search currency",
535 "new_template" : "New Template",
536 "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
537 }
res/values/strings_es.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Nodos",
229 "settings_current_node" : "Nodo actual",
230 "settings_wallets" : "Carteras",
231 - "settings_display_balance_as" : "Mostrar saldo como",
231 + "settings_display_balance" : "Mostrar saldo",
232 "settings_currency" : "Moneda",
233 "settings_fee_priority" : "Prioridad de tasa",
234 "settings_save_recipient_address" : "Guardar dirección del destinatario",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Los Yats también viven fuera de Cake Wallet. Cualquier dirección de billetera en la tierra se puede reemplazar con un Yat!",
531 "learn_more" : "Aprende más",
532 "search": "Búsqueda",
533 + "search_language": "Idioma de búsqueda",
534 + "search_currency": "Moneda de búsqueda",
535 "new_template" : "Nueva plantilla",
536 "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando"
537 }
res/values/strings_fr.arb
+4 -2
@@ -226,7 +226,7 @@
226 "settings_nodes" : "Nœuds",
227 "settings_current_node" : "Nœud actuel",
228 "settings_wallets" : "Portefeuilles",
229 - "settings_display_balance_as" : "Afficher le solde en",
229 + "settings_display_balance" : "Afficher le solde",
230 "settings_currency" : "Devise",
231 "settings_fee_priority" : "Priorité des frais",
232 "settings_save_recipient_address" : "Sauvegarder l'adresse du bénéficiaire",
@@ -527,7 +527,9 @@
527 "third_intro_title" : "Yat joue bien avec les autres",
528 "third_intro_content" : "Les Yats existent aussi en dehors de Cake Wallet. Toute adresse sur terre peut être remplacée par un Yat !",
529 "learn_more" : "En savoir plus",
530 -
530 + "search": "Chercher",
531 + "search_language": "Langue de recherche",
532 + "search_currency": "Devise de recherche",
533 "new_template" : "Nouveau Modèle",
534 "electrum_address_disclaimer": "Nous générons de nouvelles adresses à chaque fois que vous en utilisez une, mais les adresses précédentes continuent à fonctionner"
535 }
res/values/strings_hi.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "नोड्स",
229 "settings_current_node" : "वर्तमान नोड",
230 "settings_wallets" : "पर्स",
231 - "settings_display_balance_as" : "के रूप में संतुलन प्रदर्शित करें",
231 + "settings_display_balance" : "प्रदर्शन संतुलन",
232 "settings_currency" : "मुद्रा",
233 "settings_fee_priority" : "शुल्क प्राथमिकता",
234 "settings_save_recipient_address" : "प्राप्तकर्ता का पता सहेजें",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!",
531 "learn_more" : "और अधिक जानें",
532 "search": "खोज",
533 + "search_language": "भाषा खोजें",
534 + "search_currency": "मुद्रा खोजें",
535 "new_template" : "नया टेम्पलेट",
536 "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं"
537 }
res/values/strings_hr.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Nodovi",
229 "settings_current_node" : "Trenutni node",
230 "settings_wallets" : "Novčanik",
231 - "settings_display_balance_as" : "Prikaži stanje računa kao",
231 + "settings_display_balance" : "Prikaži stanje računa",
232 "settings_currency" : "Valuta",
233 "settings_fee_priority" : "Prioritet naknade",
234 "settings_save_recipient_address" : "Spremi primateljevu adresu",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats žive i izvan Cake Wallet -a. Bilo koja adresa novčanika na svijetu može se zamijeniti Yat!",
531 "learn_more" : "Saznajte više",
532 "search": "Traži",
533 + "search_language": "Jezik pretraživanja",
534 + "search_currency": "Traži valutu",
535 "new_template" : "novi predložak",
536 "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek"
537 }
res/values/strings_it.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Nodi",
229 "settings_current_node" : "Nodo attuale",
230 "settings_wallets" : "Portafogli",
231 - "settings_display_balance_as" : "Mostra saldo come",
231 + "settings_display_balance" : "Mostra saldo",
232 "settings_currency" : "Moneta",
233 "settings_fee_priority" : "Priorità commissione",
234 "settings_save_recipient_address" : "Salva indirizzo di destinazione",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Anche Yats vive fuori da Cake Wallet. Qualsiasi indirizzo di portafoglio sulla terra può essere sostituito con un Yat!",
531 "learn_more" : "Impara di più",
532 "search": "Ricerca",
533 + "search_language": "Cerca lingua",
534 + "search_currency": "Cerca valuta",
535 "new_template" : "Nuovo modello",
536 "electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare"
537 }
res/values/strings_ja.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "ノード",
229 "settings_current_node" : "現在のノード",
230 "settings_wallets" : "財布",
231 - "settings_display_balance_as" : "残高を表示",
231 + "settings_display_balance" : "ディスプレイバランス",
232 "settings_currency" : "通貨",
233 "settings_fee_priority" : "料金優先",
234 "settings_save_recipient_address" : "受信者のアドレスを保存",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "YatsはCakeWalletの外にも住んでいます。 地球上のどのウォレットアドレスもYatに置き換えることができます!",
531 "learn_more" : "もっと詳しく知る",
532 "search": "検索",
533 + "search_language": "検索言語",
534 + "search_currency": "検索通貨",
535 "new_template" : "新しいテンプレート",
536 "electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します"
537 }
res/values/strings_ko.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "노드",
229 "settings_current_node" : "현재 노드",
230 "settings_wallets" : "지갑",
231 - "settings_display_balance_as" : "잔액 표시",
231 + "settings_display_balance" : "디스플레이 잔액",
232 "settings_currency" : "통화",
233 "settings_fee_priority" : "수수료 우선",
234 "settings_save_recipient_address" : "수신자 주소 저장",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats는 Cake Wallet 밖에서도 살고 있습니다. 지구상의 모든 지갑 주소는 Yat!",
531 "learn_more" : "더 알아보기",
532 "search": "찾다",
533 + "search_language": "검색 언어",
534 + "search_currency": "통화 검색",
535 "new_template" : "새 템플릿",
536 "electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다."
537 }
res/values/strings_nl.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "knooppunten",
229 "settings_current_node" : "Huidige knooppunt",
230 "settings_wallets" : "Portemonnee",
231 - "settings_display_balance_as" : "Toon saldo als",
231 + "settings_display_balance" : "Saldo weergeven",
232 "settings_currency" : "Valuta",
233 "settings_fee_priority" : "Tariefprioriteit",
234 "settings_save_recipient_address" : "Adres ontvanger opslaan",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats wonen ook buiten Cake Wallet. Elk portemonnee-adres op aarde kan worden vervangen door een Yat!",
531 "learn_more" : "Kom meer te weten",
532 "search": "Zoekopdracht",
533 + "search_language": "Zoektaal",
534 + "search_currency": "Zoek valuta",
535 "new_template" : "Nieuwe sjabloon",
536 "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
537 }
res/values/strings_pl.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Węzły",
229 "settings_current_node" : "Bieżący węzeł",
230 "settings_wallets" : "Portfele",
231 - "settings_display_balance_as" : "Wyświetl saldo jako",
231 + "settings_display_balance" : "Wyświetl saldo",
232 "settings_currency" : "Waluta",
233 "settings_fee_priority" : "Priorytet opłaty",
234 "settings_save_recipient_address" : "Zapisz adres odbiorcy",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats mieszkają również poza Cake Wallet. Każdy adres portfela na ziemi można zastąpić Yat!",
531 "learn_more" : "Ucz się więcej",
532 "search": "Szukaj",
533 + "search_language": "Wyszukaj język",
534 + "search_currency": "Wyszukaj walutę",
535 "new_template" : "Nowy szablon",
536 "electrum_address_disclaimer": "Za każdym razem, gdy korzystasz z jednego z nich, generujemy nowe adresy, ale poprzednie adresy nadal działają"
537 }
res/values/strings_pt.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Nós",
229 "settings_current_node" : "Nó atual",
230 "settings_wallets" : "Carteiras",
231 - "settings_display_balance_as" : "Saldo a exibir",
231 + "settings_display_balance" : "Exibir saldo",
232 "settings_currency" : "Moeda",
233 "settings_fee_priority" : "Prioridade da taxa",
234 "settings_save_recipient_address" : "Salvar endereço do destinatário",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yats também mora fora da Cake Wallet. Qualquer endereço de carteira na Terra pode ser substituído por um Yat!",
531 "learn_more" : "Saber mais",
532 "search": "Procurar",
533 + "search_language": "Idioma de pesquisa",
534 + "search_currency": "Pesquisar moeda",
535 "new_template" : "Novo modelo",
536 "electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando"
537 }
res/values/strings_ru.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "Ноды",
229 "settings_current_node" : "Текущая нода",
230 "settings_wallets" : "Кошельки",
231 - "settings_display_balance_as" : "Отображать баланс как",
231 + "settings_display_balance" : "Отображать баланс",
232 "settings_currency" : "Валюта",
233 "settings_fee_priority" : "Приоритет транзакции",
234 "settings_save_recipient_address" : "Сохранять адрес получателя",
@@ -530,6 +530,8 @@
530 "third_intro_content" : "Yat находятся за пределами Cake Wallet. Любой адрес кошелька на земле можно заменить на Yat!",
531 "learn_more" : "Узнать больше",
532 "search": "Поиск",
533 + "search_language": "Язык поиска",
534 + "search_currency": "Валюта поиска",
535 "new_template" : "Новый шаблон",
536 "electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать."
537 }
res/values/strings_uk.arb
+3 -1
@@ -227,7 +227,7 @@
227 "settings_nodes" : "Вузли",
228 "settings_current_node" : "Поточний вузол",
229 "settings_wallets" : "Гаманці",
230 - "settings_display_balance_as" : "Відображати баланс як",
230 + "settings_display_balance" : "Відображати баланс",
231 "settings_currency" : "Валюта",
232 "settings_fee_priority" : "Пріоритет транзакції",
233 "settings_save_recipient_address" : "Зберігати адресу отримувача",
@@ -529,6 +529,8 @@
529 "third_intro_content" : "Yat знаходиться за межами Cake Wallet. Будь-яку адресу гаманця на землі можна замінити на Yat!",
530 "learn_more" : "Дізнатися більше",
531 "search": "Пошук",
532 + "search_language": "Мова пошуку",
533 + "search_currency": "Шукати валюту",
534 "new_template" : "Новий шаблон",
535 "electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати"
536 }
res/values/strings_zh.arb
+3 -1
@@ -228,7 +228,7 @@
228 "settings_nodes" : "节点数",
229 "settings_current_node" : "当前节点",
230 "settings_wallets" : "钱包",
231 - "settings_display_balance_as" : "将余额显示为",
231 + "settings_display_balance" : "显示余额为",
232 "settings_currency" : "货币",
233 "settings_fee_priority" : "交易优先级",
234 "settings_save_recipient_address" : "保存收件人地址",
@@ -528,6 +528,8 @@
528 "third_intro_content" : "Yats 也住在 Cake Wallet 之外。 地球上任何一個錢包地址都可以用一個Yat來代替!",
529 "learn_more" : "了解更多",
530 "search": "搜索",
531 + "search_language": "搜索语言",
532 + "search_currency": "搜索货币",
533 "new_template" : "新模板",
534 "electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效"
535 }