mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-23 19:05:51 +00:00
commit
1226e2bfa8
25 changed files with 2404 additions and 664 deletions
10
assets/svg/network-wired-2.svg
Normal file
10
assets/svg/network-wired-2.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6129_18406)">
|
||||
<path d="M14.9173 0C15.8835 0 16.6673 0.769499 16.6673 1.71875V5.15625C16.6673 6.10514 15.8835 6.875 14.9173 6.875H13.1673V8.02083H22.5007C23.146 8.02083 23.6673 8.53288 23.6673 9.16667C23.6673 9.80046 23.146 10.3125 22.5007 10.3125H19.0007V11.4583H20.7507C21.7168 11.4583 22.5007 12.2282 22.5007 13.1771V16.6146C22.5007 17.5635 21.7168 18.3333 20.7507 18.3333H14.9173C13.9512 18.3333 13.1673 17.5635 13.1673 16.6146V13.1771C13.1673 12.2282 13.9512 11.4583 14.9173 11.4583H16.6673V10.3125H7.33398V11.4583H9.08398C10.0501 11.4583 10.834 12.2282 10.834 13.1771V16.6146C10.834 17.5635 10.0501 18.3333 9.08398 18.3333H3.25065C2.28414 18.3333 1.50065 17.5635 1.50065 16.6146V13.1771C1.50065 12.2282 2.28414 11.4583 3.25065 11.4583H5.00065V10.3125H1.50065C0.856432 10.3125 0.333984 9.80046 0.333984 9.16667C0.333984 8.53288 0.856432 8.02083 1.50065 8.02083H10.834V6.875H9.08398C8.11784 6.875 7.33398 6.10514 7.33398 5.15625V1.71875C7.33398 0.769499 8.11784 0 9.08398 0H14.9173ZM9.66732 2.29167V4.58333H14.334V2.29167H9.66732ZM8.50065 16.0417V13.75H3.83398V16.0417H8.50065ZM15.5007 13.75V16.0417H20.1673V13.75H15.5007Z" fill="#232323"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_6129_18406">
|
||||
<rect width="23.3333" height="18.3333" fill="white" transform="translate(0.333984)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -1,6 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
||||
class ConfirmFullRescanDialog extends StatelessWidget {
|
||||
|
@ -11,40 +16,110 @@ class ConfirmFullRescanDialog extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return true;
|
||||
},
|
||||
child: StackDialog(
|
||||
title: "Rescan blockchain",
|
||||
message:
|
||||
"Warning! It may take a while. If you exit before completion, you will have to redo the process.",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Cancel",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
if (Util.isDesktop) {
|
||||
return DesktopDialog(
|
||||
maxWidth: 576,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
),
|
||||
child: Text(
|
||||
"Rescan blockchain",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 8,
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Warning! It may take a while. If you exit before completion, you will have to redo the process.",
|
||||
style: STextStyles.desktopTextSmall(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 43,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
desktopMed: true,
|
||||
onPressed: Navigator.of(context).pop,
|
||||
label: "Cancel",
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
desktopMed: true,
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
onConfirm.call();
|
||||
},
|
||||
label: "Rescan",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Rescan",
|
||||
style: STextStyles.button(context),
|
||||
);
|
||||
} else {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return true;
|
||||
},
|
||||
child: StackDialog(
|
||||
title: "Rescan blockchain",
|
||||
message:
|
||||
"Warning! It may take a while. If you exit before completion, you will have to redo the process.",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Cancel",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Rescan",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
onConfirm.call();
|
||||
},
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
onConfirm.call();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -285,6 +285,7 @@ class _PrivacyToggleState extends State<PrivacyToggle> {
|
|||
children: [
|
||||
Expanded(
|
||||
child: RawMaterialButton(
|
||||
elevation: 0,
|
||||
fillColor: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
shape: RoundedRectangleBorder(
|
||||
side: !externalCallsEnabled
|
||||
|
|
|
@ -25,6 +25,7 @@ import 'package:stackwallet/utilities/logger.dart';
|
|||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
|
@ -260,11 +261,19 @@ class _TransactionDetailsViewState
|
|||
bottom: 32,
|
||||
)
|
||||
: const EdgeInsets.all(0),
|
||||
child: RoundedWhiteContainer(
|
||||
borderColor: isDesktop
|
||||
? Theme.of(context).extension<StackColors>()!.background
|
||||
: null,
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) {
|
||||
return RoundedWhiteContainer(
|
||||
borderColor: isDesktop
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background
|
||||
: null,
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
primary: isDesktop ? false : null,
|
||||
child: Padding(
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/advanced_settings/advanced_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/advanced_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/appearance_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings/currency_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/language_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/nodes_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/security_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/settings_menu.dart';
|
||||
|
|
|
@ -6,12 +6,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class NetworkInfoButton extends ConsumerStatefulWidget {
|
||||
|
@ -150,14 +154,116 @@ class _NetworkInfoButtonState extends ConsumerState<NetworkInfoButton> {
|
|||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
WalletNetworkSettingsView.routeName,
|
||||
arguments: Tuple3(
|
||||
walletId,
|
||||
_currentSyncStatus,
|
||||
_currentNodeStatus,
|
||||
),
|
||||
);
|
||||
if (Util.isDesktop) {
|
||||
// showDialog<void>(
|
||||
// context: context,
|
||||
// builder: (context) => DesktopDialog(
|
||||
// maxHeight: MediaQuery.of(context).size.height - 64,
|
||||
// maxWidth: 580,
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.only(
|
||||
// left: 32,
|
||||
// ),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Network",
|
||||
// style: STextStyles.desktopH3(context),
|
||||
// ),
|
||||
// const DesktopDialogCloseButton(),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.only(
|
||||
// top: 16,
|
||||
// left: 32,
|
||||
// right: 32,
|
||||
// bottom: 32,
|
||||
// ),
|
||||
// child: WalletNetworkSettingsView(
|
||||
// walletId: walletId,
|
||||
// initialSyncStatus: _currentSyncStatus,
|
||||
// initialNodeStatus: _currentNodeStatus,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => Navigator(
|
||||
initialRoute: WalletNetworkSettingsView.routeName,
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
onGenerateInitialRoutes: (_, __) {
|
||||
return [
|
||||
FadePageRoute(
|
||||
DesktopDialog(
|
||||
maxHeight: MediaQuery.of(context).size.height - 64,
|
||||
maxWidth: 580,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Network",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
DesktopDialogCloseButton(
|
||||
onPressedOverride: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16,
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
),
|
||||
child: WalletNetworkSettingsView(
|
||||
walletId: walletId,
|
||||
initialSyncStatus: _currentSyncStatus,
|
||||
initialNodeStatus: _currentNodeStatus,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const RouteSettings(
|
||||
name: WalletNetworkSettingsView.routeName,
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Navigator.of(context).pushNamed(
|
||||
WalletNetworkSettingsView.routeName,
|
||||
arguments: Tuple3(
|
||||
walletId,
|
||||
_currentSyncStatus,
|
||||
_currentNodeStatus,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -22,6 +21,8 @@ class UnlockWalletKeysDesktop extends ConsumerStatefulWidget {
|
|||
|
||||
final String walletId;
|
||||
|
||||
static const String routeName = "/desktopUnlockWalletKeys";
|
||||
|
||||
@override
|
||||
ConsumerState<UnlockWalletKeysDesktop> createState() =>
|
||||
_UnlockWalletKeysDesktopState();
|
||||
|
@ -59,8 +60,13 @@ class _UnlockWalletKeysDesktopState
|
|||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: const [
|
||||
DesktopDialogCloseButton(),
|
||||
children: [
|
||||
DesktopDialogCloseButton(
|
||||
onPressedOverride: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -175,7 +181,10 @@ class _UnlockWalletKeysDesktopState
|
|||
Expanded(
|
||||
child: SecondaryButton(
|
||||
label: "Cancel",
|
||||
onPressed: Navigator.of(context).pop,
|
||||
onPressed: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -188,29 +197,35 @@ class _UnlockWalletKeysDesktopState
|
|||
onPressed: continueEnabled
|
||||
? () async {
|
||||
// todo: check password
|
||||
Navigator.of(context).pop();
|
||||
// Navigator.of(context).pop();
|
||||
final words = await ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(widget.walletId)
|
||||
.mnemonic;
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Navigator(
|
||||
initialRoute: WalletKeysDesktopPopup.routeName,
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
onGenerateInitialRoutes: (_, __) {
|
||||
return [
|
||||
RouteGenerator.generateRoute(
|
||||
RouteSettings(
|
||||
name: WalletKeysDesktopPopup.routeName,
|
||||
arguments: words,
|
||||
),
|
||||
)
|
||||
];
|
||||
},
|
||||
),
|
||||
|
||||
await Navigator.of(context).pushReplacementNamed(
|
||||
WalletKeysDesktopPopup.routeName,
|
||||
arguments: words,
|
||||
);
|
||||
//
|
||||
// await showDialog<void>(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Navigator(
|
||||
// initialRoute: WalletKeysDesktopPopup.routeName,
|
||||
// onGenerateRoute: RouteGenerator.generateRoute,
|
||||
// onGenerateInitialRoutes: (_, __) {
|
||||
// return [
|
||||
// RouteGenerator.generateRoute(
|
||||
// RouteSettings(
|
||||
// name: WalletKeysDesktopPopup.routeName,
|
||||
// arguments: words,
|
||||
// ),
|
||||
// )
|
||||
// ];
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
: null,
|
||||
),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
@ -20,10 +21,29 @@ class WalletKeysButton extends StatelessWidget {
|
|||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => UnlockWalletKeysDesktop(
|
||||
walletId: walletId,
|
||||
builder: (context) => Navigator(
|
||||
initialRoute: UnlockWalletKeysDesktop.routeName,
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
onGenerateInitialRoutes: (_, __) {
|
||||
return [
|
||||
RouteGenerator.generateRoute(
|
||||
RouteSettings(
|
||||
name: UnlockWalletKeysDesktop.routeName,
|
||||
arguments: walletId,
|
||||
),
|
||||
)
|
||||
];
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// showDialog<void>(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => UnlockWalletKeysDesktop(
|
||||
// walletId: walletId,
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/advanced_settings/stack_privacy_dialog.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/stack_privacy_dialog.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -165,7 +166,7 @@ class _AdvancedSettings extends ConsumerState<AdvancedSettings> {
|
|||
.textDark),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const ShowLogsButton(),
|
||||
ShowLogsButton(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -190,7 +191,7 @@ class StackPrivacyButton extends ConsumerWidget {
|
|||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return const StackPrivacyDialog();
|
||||
return StackPrivacyDialog();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -223,20 +224,19 @@ class ShowLogsButton extends ConsumerWidget {
|
|||
const ShowLogsButton({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
Future<void> viewDebugLogs() async {
|
||||
// await showDialog<dynamic>(
|
||||
// context: context,
|
||||
// useSafeArea: false,
|
||||
// barrierDismissible: true,
|
||||
// builder: (context) {
|
||||
// return const DebugInfoDialog();
|
||||
// },
|
||||
// );
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// Future<void> viewDebugLogs() async {
|
||||
// await showDialog<dynamic>(
|
||||
// context: context,
|
||||
// useSafeArea: false,
|
||||
// barrierDismissible: true,
|
||||
// builder: (context) {
|
||||
// return const DebugInfoDialog();
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
|
||||
return SizedBox(
|
||||
width: 101,
|
||||
height: 37,
|
||||
|
@ -246,7 +246,7 @@ class ShowLogsButton extends ConsumerWidget {
|
|||
.getPrimaryEnabledButtonColor(context),
|
||||
onPressed: () {
|
||||
//
|
||||
viewDebugLogs();
|
||||
// viewDebugLogs();
|
||||
},
|
||||
child: Text(
|
||||
"Show logs",
|
|
@ -0,0 +1,188 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/isar/models/log.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
|
||||
// import '../../../utilities/assets.dart';
|
||||
// import '../../../utilities/util.dart';
|
||||
// import '../../../widgets/icon_widgets/x_icon.dart';
|
||||
// import '../../../widgets/stack_text_field.dart';
|
||||
// import '../../../widgets/textfield_icon_button.dart';
|
||||
|
||||
class DebugInfoDialog extends StatefulWidget {
|
||||
const DebugInfoDialog({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _DebugInfoDialog();
|
||||
}
|
||||
|
||||
class _DebugInfoDialog extends State<DebugInfoDialog> {
|
||||
final _searchController = TextEditingController();
|
||||
final _searchFocusNode = FocusNode();
|
||||
|
||||
final scrollController = ScrollController();
|
||||
|
||||
String _searchTerm = "";
|
||||
|
||||
List<Log> filtered(List<Log> unfiltered, String filter) {
|
||||
if (filter == "") {
|
||||
return unfiltered;
|
||||
}
|
||||
return unfiltered
|
||||
.where(
|
||||
(e) => (e.toString().toLowerCase().contains(filter.toLowerCase())))
|
||||
.toList();
|
||||
}
|
||||
|
||||
BorderRadius? _borderRadius(int index, int listLength) {
|
||||
if (index == 0 && listLength == 1) {
|
||||
return BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
);
|
||||
} else if (index == 0) {
|
||||
return BorderRadius.vertical(
|
||||
bottom: Radius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
);
|
||||
} else if (index == listLength - 1) {
|
||||
return BorderRadius.vertical(
|
||||
top: Radius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// ref.read(debugServiceProvider).updateRecentLogs();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
scrollController.dispose();
|
||||
_searchFocusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DesktopDialog(
|
||||
maxHeight: 800,
|
||||
maxWidth: 600,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Text(
|
||||
"Debug info",
|
||||
style: STextStyles.desktopH3(context),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
// ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(
|
||||
// Constants.size.circularBorderRadius,
|
||||
// ),
|
||||
// child: TextField(
|
||||
// key: const Key("desktopSettingDebugInfo"),
|
||||
// autocorrect: Util.isDesktop ? false : true,
|
||||
// enableSuggestions: Util.isDesktop ? false : true,
|
||||
// controller: _searchController,
|
||||
// focusNode: _searchFocusNode,
|
||||
// // onChanged: (newString) {
|
||||
// // setState(() => _searchTerm = newString);
|
||||
// // },
|
||||
// style: STextStyles.field(context),
|
||||
// decoration: standardInputDecoration(
|
||||
// "Search",
|
||||
// _searchFocusNode,
|
||||
// context,
|
||||
// ).copyWith(
|
||||
// prefixIcon: Padding(
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// horizontal: 10,
|
||||
// vertical: 16,
|
||||
// ),
|
||||
// child: SvgPicture.asset(
|
||||
// Assets.svg.search,
|
||||
// width: 16,
|
||||
// height: 16,
|
||||
// ),
|
||||
// ),
|
||||
// suffixIcon: _searchController.text.isNotEmpty
|
||||
// ? Padding(
|
||||
// padding: const EdgeInsets.only(right: 0),
|
||||
// child: UnconstrainedBox(
|
||||
// child: Row(
|
||||
// children: [
|
||||
// TextFieldIconButton(
|
||||
// child: const XIcon(),
|
||||
// onTap: () async {
|
||||
// setState(() {
|
||||
// _searchController.text = "";
|
||||
// _searchTerm = "";
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// : null,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
// Column(
|
||||
// children: [
|
||||
//
|
||||
// ],
|
||||
// ),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
label: "Clear logs",
|
||||
onPressed: () {},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
label: "Save logs to file",
|
||||
onPressed: () {},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,21 +3,20 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/providers/global/price_provider.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
|
||||
import '../../../hive/db.dart';
|
||||
import '../../../providers/global/prefs_provider.dart';
|
||||
import '../../../providers/global/price_provider.dart';
|
||||
import '../../../services/exchange/exchange_data_loading_service.dart';
|
||||
import '../../../utilities/assets.dart';
|
||||
import '../../../utilities/constants.dart';
|
||||
import '../../../utilities/theme/stack_colors.dart';
|
||||
import '../../../utilities/util.dart';
|
||||
import '../../../widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
class StackPrivacyDialog extends ConsumerStatefulWidget {
|
||||
const StackPrivacyDialog({Key? key}) : super(key: key);
|
|
@ -40,20 +40,6 @@ class _CreateAutoBackup extends State<CreateAutoBackup> {
|
|||
"Every 30 minutes",
|
||||
];
|
||||
|
||||
// List<DropdownMenuItem<String>> get dropdownItems {
|
||||
// List<DropdownMenuItem<String>> menuItems = [
|
||||
// const DropdownMenuItem(
|
||||
// value: "Every 10 minutes",
|
||||
// child: Text("Every 10 minutes"),
|
||||
// ),
|
||||
// const DropdownMenuItem(
|
||||
// value: "Every 20 minutes",
|
||||
// child: Text("Every 20 minutes"),
|
||||
// ),
|
||||
// ];
|
||||
// return menuItems;
|
||||
// }
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
fileLocationController = TextEditingController();
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/providers/global/base_currencies_provider.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
|
||||
class CurrencyDialog extends ConsumerStatefulWidget {
|
||||
const CurrencyDialog({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
ConsumerState<CurrencyDialog> createState() => _CurrencyDialog();
|
||||
}
|
||||
|
||||
class _CurrencyDialog extends ConsumerState<CurrencyDialog> {
|
||||
late String current;
|
||||
late List<String> currenciesWithoutSelected;
|
||||
|
||||
late final TextEditingController searchCurrencyController;
|
||||
|
||||
late final FocusNode searchCurrencyFocusNode;
|
||||
|
||||
void onTap(int index) {
|
||||
if (currenciesWithoutSelected[index] == current || current.isEmpty) {
|
||||
// ignore if already selected currency
|
||||
return;
|
||||
}
|
||||
current = currenciesWithoutSelected[index];
|
||||
currenciesWithoutSelected.remove(current);
|
||||
currenciesWithoutSelected.insert(0, current);
|
||||
ref.read(prefsChangeNotifierProvider).currency = current;
|
||||
}
|
||||
|
||||
BorderRadius? _borderRadius(int index) {
|
||||
if (index == 0 && currenciesWithoutSelected.length == 1) {
|
||||
return BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
);
|
||||
} else if (index == 0) {
|
||||
return BorderRadius.vertical(
|
||||
top: Radius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
);
|
||||
} else if (index == currenciesWithoutSelected.length - 1) {
|
||||
return BorderRadius.vertical(
|
||||
bottom: Radius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String filter = "";
|
||||
|
||||
List<String> _filtered() {
|
||||
final currencyMap = ref.read(baseCurrenciesProvider).map;
|
||||
return currenciesWithoutSelected.where((element) {
|
||||
return element.toLowerCase().contains(filter.toLowerCase()) ||
|
||||
(currencyMap[element]?.toLowerCase().contains(filter.toLowerCase()) ??
|
||||
false);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
searchCurrencyController = TextEditingController();
|
||||
|
||||
searchCurrencyFocusNode = FocusNode();
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchCurrencyController.dispose();
|
||||
|
||||
searchCurrencyFocusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
current = ref
|
||||
.watch(prefsChangeNotifierProvider.select((value) => value.currency));
|
||||
|
||||
currenciesWithoutSelected = ref
|
||||
.watch(baseCurrenciesProvider.select((value) => value.map))
|
||||
.keys
|
||||
.toList();
|
||||
if (current.isNotEmpty) {
|
||||
currenciesWithoutSelected.remove(current);
|
||||
currenciesWithoutSelected.insert(0, current);
|
||||
}
|
||||
currenciesWithoutSelected = _filtered();
|
||||
|
||||
return DesktopDialog(
|
||||
maxHeight: 800,
|
||||
maxWidth: 600,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Text(
|
||||
"Select currency",
|
||||
style: STextStyles.desktopH3(context),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
flex: 24,
|
||||
child: NestedScrollView(
|
||||
floatHeaderSlivers: true,
|
||||
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
|
||||
context),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16, horizontal: 32),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autocorrect: Util.isDesktop ? false : true,
|
||||
enableSuggestions:
|
||||
Util.isDesktop ? false : true,
|
||||
controller: searchCurrencyController,
|
||||
focusNode: searchCurrencyFocusNode,
|
||||
onChanged: (newString) {
|
||||
setState(() => filter = newString);
|
||||
},
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
"Search",
|
||||
searchCurrencyFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 16,
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.search,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
suffixIcon: searchCurrencyController
|
||||
.text.isNotEmpty
|
||||
? Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
searchCurrencyController
|
||||
.text = "";
|
||||
filter = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverOverlapInjector(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
|
||||
context,
|
||||
),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
borderRadius: _borderRadius(index),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
key: Key(
|
||||
"desktopSettingsCurrencySelect_${currenciesWithoutSelected[index]}"),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 32),
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: currenciesWithoutSelected[index] ==
|
||||
current
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.currencyListItemBG
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
child: RawMaterialButton(
|
||||
onPressed: () async {
|
||||
onTap(index);
|
||||
},
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
materialTapTargetSize:
|
||||
MaterialTapTargetSize
|
||||
.shrinkWrap,
|
||||
value: true,
|
||||
groupValue:
|
||||
currenciesWithoutSelected[
|
||||
index] ==
|
||||
current,
|
||||
onChanged: (_) {
|
||||
onTap(index);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
currenciesWithoutSelected[
|
||||
index],
|
||||
key: (currenciesWithoutSelected[
|
||||
index] ==
|
||||
current)
|
||||
? const Key(
|
||||
"desktopSettingsSelectedCurrencyText")
|
||||
: null,
|
||||
style:
|
||||
STextStyles.largeMedium14(
|
||||
context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
ref.watch(baseCurrenciesProvider
|
||||
.select((value) =>
|
||||
value.map))[
|
||||
currenciesWithoutSelected[
|
||||
index]] ??
|
||||
"",
|
||||
key: (currenciesWithoutSelected[
|
||||
index] ==
|
||||
current)
|
||||
? const Key(
|
||||
"desktopSelectedCurrencyTextDescription")
|
||||
: null,
|
||||
style:
|
||||
STextStyles.itemSubtitle(
|
||||
context),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: currenciesWithoutSelected.length,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
label: "Cancel",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
label: "Save Changes",
|
||||
onPressed: () {},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
import 'currency_dialog.dart';
|
||||
|
||||
class CurrencySettings extends ConsumerStatefulWidget {
|
||||
const CurrencySettings({Key? key}) : super(key: key);
|
||||
|
||||
static const String routeName = "/settingsMenuCurrency";
|
||||
|
||||
@override
|
||||
ConsumerState<CurrencySettings> createState() => _CurrencySettings();
|
||||
}
|
||||
|
||||
class _CurrencySettings extends ConsumerState<CurrencySettings> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 30,
|
||||
),
|
||||
child: RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.circleDollarSign,
|
||||
width: 48,
|
||||
height: 48,
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.start,
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Currency",
|
||||
style: STextStyles.desktopTextSmall(context),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
"\n\nProtect your Stack Wallet with a strong password. Stack Wallet does not store "
|
||||
"your password, and is therefore NOT able to restore it. Keep your password safe and secure.",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(
|
||||
10,
|
||||
),
|
||||
child: NewPasswordButton(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NewPasswordButton extends ConsumerWidget {
|
||||
const NewPasswordButton({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
Future<void> chooseCurrency() async {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return CurrencyDialog();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
width: 200,
|
||||
height: 48,
|
||||
child: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
onPressed: () {
|
||||
chooseCurrency();
|
||||
},
|
||||
child: Text(
|
||||
"Change currency",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,349 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/languages_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
|
||||
import '../../../../utilities/assets.dart';
|
||||
import '../../../../utilities/theme/stack_colors.dart';
|
||||
import '../../../../widgets/icon_widgets/x_icon.dart';
|
||||
import '../../../../widgets/rounded_container.dart';
|
||||
import '../../../../widgets/textfield_icon_button.dart';
|
||||
|
||||
class LanguageDialog extends ConsumerStatefulWidget {
|
||||
const LanguageDialog({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
ConsumerState<LanguageDialog> createState() => _LanguageDialog();
|
||||
}
|
||||
|
||||
class _LanguageDialog extends ConsumerState<LanguageDialog> {
|
||||
late final TextEditingController searchLanguageController;
|
||||
|
||||
late final FocusNode searchLanguageFocusNode;
|
||||
|
||||
final languages = Language.values.map((e) => e.description).toList();
|
||||
|
||||
late String current;
|
||||
late List<String> listWithoutSelected;
|
||||
|
||||
void onTap(int index) {
|
||||
if (index == 0 || current.isEmpty) {
|
||||
// ignore if already selected language
|
||||
return;
|
||||
}
|
||||
current = listWithoutSelected[index];
|
||||
listWithoutSelected.remove(current);
|
||||
listWithoutSelected.insert(0, current);
|
||||
ref.read(prefsChangeNotifierProvider).language = current;
|
||||
}
|
||||
|
||||
BorderRadius? _borderRadius(int index) {
|
||||
if (index == 0 && listWithoutSelected.length == 1) {
|
||||
return BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
);
|
||||
} else if (index == 0) {
|
||||
return BorderRadius.vertical(
|
||||
top: Radius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
);
|
||||
} else if (index == listWithoutSelected.length - 1) {
|
||||
return BorderRadius.vertical(
|
||||
bottom: Radius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String filter = "";
|
||||
|
||||
List<String> _filtered() {
|
||||
return listWithoutSelected
|
||||
.where(
|
||||
(element) => element.toLowerCase().contains(filter.toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
searchLanguageController = TextEditingController();
|
||||
|
||||
searchLanguageFocusNode = FocusNode();
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchLanguageController.dispose();
|
||||
|
||||
searchLanguageFocusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
current = ref
|
||||
.watch(prefsChangeNotifierProvider.select((value) => value.language));
|
||||
|
||||
listWithoutSelected = languages;
|
||||
if (current.isNotEmpty) {
|
||||
listWithoutSelected.remove(current);
|
||||
listWithoutSelected.insert(0, current);
|
||||
}
|
||||
listWithoutSelected = _filtered();
|
||||
|
||||
return DesktopDialog(
|
||||
maxHeight: 700,
|
||||
maxWidth: 600,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Text(
|
||||
"Select language",
|
||||
style: STextStyles.desktopH3(context),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
flex: 24,
|
||||
child: NestedScrollView(
|
||||
floatHeaderSlivers: true,
|
||||
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
|
||||
context),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 16, horizontal: 32),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: searchLanguageController,
|
||||
focusNode: searchLanguageFocusNode,
|
||||
style: STextStyles.desktopTextMedium(context)
|
||||
.copyWith(
|
||||
height: 2,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
decoration: standardInputDecoration("Search",
|
||||
searchLanguageFocusNode, context)
|
||||
.copyWith(
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 16,
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.search,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
suffixIcon: searchLanguageController
|
||||
.text.isNotEmpty
|
||||
? Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
searchLanguageController
|
||||
.text = "";
|
||||
filter = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverOverlapInjector(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
|
||||
context,
|
||||
),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
borderRadius: _borderRadius(index),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
key: Key(
|
||||
"desktopSelectLanguage_${listWithoutSelected[index]}"),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 32),
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: index == 0
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.currencyListItemBG
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
child: RawMaterialButton(
|
||||
onPressed: () async {
|
||||
onTap(index);
|
||||
},
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: true,
|
||||
groupValue: index == 0,
|
||||
onChanged: (_) {
|
||||
onTap(index);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
listWithoutSelected[index],
|
||||
key: (index == 0)
|
||||
? const Key(
|
||||
"desktopSettingsSelectedLanguageText")
|
||||
: null,
|
||||
style:
|
||||
STextStyles.largeMedium14(
|
||||
context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
listWithoutSelected[index],
|
||||
key: (index == 0)
|
||||
? const Key(
|
||||
"desktopSettingsSelectedLanguageTextDescription")
|
||||
: null,
|
||||
style:
|
||||
STextStyles.itemSubtitle(
|
||||
context),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: listWithoutSelected.length,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
label: "Cancel",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
label: "Save Changes",
|
||||
onPressed: () {},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/language_dialog.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
@ -87,6 +88,17 @@ class ChangeLanguageButton extends ConsumerWidget {
|
|||
}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
Future<void> chooseLanguage() async {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return LanguageDialog();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
width: 200,
|
||||
height: 48,
|
||||
|
@ -94,7 +106,9 @@ class ChangeLanguageButton extends ConsumerWidget {
|
|||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
chooseLanguage();
|
||||
},
|
||||
child: Text(
|
||||
"Change language",
|
||||
style: STextStyles.button(context),
|
|
@ -85,17 +85,16 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_sear
|
|||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||
import 'package:stackwallet/pages/wallets_view/wallets_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/advanced_settings/advanced_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_settings_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/advanced_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/appearance_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings/currency_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/nodes_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/security_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/settings_menu.dart';
|
||||
|
@ -107,6 +106,9 @@ import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
|
|||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
import 'pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
|
||||
import 'pages_desktop_specific/home/settings_menu/language_settings/language_settings.dart';
|
||||
|
||||
class RouteGenerator {
|
||||
static const bool useMaterialPageRoute = true;
|
||||
|
||||
|
@ -1084,29 +1086,67 @@ class RouteGenerator {
|
|||
|
||||
case WalletKeysDesktopPopup.routeName:
|
||||
if (args is List<String>) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => WalletKeysDesktopPopup(
|
||||
return FadePageRoute(
|
||||
WalletKeysDesktopPopup(
|
||||
words: args,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
// return getRoute(
|
||||
// shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
// builder: (_) => WalletKeysDesktopPopup(
|
||||
// words: args,
|
||||
// ),
|
||||
// settings: RouteSettings(
|
||||
// name: settings.name,
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case UnlockWalletKeysDesktop.routeName:
|
||||
if (args is String) {
|
||||
return FadePageRoute(
|
||||
UnlockWalletKeysDesktop(
|
||||
walletId: args,
|
||||
),
|
||||
RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
// return getRoute(
|
||||
// shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
// builder: (_) => WalletKeysDesktopPopup(
|
||||
// words: args,
|
||||
// ),
|
||||
// settings: RouteSettings(
|
||||
// name: settings.name,
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case QRCodeDesktopPopupContent.routeName:
|
||||
if (args is String) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => QRCodeDesktopPopupContent(
|
||||
return FadePageRoute(
|
||||
QRCodeDesktopPopupContent(
|
||||
value: args,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
// return getRoute(
|
||||
// shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
// builder: (_) => QRCodeDesktopPopupContent(
|
||||
// value: args,
|
||||
// ),
|
||||
// settings: RouteSettings(
|
||||
// name: settings.name,
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
|
@ -1180,3 +1220,37 @@ class RouteGenerator {
|
|||
builder: (_) => errorView);
|
||||
}
|
||||
}
|
||||
|
||||
class FadePageRoute<T> extends PageRoute<T> {
|
||||
FadePageRoute(this.child, RouteSettings settings) : _settings = settings;
|
||||
|
||||
final Widget child;
|
||||
final RouteSettings _settings;
|
||||
|
||||
@override
|
||||
Color? get barrierColor => null;
|
||||
|
||||
@override
|
||||
String? get barrierLabel => null;
|
||||
|
||||
@override
|
||||
Widget buildPage(
|
||||
BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get maintainState => true;
|
||||
|
||||
@override
|
||||
Duration get transitionDuration => const Duration(milliseconds: 100);
|
||||
|
||||
@override
|
||||
RouteSettings get settings => _settings;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ class _SVG {
|
|||
String get downloadFolder => "assets/svg/folder-down.svg";
|
||||
String get lock => "assets/svg/lock-keyhole.svg";
|
||||
String get network => "assets/svg/network-wired.svg";
|
||||
String get networkWired => "assets/svg/network-wired-2.svg";
|
||||
String get addressBook => "assets/svg/address-book.svg";
|
||||
String get addressBook2 => "assets/svg/address-book2.svg";
|
||||
String get arrowRotate3 => "assets/svg/rotate-exclamation.svg";
|
||||
|
|
|
@ -4,13 +4,13 @@ class ConditionalParent extends StatelessWidget {
|
|||
const ConditionalParent({
|
||||
Key? key,
|
||||
required this.condition,
|
||||
required this.child,
|
||||
required this.builder,
|
||||
required this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
final bool condition;
|
||||
final Widget child;
|
||||
final Widget Function(Widget) builder;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -5,11 +5,16 @@ import 'package:stackwallet/providers/ui/color_theme_provider.dart';
|
|||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
||||
class BlueTextButton extends ConsumerStatefulWidget {
|
||||
const BlueTextButton({Key? key, required this.text, this.onTap})
|
||||
: super(key: key);
|
||||
const BlueTextButton({
|
||||
Key? key,
|
||||
required this.text,
|
||||
this.onTap,
|
||||
this.enabled = true,
|
||||
}) : super(key: key);
|
||||
|
||||
final String text;
|
||||
final VoidCallback? onTap;
|
||||
final bool enabled;
|
||||
|
||||
@override
|
||||
ConsumerState<BlueTextButton> createState() => _BlueTextButtonState();
|
||||
|
@ -17,38 +22,42 @@ class BlueTextButton extends ConsumerStatefulWidget {
|
|||
|
||||
class _BlueTextButtonState extends ConsumerState<BlueTextButton>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController controller;
|
||||
late Animation<dynamic> animation;
|
||||
AnimationController? controller;
|
||||
Animation<dynamic>? animation;
|
||||
late Color color;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
color = ref.read(colorThemeProvider.state).state.buttonTextBorderless;
|
||||
controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
);
|
||||
animation = ColorTween(
|
||||
begin: ref.read(colorThemeProvider.state).state.buttonTextBorderless,
|
||||
end: ref
|
||||
.read(colorThemeProvider.state)
|
||||
.state
|
||||
.buttonTextBorderless
|
||||
.withOpacity(0.4),
|
||||
).animate(controller);
|
||||
if (widget.enabled) {
|
||||
color = ref.read(colorThemeProvider.state).state.buttonTextBorderless;
|
||||
controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
);
|
||||
animation = ColorTween(
|
||||
begin: ref.read(colorThemeProvider.state).state.buttonTextBorderless,
|
||||
end: ref
|
||||
.read(colorThemeProvider.state)
|
||||
.state
|
||||
.buttonTextBorderless
|
||||
.withOpacity(0.4),
|
||||
).animate(controller!);
|
||||
|
||||
animation.addListener(() {
|
||||
setState(() {
|
||||
color = animation.value as Color;
|
||||
animation!.addListener(() {
|
||||
setState(() {
|
||||
color = animation!.value as Color;
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
color = ref.read(colorThemeProvider.state).state.textSubtitle1;
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
controller?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -59,11 +68,13 @@ class _BlueTextButtonState extends ConsumerState<BlueTextButton>
|
|||
text: TextSpan(
|
||||
text: widget.text,
|
||||
style: STextStyles.link2(context).copyWith(color: color),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
widget.onTap?.call();
|
||||
controller.forward().then((value) => controller.reverse());
|
||||
},
|
||||
recognizer: widget.enabled
|
||||
? (TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
widget.onTap?.call();
|
||||
controller?.forward().then((value) => controller?.reverse());
|
||||
})
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,31 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
import 'package:stackwallet/utilities/enums/sync_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/test_epic_box_connection.dart';
|
||||
import 'package:stackwallet/utilities/test_monero_node_connection.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/expandable.dart';
|
||||
import 'package:stackwallet/widgets/node_options_sheet.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class NodeCard extends ConsumerStatefulWidget {
|
||||
const NodeCard({
|
||||
|
@ -30,6 +46,125 @@ class NodeCard extends ConsumerStatefulWidget {
|
|||
class _NodeCardState extends ConsumerState<NodeCard> {
|
||||
String _status = "Disconnected";
|
||||
late final String nodeId;
|
||||
bool _advancedIsExpanded = true;
|
||||
|
||||
Future<void> _notifyWalletsOfUpdatedNode(WidgetRef ref) async {
|
||||
final managers = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.managers
|
||||
.where((e) => e.coin == widget.coin);
|
||||
final prefs = ref.read(prefsChangeNotifierProvider);
|
||||
|
||||
switch (prefs.syncType) {
|
||||
case SyncingType.currentWalletOnly:
|
||||
for (final manager in managers) {
|
||||
if (manager.isActiveWallet) {
|
||||
manager.updateNode(true);
|
||||
} else {
|
||||
manager.updateNode(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyncingType.selectedWalletsAtStartup:
|
||||
final List<String> walletIdsToSync = prefs.walletIdsSyncOnStartup;
|
||||
for (final manager in managers) {
|
||||
if (walletIdsToSync.contains(manager.walletId)) {
|
||||
manager.updateNode(true);
|
||||
} else {
|
||||
manager.updateNode(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyncingType.allWalletsOnStartup:
|
||||
for (final manager in managers) {
|
||||
manager.updateNode(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _testConnection(
|
||||
NodeModel node,
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
) async {
|
||||
bool testPassed = false;
|
||||
|
||||
switch (widget.coin) {
|
||||
case Coin.epicCash:
|
||||
try {
|
||||
final String uriString = "${node.host}:${node.port}/v1/version";
|
||||
|
||||
testPassed = await testEpicBoxNodeConnection(Uri.parse(uriString));
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Warning);
|
||||
}
|
||||
break;
|
||||
|
||||
case Coin.monero:
|
||||
case Coin.wownero:
|
||||
try {
|
||||
final uri = Uri.parse(node.host);
|
||||
if (uri.scheme.startsWith("http")) {
|
||||
final String path = uri.path.isEmpty ? "/json_rpc" : uri.path;
|
||||
|
||||
String uriString = "${uri.scheme}://${uri.host}:${node.port}$path";
|
||||
|
||||
testPassed = await testMoneroNodeConnection(Uri.parse(uriString));
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Warning);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Coin.bitcoin:
|
||||
case Coin.litecoin:
|
||||
case Coin.dogecoin:
|
||||
case Coin.firo:
|
||||
case Coin.bitcoinTestNet:
|
||||
case Coin.firoTestNet:
|
||||
case Coin.dogecoinTestNet:
|
||||
case Coin.bitcoincash:
|
||||
case Coin.litecoinTestNet:
|
||||
case Coin.namecoin:
|
||||
case Coin.bitcoincashTestnet:
|
||||
final client = ElectrumX(
|
||||
host: node.host,
|
||||
port: node.port,
|
||||
useSSL: node.useSSL,
|
||||
failovers: [],
|
||||
prefs: ref.read(prefsChangeNotifierProvider),
|
||||
);
|
||||
|
||||
try {
|
||||
testPassed = await client.ping();
|
||||
} catch (_) {
|
||||
testPassed = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (testPassed) {
|
||||
// showFloatingFlushBar(
|
||||
// type: FlushBarType.success,
|
||||
// message: "Server ping success",
|
||||
// context: context,
|
||||
// );
|
||||
} else {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
iconAsset: Assets.svg.circleAlert,
|
||||
message: "Could not connect to node",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return testPassed;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -50,91 +185,176 @@ class _NodeCardState extends ConsumerState<NodeCard> {
|
|||
_status = "Disconnected";
|
||||
}
|
||||
|
||||
final isDesktop = Util.isDesktop;
|
||||
|
||||
return RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: RawMaterialButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
showModalBottomSheet<dynamic>(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
builder: (_) => NodeOptionsSheet(
|
||||
nodeId: nodeId,
|
||||
coin: widget.coin,
|
||||
popBackToRoute: widget.popBackToRoute,
|
||||
borderColor: isDesktop
|
||||
? Theme.of(context).extension<StackColors>()!.background
|
||||
: null,
|
||||
child: ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) {
|
||||
return RawMaterialButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
showModalBottomSheet<void>(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
builder: (_) => NodeOptionsSheet(
|
||||
nodeId: nodeId,
|
||||
coin: widget.coin,
|
||||
popBackToRoute: widget.popBackToRoute,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(
|
||||
color: _node.name == DefaultNodes.defaultName
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemIcons
|
||||
.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) {
|
||||
return Expandable(
|
||||
onExpandChanged: (state) {
|
||||
setState(() {
|
||||
_advancedIsExpanded = state == ExpandableState.expanded;
|
||||
});
|
||||
},
|
||||
header: child,
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 24,
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.node,
|
||||
height: 11,
|
||||
width: 14,
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 66,
|
||||
),
|
||||
BlueTextButton(
|
||||
text: "Connect",
|
||||
enabled: _status == "Disconnected",
|
||||
onTap: () async {
|
||||
final canConnect =
|
||||
await _testConnection(_node, context, ref);
|
||||
if (!canConnect) {
|
||||
return;
|
||||
}
|
||||
|
||||
await ref
|
||||
.read(nodeServiceChangeNotifierProvider)
|
||||
.setPrimaryNodeFor(
|
||||
coin: widget.coin,
|
||||
node: _node,
|
||||
shouldNotifyListeners: true,
|
||||
);
|
||||
|
||||
await _notifyWalletsOfUpdatedNode(ref);
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
width: 48,
|
||||
),
|
||||
BlueTextButton(
|
||||
text: "Details",
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
NodeDetailsView.routeName,
|
||||
arguments: Tuple3(
|
||||
widget.coin,
|
||||
widget.nodeId,
|
||||
widget.popBackToRoute,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(isDesktop ? 16 : 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: isDesktop ? 40 : 24,
|
||||
height: isDesktop ? 40 : 24,
|
||||
decoration: BoxDecoration(
|
||||
color: _node.name == DefaultNodes.defaultName
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark
|
||||
.buttonBackSecondary
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemIcons,
|
||||
.infoItemIcons
|
||||
.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.node,
|
||||
height: isDesktop ? 18 : 11,
|
||||
width: isDesktop ? 20 : 14,
|
||||
color: _node.name == DefaultNodes.defaultName
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemIcons,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_node.name,
|
||||
style: STextStyles.titleBold12(context),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_node.name,
|
||||
style: STextStyles.titleBold12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
_status,
|
||||
style: STextStyles.label(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
if (!isDesktop)
|
||||
SvgPicture.asset(
|
||||
Assets.svg.network,
|
||||
color: _status == "Connected"
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorGreen
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
_status,
|
||||
style: STextStyles.label(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
SvgPicture.asset(
|
||||
Assets.svg.network,
|
||||
color: _status == "Connected"
|
||||
? Theme.of(context)
|
||||
if (isDesktop)
|
||||
SvgPicture.asset(
|
||||
_advancedIsExpanded
|
||||
? Assets.svg.chevronDown
|
||||
: Assets.svg.chevronUp,
|
||||
width: 12,
|
||||
height: 6,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorGreen
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
.textSubtitle1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -237,6 +237,7 @@ flutter:
|
|||
- assets/svg/rotate-exclamation.svg
|
||||
- assets/svg/folder-down.svg
|
||||
- assets/svg/network-wired.svg
|
||||
- assets/svg/network-wired-2.svg
|
||||
- assets/svg/address-book.svg
|
||||
- assets/svg/address-book2.svg
|
||||
- assets/svg/arrow-right.svg
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/node_card.dart';
|
||||
import 'package:stackwallet/widgets/node_options_sheet.dart';
|
||||
|
||||
|
@ -190,13 +191,22 @@ void main() {
|
|||
await tester.tap(find.byType(NodeCard));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text("Connect"), findsOneWidget);
|
||||
expect(find.text("Details"), findsOneWidget);
|
||||
expect(find.byType(NodeOptionsSheet), findsOneWidget);
|
||||
expect(find.byType(Text), findsNWidgets(7));
|
||||
if (Util.isDesktop) {
|
||||
expect(find.text("Connect"), findsNothing);
|
||||
expect(find.text("Details"), findsNothing);
|
||||
|
||||
verify(nodeService.getPrimaryNodeFor(coin: Coin.bitcoin)).called(1);
|
||||
verify(nodeService.getNodeById(id: "node id")).called(1);
|
||||
} else {
|
||||
expect(find.text("Connect"), findsOneWidget);
|
||||
expect(find.text("Details"), findsOneWidget);
|
||||
expect(find.byType(NodeOptionsSheet), findsOneWidget);
|
||||
expect(find.byType(Text), findsNWidgets(7));
|
||||
|
||||
verify(nodeService.getPrimaryNodeFor(coin: Coin.bitcoin)).called(2);
|
||||
verify(nodeService.getNodeById(id: "node id")).called(2);
|
||||
}
|
||||
|
||||
verify(nodeService.getPrimaryNodeFor(coin: Coin.bitcoin)).called(2);
|
||||
verify(nodeService.getNodeById(id: "node id")).called(2);
|
||||
verify(nodeService.addListener(any)).called(1);
|
||||
|
||||
verifyNoMoreInteractions(nodeService);
|
||||
|
|
Loading…
Reference in a new issue