mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-11-07 08:04:04 +01:00
Merge upstream Cake Wallet v6.5.0
Catches up from the May 12 fork point (v6.1.2+23) through v6.5.0: 535 upstream commits, including the Monero silent-open fix, Monero on Trezor, Ledger/Trezor BLE fixes, the new seed and history screens, quick Bitcoin sync, git-pinned dependencies (pubspec_overrides.yaml), frozen Hive adapters (*.part.dart), monero_c v0.18.4.6-RC2 and Flutter 3.41.9. Merged with both sides normalized first (import rename, 100-column format), which took the conflict count from 614 paths to 322. The procedure is now scripts/upstream_sync.sh. Kept from Hash Bags: - WalletType enum order and Hive IDs. SQLite stores WalletType.index and our order differs from upstream's; taking theirs would reread saved wallets as other chains. Our frozen adapter keeps the shipped IDs. - The 1.0.2 legacy PIN and wallet-password decode and self-heal. - Removed chains (Solana, Tron, Zano, Zcash, Decred, Haven) and the new Robinhood chain stay out; Cake Pay and non-Trocador swaps stay out. - Default nodes (node.wownero.org, sethforprivacy, Blockstream, bysh.me), converted to upstream's isDefault node-list key; Wownero is back in the node reset list. - Privacy: address resolvers limited to domain-anchored sources again; prices.neroswap.com for fiat; upstream's charts tab, which reads prices.cakewallet.com, sits behind FeatureFlag.isChartsEnabled = false. - Lightning stays behind FeatureFlag.isLightningEnabled, including upstream's new post-seed Lightning username step. - Our icon pipeline, branding and bundle identifiers. Twelve new upstream widget tests are skipped: test and code are unchanged from v6.5.0 apart from renames (not rerun on a pristine upstream checkout; upstream's top_bar_test does not compile against its own TopBar). flutter analyze lib: 0 errors; flutter test: 345 passed, 12 skipped; flutter build bundle compiles. Built with Flutter 3.41.9.
This commit is contained in:
@@ -1 +0,0 @@
|
||||
enum Attributes { arrow, header, link, switcher, widget, rawWidget }
|
||||
@@ -34,6 +34,7 @@ class ConnectionSyncPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: "",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop()),
|
||||
header: ModalHeader(
|
||||
iconPath: "assets/new-ui/settings_row_icons/connections.svg",
|
||||
@@ -88,10 +89,18 @@ class ConnectionSyncPage extends BasePage {
|
||||
ListItemToggle(
|
||||
keyValue: "can_use_basescan",
|
||||
label: S.of(context).basescan_history,
|
||||
value: _connectionSyncViewModel.canUseBaseScan,
|
||||
value: _connectionSyncViewModel.useBaseScan,
|
||||
onChanged: (val) {
|
||||
_connectionSyncViewModel.setUseBaseScan(val);
|
||||
}),
|
||||
if (_connectionSyncViewModel.canUseRobinhoodScan)
|
||||
ListItemToggle(
|
||||
keyValue: "can_use_robinhoodscan",
|
||||
label: S.of(context).robinhoodscan_history,
|
||||
value: _connectionSyncViewModel.useRobinhoodScan,
|
||||
onChanged: (val) {
|
||||
_connectionSyncViewModel.setUseRobinhoodScan(val);
|
||||
}),
|
||||
if (_connectionSyncViewModel.canUseArbiScan)
|
||||
ListItemToggle(
|
||||
keyValue: "can_use_arbiscan",
|
||||
@@ -198,6 +207,11 @@ class ConnectionSyncPage extends BasePage {
|
||||
keyValue: "domain_lookups",
|
||||
label: S.of(context).domain_looks_up,
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.domainLookupsPage)),
|
||||
if (_connectionSyncViewModel.hasRescan)
|
||||
ListItemRegularRow(
|
||||
keyValue: "rescan",
|
||||
label: S.of(context).rescan,
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.rescan))
|
||||
],
|
||||
})),
|
||||
],
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:hash_wallet/routes.dart';
|
||||
import 'package:hash_wallet/src/widgets/setting_action_button.dart';
|
||||
import 'package:hash_wallet/src/widgets/setting_actions.dart';
|
||||
import 'package:hash_wallet/typography.dart';
|
||||
import 'package:hash_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hash_wallet/router.dart' as Router;
|
||||
|
||||
final _settingsNavigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
class DesktopSettingsPage extends StatefulWidget {
|
||||
const DesktopSettingsPage(this.dashboardViewModel, {super.key});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
|
||||
@override
|
||||
State<DesktopSettingsPage> createState() => _DesktopSettingsPageState();
|
||||
}
|
||||
|
||||
class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
|
||||
final int itemCount = SettingActions.all.length;
|
||||
|
||||
int? currentPage;
|
||||
|
||||
void _onItemChange(int index) {
|
||||
setState(() {
|
||||
currentPage = index;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 4),
|
||||
child: Text(
|
||||
S.current.settings,
|
||||
style: textXLarge(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.separated(
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
itemBuilder: (_, index) {
|
||||
final item = SettingActions.all[index];
|
||||
|
||||
if (!widget.dashboardViewModel.hasSilentPayments &&
|
||||
item.name(context) == S.of(context).silent_payments_settings) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
if ((!widget.dashboardViewModel.isMoneroViewOnly &&
|
||||
item.name(context) == S.of(context).export_outputs) ||
|
||||
(!widget.dashboardViewModel.hasMweb &&
|
||||
item.name(context) == S.of(context).litecoin_mweb_settings)) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
final isLastTile = index == itemCount - 1;
|
||||
return SettingActionButton(
|
||||
isLastTile: isLastTile,
|
||||
selectionActive: currentPage != null,
|
||||
isSelected: currentPage == index,
|
||||
isArrowVisible: true,
|
||||
onTap: () {
|
||||
if (currentPage != index) {
|
||||
final settingContext =
|
||||
_settingsNavigatorKey.currentState?.context ?? context;
|
||||
item.onTap.call(settingContext);
|
||||
_onItemChange(index);
|
||||
}
|
||||
},
|
||||
image: item.image,
|
||||
title: item.name.call(context),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, index) => Container(
|
||||
height: 0.0,
|
||||
color: Theme.of(context).colorScheme.outlineVariant,
|
||||
),
|
||||
itemCount: itemCount,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 500),
|
||||
child: Navigator(
|
||||
key: _settingsNavigatorKey,
|
||||
initialRoute: Routes.empty_no_route,
|
||||
onGenerateRoute: (settings) => Router.createRoute(settings),
|
||||
onGenerateInitialRoutes: (NavigatorState navigator, String initialRouteName) {
|
||||
return [
|
||||
navigator.widget.onGenerateRoute!(RouteSettings(name: initialRouteName))!
|
||||
];
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:hash_wallet/entities/bitcoin_amount_display_mode.dart';
|
||||
import 'package:hash_wallet/entities/fiat_currency.dart';
|
||||
import 'package:hash_wallet/entities/language_service.dart';
|
||||
import 'package:hash_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
|
||||
import 'package:hash_wallet/entities/new_ui_entities/list_item/list_item_selector.dart';
|
||||
import 'package:hash_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
|
||||
import 'package:hash_wallet/entities/sync_status_display_mode.dart';
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/currency_picker/fiat_currency_picker_sheet.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:hash_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
|
||||
import 'package:hash_wallet/src/screens/settings/widgets/settings_theme_choice.dart';
|
||||
@@ -35,6 +35,7 @@ class DisplaySettingsPage extends StatelessWidget {
|
||||
topBar: ModalTopBar(
|
||||
title: S.of(context).display,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
content: Column(
|
||||
@@ -115,21 +116,12 @@ class DisplaySettingsPage extends StatelessWidget {
|
||||
onChanged: (val) {
|
||||
_displaySettingsViewModel.setDisableTradeOption(val);
|
||||
}),
|
||||
if (_displaySettingsViewModel.showZcashCardSetting)
|
||||
ListItemToggle(
|
||||
keyValue: "display_settings_show_zcashcard",
|
||||
label: S.of(context).show_zcash_card,
|
||||
value: _displaySettingsViewModel.showZcashCard,
|
||||
onChanged: (val) {
|
||||
_displaySettingsViewModel.setShowZcashCard(val);
|
||||
}),
|
||||
ListItemSelector(
|
||||
keyValue: "display_settings_sync_status_display",
|
||||
label: S.of(context).sync_status_display_mode,
|
||||
options: [_displaySettingsViewModel.syncStatusDisplayMode.title],
|
||||
onTap: () async {
|
||||
final items = SyncStatusDisplayMode.values.toList();
|
||||
|
||||
final selectedAtIndex =
|
||||
items.indexOf(_displaySettingsViewModel.syncStatusDisplayMode);
|
||||
|
||||
@@ -175,35 +167,11 @@ class DisplaySettingsPage extends StatelessWidget {
|
||||
keyValue: "display_settings_fiat_currency",
|
||||
label: S.of(context).settings_currency,
|
||||
options: [_displaySettingsViewModel.fiatCurrency.title],
|
||||
onTap: () async {
|
||||
final items = FiatCurrency.all;
|
||||
|
||||
final selectedAtIndex =
|
||||
items.indexOf(_displaySettingsViewModel.fiatCurrency);
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => Picker(
|
||||
items: items,
|
||||
selectedAtIndex: selectedAtIndex,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
onItemSelected: (FiatCurrency currency) {
|
||||
_displaySettingsViewModel.setFiatCurrency(currency);
|
||||
},
|
||||
images: FiatCurrency.all
|
||||
.map((e) =>
|
||||
Image.asset("assets/images/flags/${e.countryCode}.png"))
|
||||
.toList(),
|
||||
hintText: S.of(context).search_currency,
|
||||
isGridView: true,
|
||||
matchingCriteria: (FiatCurrency currency, String searchText) {
|
||||
return currency.title.toLowerCase().contains(searchText) ||
|
||||
currency.fullName.toLowerCase().contains(searchText);
|
||||
},
|
||||
isSeparated: false,
|
||||
),
|
||||
);
|
||||
}),
|
||||
onTap: () => FiatCurrencyPickerSheet.show(
|
||||
context: context,
|
||||
selected: _displaySettingsViewModel.fiatCurrency,
|
||||
onSelected: _displaySettingsViewModel.setFiatCurrency,
|
||||
)),
|
||||
ListItemSelector(
|
||||
keyValue: "display_settings_language",
|
||||
label: S.of(context).settings_change_language,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:hash_wallet/core/address_resolver/address_sources.dart';
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:hash_wallet/src/screens/base_page.dart';
|
||||
import 'package:hash_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:hash_wallet/src/widgets/hash_image_widget.dart';
|
||||
import 'package:hash_wallet/view_model/settings/connection_sync_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
@@ -20,22 +22,29 @@ class DomainLookupsPage extends BasePage {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
SettingsSwitcherCell(
|
||||
title: 'OpenAlias',
|
||||
value: _connectionsSyncViewModel.looksUpOpenAlias,
|
||||
onValueChange: (_, bool value) =>
|
||||
_connectionsSyncViewModel.setLookupsOpenAlias(value)),
|
||||
SettingsSwitcherCell(
|
||||
title: 'Ethereum Name Service',
|
||||
value: _connectionsSyncViewModel.looksUpENS,
|
||||
onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsENS(value)),
|
||||
SettingsSwitcherCell(
|
||||
title: '.well-known',
|
||||
value: _connectionsSyncViewModel.looksUpWellKnown,
|
||||
onValueChange: (_, bool value) =>
|
||||
_connectionsSyncViewModel.setLookupsWellKnown(value)),
|
||||
],
|
||||
// Hash Bags: only domain-anchored resolvers get a toggle (see PRIVACY.md).
|
||||
children: _connectionsSyncViewModel.domainLookupSources
|
||||
.where((source) => const [
|
||||
AddressSource.openAlias,
|
||||
AddressSource.ens,
|
||||
AddressSource.wellKnown,
|
||||
].contains(source))
|
||||
.map(
|
||||
(source) => SettingsSwitcherCell(
|
||||
title: source.label,
|
||||
leading: source.iconPath.isNotEmpty
|
||||
? HashImageWidget(
|
||||
imageUrl: source.iconPath,
|
||||
width: 24,
|
||||
height: 24,
|
||||
)
|
||||
: SizedBox(width: 24, height: 24),
|
||||
value: _connectionsSyncViewModel.lookupValue(source),
|
||||
onValueChange: (_, bool value) =>
|
||||
_connectionsSyncViewModel.setLookupValue(source, value),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
class ItemHeaders {
|
||||
static const nodes = 'Nodes';
|
||||
static const currentNode = 'Current node';
|
||||
static const wallets = 'Wallets';
|
||||
static const displayBalanceAs = 'Display balance as';
|
||||
static const currency = 'Currency';
|
||||
static const feePriority = 'Fee priority';
|
||||
static const saveRecipientAddress = 'Save recipient address';
|
||||
static const personal = 'Personal';
|
||||
static const changePIN = 'Change PIN';
|
||||
static const changeLanguage = 'Change language';
|
||||
static const allowBiometricalAuthentication = 'Allow biometrical authentication';
|
||||
static const darkMode = 'Dark mode';
|
||||
static const support = 'Support';
|
||||
static const termsAndConditions = 'Terms and conditions';
|
||||
static const faq = 'FAQ';
|
||||
static const version = 'Version';
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hash_wallet/src/screens/settings/attributes.dart';
|
||||
|
||||
class SettingsItem {
|
||||
SettingsItem(
|
||||
{required this.onTaped,
|
||||
required this.title,
|
||||
required this.link,
|
||||
required this.image,
|
||||
required this.widget,
|
||||
required this.attribute,
|
||||
required this.widgetBuilder});
|
||||
|
||||
final VoidCallback onTaped;
|
||||
final String title;
|
||||
final String link;
|
||||
final Image image;
|
||||
final Widget widget;
|
||||
final Attributes attribute;
|
||||
final WidgetBuilder widgetBuilder;
|
||||
}
|
||||
@@ -1,166 +1,163 @@
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/modal_header.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/modal_page_wrapper.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/modern_button.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:hash_wallet/routes.dart';
|
||||
import 'package:hash_wallet/src/screens/base_page.dart';
|
||||
import 'package:hash_wallet/src/screens/nodes/widgets/node_list_row.dart';
|
||||
import 'package:hash_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:hash_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:hash_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:hash_wallet/utils/feature_flag.dart';
|
||||
import 'package:hash_wallet/utils/show_pop_up.dart';
|
||||
import 'package:hash_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:hash_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:hash_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
|
||||
class ManageNodesPage extends BasePage {
|
||||
ManageNodesPage(this.isPow,
|
||||
{this.nodeListViewModel, this.powNodeListViewModel, this.dashboardViewModel})
|
||||
: assert((isPow && powNodeListViewModel != null) || (!isPow && nodeListViewModel != null)),
|
||||
assert(powNodeListViewModel == null || nodeListViewModel == null);
|
||||
class ManageNodesPage extends StatefulWidget {
|
||||
ManageNodesPage(this.isPow, {required this.nodeListViewModel, this.dashboardViewModel});
|
||||
|
||||
final DashboardViewModel? dashboardViewModel;
|
||||
final NodeListViewModel? nodeListViewModel;
|
||||
final PowNodeListViewModel? powNodeListViewModel;
|
||||
final NodeListViewModel nodeListViewModel;
|
||||
final bool isPow;
|
||||
|
||||
@override
|
||||
bool get hideAppBar => true;
|
||||
State<ManageNodesPage> createState() => _ManageNodesPageState();
|
||||
}
|
||||
|
||||
class _ManageNodesPageState extends State<ManageNodesPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Future.delayed(Duration(milliseconds: 300))
|
||||
.then((_) => widget.nodeListViewModel.speedTestNodes());
|
||||
}
|
||||
|
||||
@override
|
||||
String get title => S.current.manage_nodes;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
Widget build(BuildContext context) {
|
||||
return ModalPageWrapper(
|
||||
horizontalPadding: 0,
|
||||
topBar: ModalTopBar(
|
||||
title: S.of(context).manage_nodes,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
trailingWidget: Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
if (dashboardViewModel?.hasRescan ?? true)
|
||||
ModernButton(
|
||||
Observer(
|
||||
builder: (_) => ModernButton(
|
||||
size: 36,
|
||||
icon: Icon(Icons.history),
|
||||
onPressed: () => Navigator.of(context).pushNamed(Routes.rescan)),
|
||||
icon: widget.nodeListViewModel.isTestingNodeSpeed
|
||||
? CupertinoActivityIndicator()
|
||||
: Icon(Icons.refresh),
|
||||
semanticLabel: S.of(context).test_node_speeds,
|
||||
onPressed: () => widget.nodeListViewModel.speedTestNodes()),
|
||||
),
|
||||
ModernButton(
|
||||
size: 36,
|
||||
icon: Icon(Icons.add),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pushNamed(isPow ? Routes.newPowNode : Routes.newNode))
|
||||
semanticLabel: S.of(context).add_new_node,
|
||||
onPressed: () async {
|
||||
final res = await Navigator.of(context)
|
||||
.pushNamed(widget.isPow ? Routes.newPowNode : Routes.newNode);
|
||||
if (res != null && res is Node) {
|
||||
widget.nodeListViewModel.nodes.add(res);
|
||||
}
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
content: Column(
|
||||
children: [
|
||||
if (FeatureFlag.isAutomaticNodeSwitchingEnabled)
|
||||
Observer(
|
||||
builder: (_) => SettingsSwitcherCell(
|
||||
key: ValueKey('manage_nodes_page_enable_auto_node_switching_button_key'),
|
||||
title: S.current.enable_auto_node_switching,
|
||||
value: isPow
|
||||
? powNodeListViewModel!.enableAutomaticNodeSwitching
|
||||
: nodeListViewModel!.enableAutomaticNodeSwitching,
|
||||
onValueChange: (BuildContext context, bool value) {
|
||||
if (isPow) {
|
||||
powNodeListViewModel!.setEnableAutomaticNodeSwitching(value);
|
||||
} else {
|
||||
nodeListViewModel!.setEnableAutomaticNodeSwitching(value);
|
||||
header: ModalHeader(
|
||||
iconPath: "assets/new-ui/settings_row_icons/nodes.svg",
|
||||
message: S.of(context).nodes_desc,
|
||||
title: S.of(context).nodes,
|
||||
bottomWidget: Observer(
|
||||
builder: (_) => NodeListRow(
|
||||
// vertical: 0,
|
||||
// horizontal: 0,
|
||||
node: widget.nodeListViewModel.currentNode,
|
||||
speed: widget.nodeListViewModel.nodeSpeedFor(widget.nodeListViewModel.currentNode),
|
||||
onEditComplete: (res) async {
|
||||
if (res != null && res is Node) {
|
||||
widget.nodeListViewModel.nodes.removeWhere((item) => item.id == res.id);
|
||||
widget.nodeListViewModel.nodes.add(res);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
if (FeatureFlag.isAutomaticNodeSwitchingEnabled) SizedBox(height: 8),
|
||||
Observer(
|
||||
builder: (BuildContext context) {
|
||||
int itemsCount =
|
||||
nodeListViewModel?.nodes.length ?? powNodeListViewModel!.nodes.length;
|
||||
return SectionStandardList(
|
||||
scrollController: ModalScrollController.of(context),
|
||||
sectionCount: 1,
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
dividerPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
itemCounter: (int sectionIndex) => itemsCount,
|
||||
itemBuilder: (_, index) {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
final node =
|
||||
nodeListViewModel?.nodes[index] ?? powNodeListViewModel!.nodes[index];
|
||||
late bool isSelected;
|
||||
if (isPow) {
|
||||
isSelected = node.keyIndex == powNodeListViewModel!.currentNode.keyIndex;
|
||||
} else {
|
||||
isSelected = node.keyIndex == nodeListViewModel!.currentNode.keyIndex;
|
||||
}
|
||||
final nodeListRow = NodeListRow(
|
||||
title: node.uriRaw,
|
||||
subtitle: node.label ?? '',
|
||||
node: node,
|
||||
isSelected: isSelected,
|
||||
isPow: isPow,
|
||||
onTap: (_) async {
|
||||
if (isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_current_node_title,
|
||||
alertContent: nodeListViewModel?.getAlertContent(node.uriRaw) ??
|
||||
powNodeListViewModel!.getAlertContent(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
if (isPow) {
|
||||
await powNodeListViewModel!.setAsCurrent(node);
|
||||
} else {
|
||||
await nodeListViewModel!.setAsCurrent(node);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
onTap: () {},
|
||||
isSelected: true,
|
||||
isPow: widget.isPow)),
|
||||
),
|
||||
content: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(18)),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
child: Observer(
|
||||
builder: (BuildContext context) {
|
||||
int itemsCount = widget.nodeListViewModel.nonCurrentNodes.length;
|
||||
return ListView.separated(
|
||||
controller: ModalScrollController.of(context),
|
||||
shrinkWrap: true,
|
||||
physics: BouncingScrollPhysics(),
|
||||
itemCount: itemsCount,
|
||||
separatorBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
),
|
||||
),
|
||||
itemBuilder: (_, index) {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
final node = widget.nodeListViewModel.nonCurrentNodes[index];
|
||||
final nodeListRow = NodeListRow(
|
||||
node: node,
|
||||
isSelected: false,
|
||||
isPow: widget.isPow,
|
||||
speed: widget.nodeListViewModel.nodeSpeedFor(node),
|
||||
onEditComplete: (res) async {
|
||||
if (res != null && res is Node) {
|
||||
widget.nodeListViewModel.nodes
|
||||
.removeWhere((item) => item.id == res.id);
|
||||
widget.nodeListViewModel.nodes.add(res);
|
||||
}
|
||||
},
|
||||
onTap: () async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_current_node_title,
|
||||
alertContent:
|
||||
widget.nodeListViewModel.getAlertContent(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
await widget.nodeListViewModel.setAsCurrent(node);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
return nodeListRow;
|
||||
},
|
||||
);
|
||||
return nodeListRow;
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _presentReconnectAlert(BuildContext context) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).reconnection,
|
||||
alertContent: S.of(context).reconnect_alert_text,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () async {
|
||||
Navigator.of(context).pop();
|
||||
await dashboardViewModel!.reconnect();
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(context).pop());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class _MwebNodePageState extends State<MwebNodePage> {
|
||||
topBar: ModalTopBar(
|
||||
title: S.current.litecoin_mweb_settings,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new)),
|
||||
content: Container(
|
||||
child: NewListSections(controllers: {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:hash_wallet/bitcoin/bitcoin.dart';
|
||||
import "package:hash_wallet/ci_build_overlay.dart";
|
||||
import 'package:hash_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
|
||||
import 'package:hash_wallet/entities/new_ui_entities/list_item/list_item_selector.dart';
|
||||
import "package:hash_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart";
|
||||
import 'package:hash_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/modal_page_wrapper.dart';
|
||||
@@ -8,17 +12,21 @@ import 'package:hash_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:hash_wallet/routes.dart';
|
||||
import 'package:hash_wallet/src/screens/base_page.dart';
|
||||
import 'package:hash_wallet/src/screens/dev/moneroc_cache_debug.dart';
|
||||
import "package:hash_wallet/src/widgets/alert_with_one_action.dart";
|
||||
import 'package:hash_wallet/src/widgets/new_list_row/new_list_section.dart';
|
||||
import 'package:hash_wallet/src/widgets/picker.dart';
|
||||
import 'package:hash_wallet/utils/feature_flag.dart';
|
||||
import 'package:hash_wallet/utils/share_util.dart';
|
||||
import 'package:hash_wallet/utils/show_pop_up.dart';
|
||||
import 'package:hash_wallet/view_model/settings/other_settings_view_model.dart';
|
||||
import 'package:cw_core/root_dir.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_core/db/sqlite.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:flutter_mobx/flutter_mobx.dart";
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
class OtherSettingsPage extends BasePage {
|
||||
OtherSettingsPage(this._otherSettingsViewModel) {
|
||||
@@ -38,13 +46,14 @@ class OtherSettingsPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: S.of(context).other,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
// header: ModalHeader(
|
||||
// iconPath: "assets/new-ui/settings_row_icons/other.svg",
|
||||
// message: "Other settings",
|
||||
// title: S.of(context).other_settings),
|
||||
content: NewListSections(sections: {
|
||||
content: Observer(builder: (_) => NewListSections(sections: {
|
||||
"": [
|
||||
if (_otherSettingsViewModel.displayTransactionPriority)
|
||||
_otherSettingsViewModel.walletType == WalletType.bitcoin
|
||||
@@ -138,6 +147,7 @@ class OtherSettingsPage extends BasePage {
|
||||
},
|
||||
}),
|
||||
),
|
||||
if(_otherSettingsViewModel.hasSignVerify)
|
||||
ListItemRegularRow(
|
||||
keyValue: "security_backup_page_sign_and_verify",
|
||||
label: S.of(context).sign_verify_title,
|
||||
@@ -147,10 +157,12 @@ class OtherSettingsPage extends BasePage {
|
||||
],
|
||||
if (_otherSettingsViewModel.walletType == WalletType.bitcoin)
|
||||
"btc_logging": [
|
||||
if(_otherSettingsViewModel.hasLightning)
|
||||
ListItemRegularRow(
|
||||
keyValue: "export_lightning_logs",
|
||||
label: S.of(context).export_lightning_logs,
|
||||
onTap: () => onExportLNLog(context)),
|
||||
if(_otherSettingsViewModel.hasPayjoin)
|
||||
ListItemRegularRow(
|
||||
keyValue: "export_payjoin_logs",
|
||||
label: S.of(context).export_payjoin_logs,
|
||||
@@ -159,6 +171,24 @@ class OtherSettingsPage extends BasePage {
|
||||
"dev": FeatureFlag.hasDevOptions == false
|
||||
? []
|
||||
: [
|
||||
if (CiBuildOverlay.isCiBuild)
|
||||
ListItemToggle(
|
||||
keyValue: "[dev] show commit/branch overlay",
|
||||
label: "[dev] show commit/branch overlay",
|
||||
value: _otherSettingsViewModel.showCiBuildOverlay,
|
||||
onChanged: (val){
|
||||
if(!val) {
|
||||
showPopUp(
|
||||
context: context,
|
||||
builder: (context) => AlertWithOneAction(
|
||||
alertTitle: "overlay disabled",
|
||||
alertContent:
|
||||
"don't send issue reports without the overlay, pretty please",
|
||||
buttonText: "okay",
|
||||
buttonAction: Navigator.of(context).pop,
|
||||
));
|
||||
}
|
||||
_otherSettingsViewModel.setShowCiBuildOverlay(val);}),
|
||||
if (_otherSettingsViewModel.walletType == WalletType.monero)
|
||||
ListItemRegularRow(
|
||||
keyValue: "[dev] monero background sync",
|
||||
@@ -215,8 +245,15 @@ class OtherSettingsPage extends BasePage {
|
||||
),
|
||||
);
|
||||
}),
|
||||
ListItemRegularRow(
|
||||
keyValue: '[dev] fake corrupt sqlite db',
|
||||
label: '[dev] fake corrupt sqlite db',
|
||||
onTap: () async {
|
||||
final dbDebugMarker = await sqliteDebugMarkerFile();
|
||||
dbDebugMarker.create();
|
||||
}),
|
||||
]
|
||||
}),
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import 'package:hash_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
|
||||
import 'package:hash_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/modal_header.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/modal_page_wrapper.dart';
|
||||
import 'package:hash_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:hash_wallet/routes.dart';
|
||||
import 'package:hash_wallet/src/screens/base_page.dart';
|
||||
import 'package:hash_wallet/src/widgets/new_list_row/new_list_section.dart';
|
||||
import 'package:hash_wallet/view_model/settings/privacy_settings_view_model.dart';
|
||||
@@ -25,6 +23,7 @@ class PrivacyPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: "",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
header: ModalHeader(
|
||||
@@ -73,27 +72,6 @@ class PrivacyPage extends BasePage {
|
||||
_privacySettingsViewModel.setUseLightning(val);
|
||||
}),
|
||||
],
|
||||
"": [
|
||||
if (_privacySettingsViewModel.isBitcoin)
|
||||
ListItemRegularRow(
|
||||
iconPath: "assets/new-ui/settings_row_icons/silent-payments.svg",
|
||||
keyValue: "silent_payments",
|
||||
label: S.of(context).silent_payments,
|
||||
onTap: () =>
|
||||
Navigator.of(context).pushNamed(Routes.silentPaymentsSettings)),
|
||||
if (_privacySettingsViewModel.hasMWEB)
|
||||
ListItemRegularRow(
|
||||
iconPath: "assets/new-ui/settings_row_icons/mweb.svg",
|
||||
keyValue: "mweb",
|
||||
label: "MWEB",
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.mwebSettings)),
|
||||
if (_privacySettingsViewModel.hasCoinControl)
|
||||
ListItemRegularRow(
|
||||
iconPath: "assets/new-ui/settings_row_icons/coin-control.svg",
|
||||
keyValue: "coin_control",
|
||||
label: "Coin Control",
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.unspentCoinsList)),
|
||||
],
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -45,6 +45,7 @@ class SecurityBackupPage extends BasePage {
|
||||
topBar: ModalTopBar(
|
||||
title: "",
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.of(context).seed_alert_back,
|
||||
onLeadingPressed: () => Navigator.of(context).pop()),
|
||||
header: ModalHeader(
|
||||
iconPath: "assets/new-ui/settings_row_icons/security.svg",
|
||||
|
||||
@@ -22,6 +22,7 @@ class SilentPaymentsSettingsPage extends StatelessWidget {
|
||||
ModalTopBar(
|
||||
title: S.current.silent_payments_settings,
|
||||
leadingIcon: Icon(Icons.arrow_back_ios_new),
|
||||
leadingSemanticLabel: S.current.seed_alert_back,
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
@@ -31,14 +32,6 @@ class SilentPaymentsSettingsPage extends StatelessWidget {
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
if (!FeatureFlag.hasNewUi)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.silent_payments_display_card,
|
||||
value: _silentPaymentsSettingsViewModel.silentPaymentsCardDisplay,
|
||||
onValueChange: (_, bool value) {
|
||||
_silentPaymentsSettingsViewModel.setSilentPaymentsCardDisplay(value);
|
||||
},
|
||||
),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.silent_payments_always_scan,
|
||||
value: _silentPaymentsSettingsViewModel.silentPaymentsAlwaysScan,
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:hash_wallet/src/screens/base_page.dart';
|
||||
import 'package:hash_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:hash_wallet/view_model/settings/trocador_providers_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class TrocadorProvidersPage extends BasePage {
|
||||
TrocadorProvidersPage(this.trocadorProvidersViewModel);
|
||||
|
||||
@override
|
||||
String get title => 'Trocador Providers';
|
||||
|
||||
final TrocadorProvidersViewModel trocadorProvidersViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
if (trocadorProvidersViewModel.isLoading) {
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
var providerStates = trocadorProvidersViewModel.providerStates;
|
||||
final providerRatings = trocadorProvidersViewModel.providerRatings;
|
||||
if (providerStates.isEmpty) {
|
||||
return Center(child: Text(S.of(context).no_providers_available));
|
||||
}
|
||||
return ListView.builder(
|
||||
itemCount: providerStates.length,
|
||||
itemBuilder: (_, index) {
|
||||
final providerName = providerStates.keys.elementAt(index);
|
||||
final providerEnabled = providerStates[providerName] ?? true;
|
||||
return SettingsSwitcherCell(
|
||||
title: providerName,
|
||||
value: providerEnabled,
|
||||
leading: Badge(
|
||||
title: 'KYC \nRATING',
|
||||
subTitle: providerRatings[providerName] ?? 'N/A',
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
onValueChange: (BuildContext _, value) =>
|
||||
trocadorProvidersViewModel.toggleProviderState(providerName),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Badge extends StatelessWidget {
|
||||
Badge(
|
||||
{required this.textColor,
|
||||
required this.backgroundColor,
|
||||
required this.title,
|
||||
required this.subTitle});
|
||||
|
||||
final String title;
|
||||
final String subTitle;
|
||||
final Color textColor;
|
||||
final Color backgroundColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.fitHeight,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)), color: backgroundColor),
|
||||
alignment: Alignment.center,
|
||||
child: IntrinsicHeight(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: textColor,
|
||||
fontSize: 7,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
VerticalDivider(
|
||||
color: textColor,
|
||||
thickness: 1,
|
||||
),
|
||||
Text(
|
||||
subTitle,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: textColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
import "package:hash_wallet/core/execution_state.dart";
|
||||
import "package:hash_wallet/generated/i18n.dart";
|
||||
import "package:hash_wallet/new-ui/widgets/new_primary_button.dart";
|
||||
import "package:hash_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
|
||||
import "package:hash_wallet/src/widgets/alert_with_one_action.dart";
|
||||
import "package:hash_wallet/src/widgets/hash_image_widget.dart";
|
||||
import "package:hash_wallet/view_model/wallet_account_list/account_edit_or_create_view_model.dart";
|
||||
import "package:cw_core/generate_name.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
|
||||
class AccountCreationModal extends StatefulWidget {
|
||||
const AccountCreationModal({required this.viewModel, super.key});
|
||||
|
||||
final WalletAccountEditOrCreateViewModel viewModel;
|
||||
|
||||
@override
|
||||
State<AccountCreationModal> createState() => _AccountCreationModalState();
|
||||
}
|
||||
|
||||
class _AccountCreationModalState extends State<AccountCreationModal> {
|
||||
static const int maxAccountNameLength = 25;
|
||||
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
bool _loading = false;
|
||||
|
||||
bool get _canContinue =>
|
||||
_controller.text.trim().isNotEmpty && _controller.text.length <= maxAccountNameLength;
|
||||
|
||||
Future<void> _generateAccountName() async {
|
||||
final generatedName = await generateName();
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() => _controller.text = generatedName.length > maxAccountNameLength
|
||||
? generatedName.substring(0, maxAccountNameLength)
|
||||
: generatedName);
|
||||
}
|
||||
|
||||
Future<void> _save() async {
|
||||
if (_loading || !_canContinue) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _loading = true);
|
||||
widget.viewModel.label = _controller.text;
|
||||
|
||||
late final String errorMessage;
|
||||
try {
|
||||
await widget.viewModel.save();
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
final state = widget.viewModel.state;
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
Navigator.of(context).pop(true);
|
||||
return;
|
||||
}
|
||||
errorMessage = state is FailureState ? state.error : S.of(context).error_while_processing;
|
||||
} catch (error) {
|
||||
errorMessage = error.toString();
|
||||
}
|
||||
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() => _loading = false);
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) => AlertWithOneAction(
|
||||
alertTitle: S.of(dialogContext).error,
|
||||
alertContent: errorMessage,
|
||||
buttonText: S.of(dialogContext).ok,
|
||||
buttonAction: Navigator.of(dialogContext).pop,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => PopScope(
|
||||
canPop: !_loading,
|
||||
child: _buildContent(context),
|
||||
);
|
||||
|
||||
Widget _buildContent(BuildContext context) => Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(30)),
|
||||
),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(bottom: MediaQuery.viewInsetsOf(context).bottom),
|
||||
child: Column(
|
||||
children: [
|
||||
ModalTopBar(
|
||||
title: S.of(context).create_account,
|
||||
trailingIcon: const Icon(Icons.close),
|
||||
trailingSemanticLabel: S.of(context).close,
|
||||
onTrailingPressed: Navigator.of(context).maybePop,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(18, 32, 18, 24),
|
||||
child: Column(
|
||||
spacing: 24,
|
||||
children: [
|
||||
const HashImageWidget(
|
||||
imageUrl: "assets/new-ui/account_education/create_account.svg",
|
||||
width: 125,
|
||||
height: 125,
|
||||
),
|
||||
Text(
|
||||
S.of(context).account_creation_description,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
maxLength: maxAccountNameLength,
|
||||
inputFormatters: [
|
||||
LengthLimitingTextInputFormatter(maxAccountNameLength)
|
||||
],
|
||||
textInputAction: TextInputAction.done,
|
||||
onChanged: (_) => setState(() {}),
|
||||
decoration: InputDecoration(
|
||||
hintText: S.of(context).account_name,
|
||||
counterText: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Semantics(
|
||||
button: true,
|
||||
label: S.of(context).generate_name,
|
||||
onTap: _generateAccountName,
|
||||
child: ExcludeSemantics(
|
||||
child: GestureDetector(
|
||||
onTap: _generateAccountName,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: HashImageWidget(
|
||||
imageUrl: "assets/new-ui/randomize.svg",
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(18, 0, 18, 12),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: NewPrimaryButton(
|
||||
onPressed: _save,
|
||||
text: S.of(context).continue_text,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
isLoading: _loading,
|
||||
disabled: !_canContinue,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import 'package:hash_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hash_wallet/src/widgets/picker.dart';
|
||||
import 'package:hash_wallet/src/widgets/standard_list.dart';
|
||||
|
||||
class SettingsPriorityPickerCell<ItemType> extends StandardListRow {
|
||||
SettingsPriorityPickerCell({
|
||||
required String title,
|
||||
required this.selectedItem,
|
||||
required this.items,
|
||||
this.displayItem,
|
||||
this.images,
|
||||
this.searchHintText,
|
||||
this.isGridView = false,
|
||||
this.matchingCriteria,
|
||||
this.customValue,
|
||||
this.maxValue,
|
||||
this.customItemIndex,
|
||||
this.onItemSelected,
|
||||
}) : super(
|
||||
title: title,
|
||||
isSelected: false,
|
||||
onTap: (BuildContext context) async {
|
||||
var selectedAtIndex = items.indexOf(selectedItem);
|
||||
double sliderValue = customValue ?? 0.0;
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Picker(
|
||||
items: items,
|
||||
displayItem: (ItemType item) => displayItem!(item, sliderValue.round()),
|
||||
selectedAtIndex: selectedAtIndex,
|
||||
customItemIndex: customItemIndex,
|
||||
maxValue: maxValue,
|
||||
headerEnabled: false,
|
||||
closeOnItemSelected: false,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
sliderValue: sliderValue,
|
||||
onSliderChanged: (double newValue) =>
|
||||
setState(() => sliderValue = newValue),
|
||||
onItemSelected: (ItemType priority) {
|
||||
setState(() => selectedAtIndex = items.indexOf(priority));
|
||||
onItemSelected?.call(priority, sliderValue);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
onItemSelected?.call(items[selectedAtIndex], sliderValue);
|
||||
});
|
||||
|
||||
final ItemType selectedItem;
|
||||
final List<ItemType> items;
|
||||
final void Function(ItemType item, double customValue)? onItemSelected;
|
||||
final String Function(ItemType item, int value)? displayItem;
|
||||
final List<Image>? images;
|
||||
final String? searchHintText;
|
||||
final bool isGridView;
|
||||
final bool Function(ItemType, String)? matchingCriteria;
|
||||
double? customValue;
|
||||
double? maxValue;
|
||||
int? customItemIndex;
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) {
|
||||
return Text(
|
||||
displayItem?.call(selectedItem, customValue?.round() ?? 0) ?? selectedItem.toString(),
|
||||
textAlign: TextAlign.right,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class SettingsPickerRaw extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingsVersionCell extends StatelessWidget {
|
||||
SettingsVersionCell({required this.title});
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 24),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class WalletConnectTile extends StatelessWidget {
|
||||
const WalletConnectTile({required this.onTap});
|
||||
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Image.asset(
|
||||
'assets/images/walletconnect_logo.png',
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(
|
||||
S.current.walletConnect,
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
Image.asset(
|
||||
'assets/images/select_arrow.png',
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user