From c9220c5c11518da877b5736f79dceb98f9744658 Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 30 Oct 2022 11:13:32 -0600 Subject: [PATCH] desktop wallet renaming --- .../wallet_view/desktop_wallet_view.dart | 156 ++++++++++++------ lib/widgets/desktop/desktop_app_bar.dart | 10 +- lib/widgets/hover_text_field.dart | 123 ++++++++++++++ 3 files changed, 236 insertions(+), 53 deletions(-) create mode 100644 lib/widgets/hover_text_field.dart diff --git a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart index 0e5aa925f..5dadd511c 100644 --- a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart +++ b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart @@ -43,6 +43,7 @@ import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; +import 'package:stackwallet/widgets/hover_text_field.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -66,6 +67,7 @@ class DesktopWalletView extends ConsumerStatefulWidget { } class _DesktopWalletViewState extends ConsumerState { + late final TextEditingController controller; late final String walletId; late final EventBus eventBus; @@ -179,10 +181,13 @@ class _DesktopWalletViewState extends ConsumerState { @override void initState() { + controller = TextEditingController(); walletId = widget.walletId; final managerProvider = ref.read(walletsChangeNotifierProvider).getManagerProvider(walletId); + controller.text = ref.read(managerProvider).walletName; + eventBus = widget.eventBus != null ? widget.eventBus! : GlobalEventBus.instance; @@ -211,61 +216,110 @@ class _DesktopWalletViewState extends ConsumerState { return DesktopScaffold( appBar: DesktopAppBar( background: Theme.of(context).extension()!.popupBG, - leading: Row( - children: [ - const SizedBox( - width: 32, - ), - AppBarIconButton( - size: 32, - color: Theme.of(context) - .extension()! - .textFieldDefaultBG, - shadows: const [], - icon: SvgPicture.asset( - Assets.svg.arrowLeft, - width: 18, - height: 18, + leading: Expanded( + child: Row( + children: [ + const SizedBox( + width: 32, + ), + AppBarIconButton( + size: 32, color: Theme.of(context) .extension()! - .topNavIconPrimary, + .textFieldDefaultBG, + shadows: const [], + icon: SvgPicture.asset( + Assets.svg.arrowLeft, + width: 18, + height: 18, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, + ), + onPressed: onBackPressed, ), - onPressed: onBackPressed, - ), - const SizedBox( - width: 15, - ), - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 32, - height: 32, - ), - const SizedBox( - width: 12, - ), - Text( - manager.walletName, - style: STextStyles.desktopH3(context), - ), - ], - ), - trailing: Row( - children: [ - NetworkInfoButton( - walletId: walletId, - eventBus: eventBus, - ), - const SizedBox( - width: 32, - ), - WalletKeysButton( - walletId: walletId, - ), - const SizedBox( - width: 32, - ), - ], + const SizedBox( + width: 15, + ), + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 32, + height: 32, + ), + const SizedBox( + width: 12, + ), + ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 48, + ), + child: IntrinsicWidth( + child: HoverTextField( + controller: controller, + style: STextStyles.desktopH3(context), + readOnly: true, + onDone: () async { + final currentWalletName = + ref.read(managerProvider).walletName; + final newName = controller.text; + if (newName != currentWalletName) { + final success = await ref + .read(walletsServiceChangeNotifierProvider) + .renameWallet( + from: currentWalletName, + to: newName, + shouldNotifyListeners: true, + ); + if (success) { + ref + .read(walletsChangeNotifierProvider) + .getManager(walletId) + .walletName = newName; + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "Wallet renamed", + context: context, + ), + ); + } else { + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: + "Wallet named \"$newName\" already exists", + context: context, + ), + ); + controller.text = currentWalletName; + } + } + }, + ), + ), + ), + const Spacer(), + Row( + children: [ + NetworkInfoButton( + walletId: walletId, + eventBus: eventBus, + ), + const SizedBox( + width: 32, + ), + WalletKeysButton( + walletId: walletId, + ), + const SizedBox( + width: 32, + ), + ], + ), + ], + ), ), + useSpacers: false, isCompactHeight: true, ), body: Padding( diff --git a/lib/widgets/desktop/desktop_app_bar.dart b/lib/widgets/desktop/desktop_app_bar.dart index 1c825382c..bbad0385a 100644 --- a/lib/widgets/desktop/desktop_app_bar.dart +++ b/lib/widgets/desktop/desktop_app_bar.dart @@ -11,6 +11,7 @@ class DesktopAppBar extends StatefulWidget { this.trailing, this.background = Colors.transparent, required this.isCompactHeight, + this.useSpacers = true, }) : super(key: key); final Widget? leading; @@ -18,6 +19,7 @@ class DesktopAppBar extends StatefulWidget { final Widget? trailing; final Color background; final bool isCompactHeight; + final bool useSpacers; @override State createState() => _DesktopAppBarState(); @@ -33,11 +35,15 @@ class _DesktopAppBarState extends State { items.add(widget.leading!); } - items.add(const Spacer()); + if (widget.useSpacers) { + items.add(const Spacer()); + } if (widget.center != null) { items.add(widget.center!); - items.add(const Spacer()); + if (widget.useSpacers) { + items.add(const Spacer()); + } } if (widget.trailing != null) { diff --git a/lib/widgets/hover_text_field.dart b/lib/widgets/hover_text_field.dart new file mode 100644 index 000000000..475d6c2ec --- /dev/null +++ b/lib/widgets/hover_text_field.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; + +class HoverTextField extends StatefulWidget { + const HoverTextField({ + Key? key, + this.controller, + this.focusNode, + this.readOnly = false, + this.enabled, + this.onTap, + this.onChanged, + this.onEditingComplete, + this.style, + this.onDone, + }) : super(key: key); + + final TextEditingController? controller; + final FocusNode? focusNode; + final bool readOnly; + final bool? enabled; + final GestureTapCallback? onTap; + final ValueChanged? onChanged; + final VoidCallback? onEditingComplete; + final TextStyle? style; + final VoidCallback? onDone; + + @override + State createState() => _HoverTextFieldState(); +} + +class _HoverTextFieldState extends State { + late final TextEditingController? controller; + late final FocusNode? focusNode; + late bool readOnly; + late bool? enabled; + late final GestureTapCallback? onTap; + late final ValueChanged? onChanged; + late final VoidCallback? onEditingComplete; + late final TextStyle? style; + late final VoidCallback? onDone; + + final InputBorder inputBorder = OutlineInputBorder( + borderSide: const BorderSide( + width: 0, + color: Colors.transparent, + ), + borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), + ); + + @override + void initState() { + controller = widget.controller; + focusNode = widget.focusNode ?? FocusNode(); + readOnly = widget.readOnly; + enabled = widget.enabled; + onChanged = widget.onChanged; + style = widget.style; + onTap = widget.onTap; + onEditingComplete = widget.onEditingComplete; + onDone = widget.onDone; + + focusNode!.addListener(() { + if (!focusNode!.hasPrimaryFocus && !readOnly) { + setState(() { + readOnly = true; + }); + onDone?.call(); + } + }); + super.initState(); + } + + @override + void dispose() { + controller?.dispose(); + focusNode?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return TextField( + autocorrect: !Util.isDesktop, + enableSuggestions: !Util.isDesktop, + controller: controller, + focusNode: focusNode, + readOnly: readOnly, + enabled: enabled, + onTap: () { + setState(() { + readOnly = false; + }); + onTap?.call(); + }, + onChanged: onChanged, + onEditingComplete: () { + setState(() { + readOnly = true; + }); + onEditingComplete?.call(); + onDone?.call(); + }, + style: style, + decoration: InputDecoration( + contentPadding: const EdgeInsets.symmetric( + vertical: 4, + horizontal: 12, + ), + border: inputBorder, + focusedBorder: inputBorder, + disabledBorder: inputBorder, + enabledBorder: inputBorder, + errorBorder: inputBorder, + fillColor: readOnly + ? Colors.transparent + : Theme.of(context).extension()!.textFieldDefaultBG, + ), + ); + } +}