fix(shopinbit): show payment QR in a dialog instead of a bottom sheet
What changed, and why it matters
This commit is a routine user-interface polish for the ShopinBit payment flow. It changes how a QR-code payment screen is displayed (from a bottom sheet to a dialog), updates a copy icon to match the app's style, and makes the clipboard copy operation wait for completion before showing a confirmation message. There is no security-relevant change.
No security action needed. Treat as normal UI refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff refactors _onUnownedCoinTap in shopinbit_payment_view.dart to use showDialog with useRootNavigator: true and a new _UnownedCoinPaymentDialog widget instead of showModalBottomSheet. It also adds await to Clipboard.setData and a context.mounted guard before showing the flushbar. The CopyIcon color is switched from accentColorBlue to infoItemIcons and sizes are made responsive. These are UI/UX and code-quality changes, not security fixes.
Changed components
lib/pages/shopinbit/shopinbit_payment_view.dartlib/pages/shopinbit/shopinbit_car_research_payment_view.dartInspect captured patch +143 / −57
diff --git a/lib/pages/shopinbit/shopinbit_car_research_payment_view.dart b/lib/pages/shopinbit/shopinbit_car_research_payment_view.dart
index 1978f3e..3415f32 100644
--- a/lib/pages/shopinbit/shopinbit_car_research_payment_view.dart
+++ b/lib/pages/shopinbit/shopinbit_car_research_payment_view.dart
@@ -626,11 +626,11 @@ class _ShopInBitCarResearchPaymentViewState
),
const Spacer(),
CopyIcon(
- width: 14,
- height: 14,
+ width: isDesktop ? 15 : 10,
+ height: isDesktop ? 15 : 10,
color: Theme.of(
context,
- ).extension<StackColors>()!.accentColorBlue,
+ ).extension<StackColors>()!.infoItemIcons,
),
const SizedBox(width: 4),
Text("Copy", style: STextStyles.link2(context)),
diff --git a/lib/pages/shopinbit/shopinbit_payment_view.dart b/lib/pages/shopinbit/shopinbit_payment_view.dart
index 05fd2f3..d298842 100644
--- a/lib/pages/shopinbit/shopinbit_payment_view.dart
+++ b/lib/pages/shopinbit/shopinbit_payment_view.dart
@@ -24,6 +24,8 @@ import '../../widgets/desktop/desktop_dialog.dart';
import '../../widgets/desktop/desktop_dialog_close_button.dart';
import '../../widgets/desktop/primary_button.dart';
import '../../widgets/desktop/secondary_button.dart';
+import '../../widgets/dialogs/s_dialog.dart';
+import '../../widgets/dialogs/simple_mobile_dialog.dart';
import '../../widgets/icon_widgets/copy_icon.dart';
import '../../widgets/qr.dart';
import '../../widgets/rounded_white_container.dart';
@@ -381,64 +383,21 @@ class _ShopInBitPaymentViewState extends ConsumerState<ShopInBitPaymentView>
}
void _onUnownedCoinTap(int methodIndex) {
- if (_isExpiredOrInvalid || _isTerminal) return;
+ if (!_payNowEnabled) return;
final ticker = _methods[methodIndex].toUpperCase();
final address = _addresses[methodIndex];
+ if (address.isEmpty) return;
- showModalBottomSheet(
+ showDialog<void>(
context: context,
- builder: (ctx) => Padding(
- padding: const EdgeInsets.all(24),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text("$ticker Payment", style: STextStyles.pageTitleH2(context)),
- const SizedBox(height: 16),
- Center(
- child: QR(data: address, size: Util.isDesktop ? 200 : 180),
- ),
- const SizedBox(height: 16),
- GestureDetector(
- onTap: () {
- Clipboard.setData(ClipboardData(text: address));
- showFloatingFlushBar(
- type: FlushBarType.info,
- message: "Copied to clipboard",
- iconAsset: Assets.svg.copy,
- context: context,
- );
- },
- child: RoundedWhiteContainer(
- child: Row(
- children: [
- Expanded(
- child: Text(
- address,
- style: STextStyles.itemSubtitle12(context),
- ),
- ),
- const SizedBox(width: 8),
- CopyIcon(
- width: 14,
- height: 14,
- color: Theme.of(
- context,
- ).extension<StackColors>()!.accentColorBlue,
- ),
- ],
- ),
- ),
- ),
- const SizedBox(height: 16),
- PrimaryButton(
- label: "CHECK FOR PAYMENT",
- onPressed: () {
- Navigator.of(ctx).pop();
- _checkForPayment();
- },
- ),
- ],
- ),
+ useRootNavigator: true,
+ builder: (ctx) => _UnownedCoinPaymentDialog(
+ ticker: ticker,
+ address: address,
+ onCheckForPayment: () {
+ Navigator.of(ctx).pop();
+ _checkForPayment();
+ },
),
);
}
@@ -763,3 +722,130 @@ class _ShopInBitPaymentViewState extends ConsumerState<ShopInBitPaymentView>
);
}
}
+
+class _UnownedCoinPaymentDialog extends StatelessWidget {
+ const _UnownedCoinPaymentDialog({
+ required this.ticker,
+ required this.address,
+ required this.onCheckForPayment,
+ });
+
+ final String ticker;
+ final String address;
+ final VoidCallback onCheckForPayment;
+
+ @override
+ Widget build(BuildContext context) {
+ final isDesktop = Util.isDesktop;
+
+ final content = Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Center(
+ child: QR(data: address, size: isDesktop ? 200 : 180),
+ ),
+ const SizedBox(height: 16),
+ GestureDetector(
+ onTap: () async {
+ await Clipboard.setData(ClipboardData(text: address));
+ if (!context.mounted) return;
+ unawaited(
+ showFloatingFlushBar(
+ type: FlushBarType.info,
+ message: "Copied to clipboard",
+ iconAsset: Assets.svg.copy,
+ context: context,
+ ),
+ );
+ },
+ child: RoundedWhiteContainer(
+ child: Column(
+ children: [
+ Row(
+ children: [
+ Text(
+ "$ticker address",
+ style: isDesktop
+ ? STextStyles.desktopTextExtraExtraSmall(context)
+ : STextStyles.itemSubtitle12(context),
+ ),
+ const Spacer(),
+ CopyIcon(
+ width: isDesktop ? 15 : 10,
+ height: isDesktop ? 15 : 10,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.infoItemIcons,
+ ),
+ const SizedBox(width: 4),
+ Text("Copy", style: STextStyles.link2(context)),
+ ],
+ ),
+ const SizedBox(height: 4),
+ Row(
+ children: [
+ Expanded(
+ child: Text(
+ address,
+ style: isDesktop
+ ? STextStyles.desktopTextExtraExtraSmall(context)
+ : STextStyles.itemSubtitle12(context),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(height: 16),
+ PrimaryButton(label: "CHECK FOR PAYMENT", onPressed: onCheckForPayment),
+ ],
+ );
+
+ if (!isDesktop) {
+ return SimpleMobileDialog(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text("$ticker Payment", style: STextStyles.pageTitleH2(context)),
+ const SizedBox(height: 16),
+ content,
+ ],
+ ),
+ );
+ }
+
+ return SDialog(
+ child: SizedBox(
+ width: 480,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 32),
+ child: Text(
+ "$ticker Payment",
+ style: STextStyles.desktopH3(context),
+ ),
+ ),
+ const DesktopDialogCloseButton(),
+ ],
+ ),
+ Flexible(
+ child: SingleChildScrollView(
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(32, 8, 32, 32),
+ child: content,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.