diff --git a/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart b/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart index 1d24a5ad4..bf6dc1fd9 100644 --- a/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart +++ b/lib/cake_pay/src/cards/cake_pay_buy_card_page.dart @@ -627,6 +627,7 @@ class CakePayBuyCardPage extends BasePage { feeFiatAmount: _sendViewModel.pendingTransactionFeeFiatAmountFormatted, outputs: displayingOutputs, footerType: FooterType.slideActionButton, + isSlideActionEnabled: _sendViewModel.isReadyForSend, slideActionButtonText: cakePayBuyCardViewModel.isSimulating ? 'Swipe to simulate' : 'Swipe to send', accessibleNavigationModeSlideActionButtonText: diff --git a/lib/src/screens/exchange_trade/exchange_trade_page.dart b/lib/src/screens/exchange_trade/exchange_trade_page.dart index 67f05c74b..7a1587d84 100644 --- a/lib/src/screens/exchange_trade/exchange_trade_page.dart +++ b/lib/src/screens/exchange_trade/exchange_trade_page.dart @@ -284,6 +284,7 @@ class ExchangeTradeState extends State { return ConfirmSendingBottomSheet( key: ValueKey('exchange_trade_page_confirm_sending_bottom_sheet_key'), footerType: FooterType.slideActionButton, + isSlideActionEnabled: widget.exchangeTradeViewModel.sendViewModel.isReadyForSend, walletType: widget.exchangeTradeViewModel.sendViewModel.walletType, titleText: S.of(bottomSheetContext).confirm_transaction, titleIconPath: diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 3ffd31589..f5b151482 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -567,6 +567,7 @@ class SendPage extends BasePage { titleText: S.of(bottomSheetContext).confirm_transaction, accessibleNavigationModeSlideActionButtonText: S.of(bottomSheetContext).send, footerType: FooterType.slideActionButton, + isSlideActionEnabled: sendViewModel.isReadyForSend, walletType: sendViewModel.walletType, titleIconPath: sendViewModel.selectedCryptoCurrency.iconPath, currency: sendViewModel.selectedCryptoCurrency, diff --git a/lib/src/screens/transaction_details/rbf_details_page.dart b/lib/src/screens/transaction_details/rbf_details_page.dart index 521cf0636..66866bf2a 100644 --- a/lib/src/screens/transaction_details/rbf_details_page.dart +++ b/lib/src/screens/transaction_details/rbf_details_page.dart @@ -190,6 +190,7 @@ class RBFDetailsPage extends BasePage { return ConfirmSendingBottomSheet( key: ValueKey('rbf_confirm_sending_bottom_sheet'), titleText: S.of(bottomSheetContext).confirm_transaction, + isSlideActionEnabled: transactionDetailsViewModel.sendViewModel.isReadyForSend, walletType: transactionDetailsViewModel.sendViewModel.walletType, titleIconPath: transactionDetailsViewModel.sendViewModel.selectedCryptoCurrency.iconPath, diff --git a/lib/src/screens/wallet_connect/services/walletkit_service.dart b/lib/src/screens/wallet_connect/services/walletkit_service.dart index 4c25032a4..9cdbe8eb1 100644 --- a/lib/src/screens/wallet_connect/services/walletkit_service.dart +++ b/lib/src/screens/wallet_connect/services/walletkit_service.dart @@ -202,6 +202,13 @@ abstract class WalletKitServiceBase with Store { ), ); } + } on ReownSignError catch (e) { + if (e.code == 6) { + try { + await deletePairing(topic: session.pairingTopic); + } catch (_) {} + _refreshPairings(); + } } catch (_) {} } } diff --git a/lib/src/screens/wallet_connect/wc_connections_listing_view.dart b/lib/src/screens/wallet_connect/wc_connections_listing_view.dart index 9fcdb61fc..46618a6e6 100644 --- a/lib/src/screens/wallet_connect/wc_connections_listing_view.dart +++ b/lib/src/screens/wallet_connect/wc_connections_listing_view.dart @@ -33,9 +33,13 @@ class WalletConnectConnectionsView extends StatelessWidget { final query = actualLinkList[1]; - final uri = Uri.decodeComponent(query); + final decoded = Uri.decodeComponent(query).trim(); - final uriData = Uri.parse(uri); + final sanitized = decoded.startsWith('@') ? decoded.substring(1) : decoded; + + final uriData = Uri.tryParse(sanitized); + + if (uriData == null || (uriData.scheme.isEmpty)) return; await walletKitService.pairWithUri(uriData); } @@ -88,7 +92,25 @@ class WCPairingsWidget extends BasePage { if (walletConnectURI == null) return _invalidUriToast(context, S.current.nullURIError); log('_onFoundUri: $walletConnectURI'); - final Uri uriData = Uri.parse(walletConnectURI); + // Accept either a raw WC URI or a full URL containing `uri=` parameter + String input = walletConnectURI.trim(); + + if (input.contains('uri=')) { + final parts = input.split('uri='); + if (parts.length > 1) { + input = Uri.decodeComponent(parts.last); + } + } + + // Some scanners may prefix with '@', strip it + if (input.startsWith('@')) { + input = input.substring(1); + } + final Uri? uriData = Uri.tryParse(input); + final bool hasValidScheme = uriData != null && uriData.scheme.isNotEmpty; + if (!hasValidScheme) { + return _invalidUriToast(context, S.current.invalid_input); + } await walletKitService.pairWithUri(uriData); } @@ -121,10 +143,10 @@ class WCPairingsWidget extends BasePage { Text( S.current.connectWalletPrompt, style: Theme.of(context).textTheme.bodyMedium!.copyWith( - fontSize: 16.0, - fontWeight: FontWeight.normal, - color: Theme.of(context).colorScheme.onSurface, - ), + fontSize: 16.0, + fontWeight: FontWeight.normal, + color: Theme.of(context).colorScheme.onSurface, + ), ), SizedBox(height: 16), PrimaryButton( @@ -156,10 +178,10 @@ class WCPairingsWidget extends BasePage { S.current.activeConnectionsPrompt, textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodyMedium!.copyWith( - fontSize: 16.0, - fontWeight: FontWeight.normal, - color: Theme.of(context).colorScheme.onSurface, - ), + fontSize: 16.0, + fontWeight: FontWeight.normal, + color: Theme.of(context).colorScheme.onSurface, + ), ), ), replacement: ListView.builder( diff --git a/lib/src/widgets/bottom_sheet/base_bottom_sheet_widget.dart b/lib/src/widgets/bottom_sheet/base_bottom_sheet_widget.dart index 62fcdd22b..374972826 100644 --- a/lib/src/widgets/bottom_sheet/base_bottom_sheet_widget.dart +++ b/lib/src/widgets/bottom_sheet/base_bottom_sheet_widget.dart @@ -12,6 +12,7 @@ abstract class BaseBottomSheet extends StatelessWidget { required this.footerType, this.slideActionButtonText, this.onSlideActionComplete, + this.isSlideActionEnabled = true, this.singleActionButtonText, this.accessibleNavigationModeSlideActionButtonText, this.onSingleActionButtonPressed, @@ -30,6 +31,7 @@ abstract class BaseBottomSheet extends StatelessWidget { final FooterType footerType; final String? slideActionButtonText; final VoidCallback? onSlideActionComplete; + final bool isSlideActionEnabled; final String? singleActionButtonText; final String? accessibleNavigationModeSlideActionButtonText; final VoidCallback? onSingleActionButtonPressed; @@ -112,6 +114,7 @@ abstract class BaseBottomSheet extends StatelessWidget { buttonText: slideActionButtonText ?? '', onSlideComplete: onSlideActionComplete ?? () {}, accessibleNavigationModeButtonText: accessibleNavigationModeSlideActionButtonText ?? '', + isDisabled: !isSlideActionEnabled, ), ); diff --git a/lib/src/widgets/bottom_sheet/confirm_sending_bottom_sheet_widget.dart b/lib/src/widgets/bottom_sheet/confirm_sending_bottom_sheet_widget.dart index 4bac63a23..1f9b09d52 100644 --- a/lib/src/widgets/bottom_sheet/confirm_sending_bottom_sheet_widget.dart +++ b/lib/src/widgets/bottom_sheet/confirm_sending_bottom_sheet_widget.dart @@ -21,6 +21,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet { String? titleIconPath, String? slideActionButtonText, VoidCallback? onSlideActionComplete, + bool isSlideActionEnabled = true, String? accessibleNavigationModeSlideActionButtonText, required this.currency, this.paymentId, @@ -48,6 +49,7 @@ class ConfirmSendingBottomSheet extends BaseBottomSheet { footerType: footerType, slideActionButtonText: slideActionButtonText ?? 'Swipe to send', onSlideActionComplete: onSlideActionComplete, + isSlideActionEnabled: isSlideActionEnabled, accessibleNavigationModeSlideActionButtonText: accessibleNavigationModeSlideActionButtonText, key: key); diff --git a/lib/src/widgets/standard_slide_button_widget.dart b/lib/src/widgets/standard_slide_button_widget.dart index d531cfb6c..3f6b9ad59 100644 --- a/lib/src/widgets/standard_slide_button_widget.dart +++ b/lib/src/widgets/standard_slide_button_widget.dart @@ -11,6 +11,7 @@ class StandardSlideButton extends StatefulWidget { required this.accessibleNavigationModeButtonText, this.tileBackgroundColor, this.knobColor, + this.isDisabled = false, }) : super(key: key); final VoidCallback onSlideComplete; @@ -19,6 +20,7 @@ class StandardSlideButton extends StatefulWidget { final String accessibleNavigationModeButtonText; final Color? tileBackgroundColor; final Color? knobColor; + final bool isDisabled; @override StandardSlideButtonState createState() => StandardSlideButtonState(); @@ -36,14 +38,16 @@ class StandardSlideButtonState extends State { Widget build(BuildContext context) { final bool accessible = MediaQuery.of(context).accessibleNavigation; - final tileBackgroundColor = context.currentTheme.customColors.backgroundGradientColor; + final tileBackgroundColor = widget.isDisabled + ? context.currentTheme.customColors.backgroundGradientColor.withOpacity(0.5) + : context.currentTheme.customColors.backgroundGradientColor; return accessible ? PrimaryButton( text: widget.accessibleNavigationModeButtonText, color: Theme.of(context).colorScheme.primary, textColor: Theme.of(context).colorScheme.onPrimary, - onPressed: () => widget.onSlideComplete(), + onPressed: widget.isDisabled ? null : () => widget.onSlideComplete(), ) : LayoutBuilder( builder: (context, constraints) { @@ -56,7 +60,10 @@ class StandardSlideButtonState extends State { height: widget.height, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: widget.tileBackgroundColor ?? tileBackgroundColor, + color: (widget.isDisabled + ? widget.tileBackgroundColor?.withOpacity(0.5) + : widget.tileBackgroundColor) ?? + tileBackgroundColor, ), child: Stack( alignment: Alignment.centerLeft, @@ -74,22 +81,26 @@ class StandardSlideButtonState extends State { left: sideMargin + _dragPosition, child: GestureDetector( key: ValueKey('standard_slide_button_widget_slider_key'), - onHorizontalDragUpdate: (details) { - setState(() { - _dragPosition += details.delta.dx; - if (_dragPosition < 0) _dragPosition = 0; - if (_dragPosition > effectiveMaxWidth - sliderWidth) { - _dragPosition = effectiveMaxWidth - sliderWidth; - } - }); - }, - onHorizontalDragEnd: (details) { - if (_dragPosition >= effectiveMaxWidth - sliderWidth - 10) { - widget.onSlideComplete(); - } else { - setState(() => _dragPosition = 0); - } - }, + onHorizontalDragUpdate: widget.isDisabled + ? null + : (details) { + setState(() { + _dragPosition += details.delta.dx; + if (_dragPosition < 0) _dragPosition = 0; + if (_dragPosition > effectiveMaxWidth - sliderWidth) { + _dragPosition = effectiveMaxWidth - sliderWidth; + } + }); + }, + onHorizontalDragEnd: widget.isDisabled + ? null + : (details) { + if (_dragPosition >= effectiveMaxWidth - sliderWidth - 10) { + widget.onSlideComplete(); + } else { + setState(() => _dragPosition = 0); + } + }, child: Container( key: ValueKey('standard_slide_button_widget_slider_container_key'), width: sliderWidth,