From d9c01a5d07c2ce44064c2e9f2191ab31e93995ad Mon Sep 17 00:00:00 2001 From: Blazebrain Date: Thu, 17 Apr 2025 07:51:03 +0100 Subject: [PATCH 1/2] fix(desktop-pin-code-issue): persist FocusNode so KeyboardListener works on macOS Previously, every rebuild created a new FocusNode, so KeyboardListener never held focus and missed key events on macOS. This change: - Moves the FocusNode into state and initializes it in initState - Requests focus once after the first frame - Disposes of the FocusNode in dispose - Removes the inline FocusNode creation from build --- lib/src/screens/pin_code/pin_code_widget.dart | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/src/screens/pin_code/pin_code_widget.dart b/lib/src/screens/pin_code/pin_code_widget.dart index f6249576d..410349336 100644 --- a/lib/src/screens/pin_code/pin_code_widget.dart +++ b/lib/src/screens/pin_code/pin_code_widget.dart @@ -38,6 +38,7 @@ class PinCodeState extends State { static const fourPinLength = 4; final _gridViewKey = GlobalKey(); final _key = GlobalKey(); + late final FocusNode _focusNode; int pinLength; String pin; @@ -54,7 +55,17 @@ class PinCodeState extends State { pin = ''; title = S.current.enter_your_pin; _aspectRatio = 0; - WidgetsBinding.instance.addPostFrameCallback(_afterLayout); + _focusNode = FocusNode(); + WidgetsBinding.instance.addPostFrameCallback((_) { + _focusNode.requestFocus(); + _afterLayout(_); + }); + } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); } void setTitle(String title) => setState(() => this.title = title); @@ -120,8 +131,8 @@ class PinCodeState extends State { ); return KeyboardListener( - focusNode: FocusNode(), - autofocus: true, + focusNode: _focusNode, + autofocus: false, onKeyEvent: (keyEvent) { if (keyEvent is KeyDownEvent) { if (keyEvent.logicalKey.keyLabel == "Backspace") { @@ -144,8 +155,7 @@ class PinCodeState extends State { style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500, - color: - Theme.of(context).extension()!.titleColor)), + color: Theme.of(context).extension()!.titleColor)), Spacer(flex: 8), Container( width: 180, @@ -162,7 +172,9 @@ class PinCodeState extends State { shape: BoxShape.circle, color: isFilled ? Theme.of(context).extension()!.titleColor - : Theme.of(context).extension()!.indicatorsColor + : Theme.of(context) + .extension()! + .indicatorsColor .withOpacity(0.25), )); }), @@ -225,7 +237,8 @@ class PinCodeState extends State { child: TextButton( onPressed: () => _pop(), style: TextButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: + Theme.of(context).colorScheme.background, shape: CircleBorder(), ), child: deleteIconImage, @@ -250,7 +263,9 @@ class PinCodeState extends State { style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w600, - color: Theme.of(context).extension()!.titleColor)), + color: Theme.of(context) + .extension()! + .titleColor)), ), ); }), From fe435d4e3bd40ac2fd51e83b9db15f5b807e6fae Mon Sep 17 00:00:00 2001 From: Blazebrain Date: Thu, 17 Apr 2025 08:09:53 +0100 Subject: [PATCH 2/2] fix(buy/sell-flow): add buy/sell toggle to DesktopExchangeCardsSection The desktop exchange screen was only showing the buy flow with no way to switch to sell. This change adds the missing toggle to the DesktopExchangeCardsSection and links it up in the buy/sell page --- lib/src/screens/buy/buy_sell_page.dart | 8 ++++++ .../desktop_exchange_cards_section.dart | 26 ++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/src/screens/buy/buy_sell_page.dart b/lib/src/screens/buy/buy_sell_page.dart index 48334f439..df81c60ce 100644 --- a/lib/src/screens/buy/buy_sell_page.dart +++ b/lib/src/screens/buy/buy_sell_page.dart @@ -490,11 +490,19 @@ class BuySellPage extends BasePage { return DesktopExchangeCardsSection( firstExchangeCard: fiatExchangeCard, secondExchangeCard: cryptoExchangeCard, + onBuyTap: () => null, + onSellTap: () => + buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null, + isBuySellOption: true, ); } else { return DesktopExchangeCardsSection( firstExchangeCard: cryptoExchangeCard, secondExchangeCard: fiatExchangeCard, + onBuyTap: () => + !buySellViewModel.isBuyAction ? buySellViewModel.changeBuySellAction() : null, + onSellTap: () => null, + isBuySellOption: true, ); } }, diff --git a/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart b/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart index 0a97d7bad..5bc07091b 100644 --- a/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart +++ b/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart @@ -1,15 +1,22 @@ +import 'package:cake_wallet/src/screens/exchange/widgets/mobile_exchange_cards_section.dart'; import 'package:flutter/material.dart'; class DesktopExchangeCardsSection extends StatelessWidget { - final Widget firstExchangeCard; - final Widget secondExchangeCard; - const DesktopExchangeCardsSection({ Key? key, required this.firstExchangeCard, required this.secondExchangeCard, + this.isBuySellOption = false, + this.onBuyTap, + this.onSellTap, }) : super(key: key); + final Widget firstExchangeCard; + final Widget secondExchangeCard; + final bool isBuySellOption; + final VoidCallback? onBuyTap; + final VoidCallback? onSellTap; + @override Widget build(BuildContext context) { return FocusTraversalGroup( @@ -18,7 +25,18 @@ class DesktopExchangeCardsSection extends StatelessWidget { children: [ Padding( padding: EdgeInsets.only(top: 55, left: 24, right: 24), - child: firstExchangeCard, + child: Column( + children: [ + if (isBuySellOption) + Column( + children: [ + const SizedBox(height: 16), + BuySellOptionButtons(onBuyTap: onBuyTap, onSellTap: onSellTap), + ], + ), + firstExchangeCard, + ], + ), ), Padding( padding: EdgeInsets.only(top: 29, left: 24, right: 24),