From d043b5384a0dc2d79d0549f5cea0f9df44c37a6c Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:00:44 +0200 Subject: [PATCH 1/5] fix: upgrade mobile_scanner to 7.4.0 for arm64 iOS-26 simulator support mobile_scanner 5.2.3 depended on GoogleMLKit, whose frameworks ship no arm64-iphonesimulator slice. On the arm-only iOS 26 simulator (Rosetta removed by Apple), the app could neither build nor run, breaking the handbook-flow CI with "Framework 'Pods_Runner' not found". 7.4.0 drops GoogleMLKit for Apple's native Vision API and builds/runs natively on arm64 simulators. Migrate the two errorBuilder call sites to the new 2-arg signature, and give QrScannerView a compact, textScale-safe default error placeholder so 7.x's taller default no longer overflows send_recipient_page's bounded layout at large text sizes. --- ios/Podfile.lock | 7 ++++++ lib/screens/pay/pay_scan_page.dart | 2 +- lib/widgets/scanner/qr_scanner_view.dart | 28 ++++++++++++++++++++---- pubspec.lock | 6 ++--- pubspec.yaml | 2 +- test/screens/pay/pay_scan_page_test.dart | 1 - 6 files changed, 36 insertions(+), 10 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index bd793d782..78b4b8d8b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -26,6 +26,9 @@ PODS: - local_auth_darwin (0.0.1): - Flutter - FlutterMacOS + - mobile_scanner (7.0.0): + - Flutter + - FlutterMacOS - no_screenshot (0.10.0): - Flutter - open_file_ios (1.0.3): @@ -49,6 +52,7 @@ DEPENDENCIES: - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) + - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) - no_screenshot (from `.symlinks/plugins/no_screenshot/ios`) - open_file_ios (from `.symlinks/plugins/open_file_ios/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) @@ -78,6 +82,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/image_picker_ios/ios" local_auth_darwin: :path: ".symlinks/plugins/local_auth_darwin/darwin" + mobile_scanner: + :path: ".symlinks/plugins/mobile_scanner/darwin" no_screenshot: :path: ".symlinks/plugins/no_screenshot/ios" open_file_ios: @@ -99,6 +105,7 @@ SPEC CHECKSUMS: IdensicMobileSDK: a8ec2cf5c216ae138b00e2ff32e0e31c5e366cec image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb + mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 no_screenshot: 03c8ac6586f9652cd45e3d12d74e5992256403ac open_file_ios: 46184d802ee7959203f6392abcfa0dd49fdb5be0 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 diff --git a/lib/screens/pay/pay_scan_page.dart b/lib/screens/pay/pay_scan_page.dart index 8ca3f74d4..01affc73b 100644 --- a/lib/screens/pay/pay_scan_page.dart +++ b/lib/screens/pay/pay_scan_page.dart @@ -55,7 +55,7 @@ class PayScanView extends StatelessWidget { appBar: AppBar(title: Text(S.of(context).payScanTitle)), body: QrScannerView( onDetect: (raw) => context.read().onCodeDetected(raw), - errorBuilder: (context, error, child) { + errorBuilder: (context, error) { final message = error.errorCode == MobileScannerErrorCode.permissionDenied ? S.of(context).payScanCameraPermissionDenied : S.of(context).payScanCameraUnavailable; diff --git a/lib/widgets/scanner/qr_scanner_view.dart b/lib/widgets/scanner/qr_scanner_view.dart index 6ef8f793f..6d5e9c384 100644 --- a/lib/widgets/scanner/qr_scanner_view.dart +++ b/lib/widgets/scanner/qr_scanner_view.dart @@ -4,8 +4,26 @@ // pay flow (LNURL decode) and the wallet-to-wallet send flow (EVM address // decode); the per-flow decode logic it feeds is unit-tested in the respective // cubit tests. -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:realunit_wallet/styles/colors.dart'; + +/// Compact icon-only error placeholder used when [QrScannerView.errorBuilder] +/// is null. Replaces mobile_scanner 7.x's own (taller, textScale-scaling) +/// default to avoid overflow in bounded layouts like send_recipient_page.dart's +/// Expanded. +Widget _defaultErrorBuilder(BuildContext context, MobileScannerException error) { + return ColoredBox( + color: RealUnitColors.basic.black, + child: Center( + child: Icon( + Icons.error_outline, + size: 48, + color: RealUnitColors.status.red600, + ), + ), + ); +} /// Thin wrapper around [MobileScanner] that surfaces the first raw barcode /// value of each capture via [onDetect]. Keeping the camera/MethodChannel @@ -17,8 +35,10 @@ class QrScannerView extends StatelessWidget { final ValueChanged onDetect; /// Optional error UI builder forwarded to [MobileScanner.errorBuilder]. - /// When null, MobileScanner's own default error handling is used. - final Widget Function(BuildContext, MobileScannerException, Widget?)? errorBuilder; + /// When null, this compact icon-only placeholder is used instead of + /// mobile_scanner 7.x's own (taller, textScale-scaling) default, to avoid + /// overflow in bounded layouts like send_recipient_page.dart's Expanded. + final Widget Function(BuildContext, MobileScannerException)? errorBuilder; const QrScannerView({ super.key, @@ -33,7 +53,7 @@ class QrScannerView extends StatelessWidget { final raw = capture.barcodes.firstOrNull?.rawValue; if (raw != null) onDetect(raw); }, - errorBuilder: errorBuilder, + errorBuilder: errorBuilder ?? _defaultErrorBuilder, ); } } diff --git a/pubspec.lock b/pubspec.lock index 5c204b0f5..759158cf0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -78,7 +78,7 @@ packages: description: path: "." ref: "v0.0.10" - resolved-ref: "cd99ce656410e8df6c6585076d6ee0205a67b34c" + resolved-ref: cd99ce656410e8df6c6585076d6ee0205a67b34c url: "https://github.com/DFXswiss/bitbox_flutter.git" source: git version: "0.0.1" @@ -955,10 +955,10 @@ packages: dependency: "direct main" description: name: mobile_scanner - sha256: d234581c090526676fd8fab4ada92f35c6746e3fb4f05a399665d75a399fb760 + sha256: ce3f059ebd6dbfab7292bba0e893e354b46730636820d3c9ef69005ce2d55bce url: "https://pub.dev" source: hosted - version: "5.2.3" + version: "7.4.0" mocktail: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 67fd1d5ce..c6634fa58 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,7 +65,7 @@ dependencies: http: ^1.1.0 intl: any local_auth: ^3.0.0 - mobile_scanner: ^5.2.3 + mobile_scanner: ^7.4.0 no_screenshot: ^1.1.0 open_file: ^3.5.11 path: ^1.9.0 diff --git a/test/screens/pay/pay_scan_page_test.dart b/test/screens/pay/pay_scan_page_test.dart index 4689fd5b6..b1718d948 100644 --- a/test/screens/pay/pay_scan_page_test.dart +++ b/test/screens/pay/pay_scan_page_test.dart @@ -132,7 +132,6 @@ void main() { final errorWidget = scanner.errorBuilder!( context, MobileScannerException(errorCode: nonPermissionCode), - null, ); await tester.pumpWidget(MaterialApp(home: errorWidget)); From 8cc0174f037f8b76c097491f9a736ab8542df140 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:11:31 +0200 Subject: [PATCH 2/5] fix: stub mobile_scanner 7.x deviceOrientation event channel in golden tests mobile_scanner 7.x subscribes to a new 'dev.steenbakker.mobile_scanner/scanner/deviceOrientation' EventChannel that 5.2.3 did not have. The shared golden-test stub only handled the method + barcode-event channels, so the scanner-rendering golden tests threw MissingPluginException on listen/cancel. Add a no-op stream handler for it, mirroring the existing event-channel stub. --- test/helper/golden_plugin_stubs.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/helper/golden_plugin_stubs.dart b/test/helper/golden_plugin_stubs.dart index d20b47b1c..d9141c945 100644 --- a/test/helper/golden_plugin_stubs.dart +++ b/test/helper/golden_plugin_stubs.dart @@ -68,4 +68,10 @@ void stubMobileScannerChannel() { const EventChannel('dev.steenbakker.mobile_scanner/scanner/event'), MockStreamHandler.inline(onListen: (arguments, sink) {}), ); + // mobile_scanner 7.x additionally subscribes to a device-orientation event + // stream; stub it as a no-op so `listen`/`cancel` don't throw MissingPluginException. + messenger.setMockStreamHandler( + const EventChannel('dev.steenbakker.mobile_scanner/scanner/deviceOrientation'), + MockStreamHandler.inline(onListen: (arguments, sink) {}), + ); } From fec8af765c64e82cf1fea38ee7f2abb853f984b4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:13:13 +0200 Subject: [PATCH 3/5] test(goldens): regenerate baselines on the self-hosted runner --- .../macos/send_recipient_page_empty.png | Bin 18266 -> 19208 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/goldens/screens/send/goldens/macos/send_recipient_page_empty.png b/test/goldens/screens/send/goldens/macos/send_recipient_page_empty.png index 7b64f40a5e4d71f611099f72b372c6dc9acd3692..850d2b9747adf5a192984551f455bf0e1fa5f84c 100644 GIT binary patch literal 19208 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%0D5e99A1htx!TjbAQ?mD9bjQqGTymHACia8| z%;)Y8u~^xi#CrF)A63c_V+Xke3Dig+!UPe^@nif|rcE9v#(U*H*c&qe8wtooy|Azj z33tJh%4Y`NQSuk({IzMzfMkQVHkoZYSOLtd_DG<*jU2udF|<$g3V;& zuq-BRE-y&b2hs+BZTlHP)xi0UYHX8Uz`R!m3L5MK0BSwsMj-i-+(Gf)-kunC(A3z- zsNh!thqAc41+J4RF(HBW-aW9vnY2e6UI*A7hQ&iK7f<#~d&9nP6Pp-%HUVG#X05KF zqpq*0_zr*qBizhT&p=XK$N=3SpCP~kN#jQ1F$Y_}Y>az{di7mg(ixSX8~uS80uTD| zi=)}<@a+{(A%(f#S?=%HH^*w_9?kj7iJQA;{O$FQ^I;cza|uF8VPaVA;Q*LUBeG+^ zSx_=d$H&ag-N>)0q_L*9mX<9$M^h!XctKPP+MNz1!OERcCuF~)64nt!C}H%vUU#OcXd&m`gSH^n3K^MyNQ)Qt}{9?Bo@uutF^W2vafEo!FRc=#TDCtQnMI68Y=U3WeF z{=%PKY9}|B-$Jam!N?c)^L}9lnhsyC{=(Syq&&;FlgNk{|6TaPK7h;a^5qI9=Hqa{ zl7pDQxnDom1{(5DWE|_W!88lWgw39Qrs(=I)7fuQv7c083ko=7Yqy|*p=TL2MRKEW z9150tC4;Y|eLJH6^hu5779#H5r%y>;FYZ5l$Ut(9imF$bcs%0A)924c$VnbPOt2IF zhbo@@J#f`)dh+MbIXeIIOZCq|J9wtBs)Mi3pC7O^cuW_s1#Wad^(t%VjLyH~F&;pf zGr^uS$WHthi9@y26~CU=>hVgA-xOv?+5K+v<=+z0=;DBC1*H01lDf0Rq?=(lR?q*=di z{lZk*NuX2B?b9A`FLepfpY&-+E>lLFSYBmknIErL?tp!#rz7o)FfZ`+VJ-tw;5LhN z*UXMaZ)`}e=YFi71I!==i!3Q z`CM_VJaDyE`C00`-CZT$lHy+GIQznWXl&SoL=Y?FsU-} z*1)8dN*c}ILG%RQcG-=-5;CyBnGD>3HW<-T>UT?Dvyn00&bX~4*X8amqv6XJ!e9S} zS2+aJFnRVm9!CN19v)e~q*d~q3@cey=dOK-9a`V@V`(4&p z(?i*UBiHwGOkA(c?6a!|)F~isHG9);FGmYrWN0ZS=`q<|yFZ-s$;(pb-rF+mU+WigII`9Tnm2v$`Ts0TyZC9}> z8i~ArO1EtF)!J(MagptOR`lhAkvl4^JzivG|@ zK*i2)l$mZ!?;Lv@TyrEZXmV(*QI)uv_kln3DrjM`Hx2Z5h4vK))Xjvx`2oz8p``gV zx%o%hFT%*6d6|0LFl*KGw0;tnx3G5)fL50yo>1bp`$<7S>&(7@&9r~merC8)BFt1N zz#DXNw=L{eIFGWpjlGA6jk(cPpaGz_6d!e=n`?A5EO9r1cze&-&(zHnd<9h74Zi}q z_rc-Dr9A3m%ADdF=#gOm2cVZlgV#aF7%TC8rlu&LUPCd!9jEqg?X!&3^ zBMfop47Uq5<_F~z2K=)!Q>xcdK~~Q)SNvOa-EZfF^HESM$t&A)av>IXgM*egyr0Lv z7jkIaY#s7{iCxx8`Y?GG{p^Tot^)i0HI#*)zjh~oZ(yfc>mvM9%18{x`IX_@kvppj zLu{lVwd(7Tg9@(Dz#^&=r|w`6TRC}82PQ)eW}qjt^sVZ%QQZ~qbU!eDs zkfm(kDc7I}02_Y>Dl$gCqs=YMc)7Cf8VhZEQ|7%`%0!Vv-)o6s>Zx zPrZEVS9acvD)Yc~!ef5y@T%444A{T#d`W*8sG%vrq_~Ma7Y^w`%To<*{rJ?kQpT{S@}eqn->XZM~K)45{tRP;<7@cxW5~36a){SUV)uTh=16{>9yWS2-HM zM73)AH=c^6llEWCj_wsal!|Knb65F2aAKBExeqmn-RCw5Dj z4=eiVA4?4Jl4Y}M7ThDbR^nlAZxYxoa%VoOwf1$^`ls=qcRXmQ!+774UWQ4B6j3QV zf??OTyS5$Z-n_r>91bvZsmtNQ$@@FS9?@v8iQV#tG7Lfk0zd2Y zxTPNo0Oa9w1;m!Q`D>Lu#>tn`#X6QNO0@isa2e>frs#L6tIje1zlFkI6YEGiRmRz- zak;nstXJGwuT-#J$(s9fXxw3#CPD4Z?C@G<0MH|k<k*`xpf literal 18266 zcmeIac|4Tw-#4tUQmOPUq^uPZLS^48A!O|PR%9FdG8k*+8>Nsv+t>|bnQYljC1f4j z*v1&L3J2NlvFtZ zQ&;Y|en!#$)Tzg(i>NapLZfWYNa@hyXAd`ZvmZVA8;|r`%6hetttcy*4nvO7?|Y{A!isEoUi?4V7Pydk>UHziwq2r_Zb*2{wprvS8d{*McM-iqx!@}YaR z)=Uh{SE3}Rae+7+Tp7dc@?Ojqkh5_#X5AXYbP2|75u=mW~MUUb2STl))JO`ZWV&byRC;XsD;BXZTOYN65nOgjHLy+^I%+ zpZ$XDs7qW+Gfj{(?4obu$DZC^Kd-6UZsix>UxV%RKv{?t<8{&RA4Xgi&zwHp0Dqot zc#o-QvMsDxQA7kWHJ-@|AAxQQ@12q(QkI9*YMjxg{Tb4t{*8To&nYV-nq_9l%4!JX zfWSYeBF=%}Mm|11%$F~#mi9V3I+i|;WKsxNGcQ7Nc^A)>2prxDrC`j2c+Rk|6~g5G zoQf)0y^H_wFb)KBSbM)&>d!P=QaU=IrU~??OTznT`@8F9?=EnduI`_5=A3yjTTcCX zLBe>d8WwR()3&%A$0}^Vw~jOqd#)ns*O%v}+|;!S20e zZ*+Aa*ucPG3KbENPHs8aXih8)A+^?zLVbOG+1S~O8X6k3?KEef8?ECPx;_}0M89uwpJ+K4918+NHeX& zEnTnrje&G?cpSSDjKN!gh8)5ivM z7*B5Z&igh(HlMw%uJ-Gr374+K=sde86Jh-%-*9-i)p9pthNjVL>XjfMc&BKUBoS`> z=b`9G-o$B-$tt}`d3iyQDtDmq*?58F*@V-A+&U_yM7bb=$H35E=t)V^KKp-#Ngt0J z*@Dyy3yX-r{e|sSnxbKont$R}$fRN-9TsNh75>mxBnV{D>5Dh)xw5-HRS(Rhk2WRJ%B5DMb!||~(o@4r=;~tnm)&8MIo2l-(&C(rWj+8?l zFviY8BtI~%8Sh5x;C+mqwEYCbrM9olgu_6U%#!So%d7o_4Kw{0m$VE)o|Ukm6^GdC zV|I}eYX%$D4lEra!h#sT$-M%to`C^MFiyq`U&cgPy<2YD?@Qp3bxmCovw&w!TceLA z1Vjv}_<)q3YHCX4Bl6;dCEqvFfBE~Mc$-28p^oDCMcQtt71Lf%Ez)&Uc-;{ zl)RJ1Ba95HwmxWUgA`YKb3V0Lr~Qe)BP^-dJe+pa|0_L4HMKCo>~bo~?s#N0Vb3A> zV1$n{%o^z0In6%RNPT_0HQ1jLj$?n|)vXXFA08!-^zdg@-cGxcSQy`RT%N~>#%$gS zD|5Z12TJ*8F3HD;otHBoPA6T%oWE=Wwv5{4mGd3bc$`>#_|5z*i_r3ivtEWZ8kdqY z)5`j>RD{L+eq!MpLZA_Kzyl$`oVb&giTvDa6GrL@4a)|PHMEU+O|G0*3joChY$)H= zvaIoe@9!+%)S9X~cr8%sfL($+;${x)t2f%9=8Z4+_Pg*>z(jH3?fMYXv}GFzZa>dT z8JZ9dK8}^3tnnAH8A|?^q>GKS3_+Erh=U2ID=bkqNyQSz#z#%7Q&o;1dIJG75|hqP zwK(K>HtyPIkEmEmM>4WUNUhYWmgaO@i>JwuCg4~kAHp-+5<1}Zw}mEB)h`Fkbau7r zq=`txexXzWyLUZ5x}d#ls|BQ%x(e#cNsI z5EqjN9JY8Y=b(S@f10tuPW5vuo~PjiOiu2;cm!cj-3q znPDRp3jMb6X()bV$t|$&rMkvHD?K04X7PSgca`~dB-)PZP9k&w&dNSZf{R9HA&1EDMOp>$$czSm;3fr*k9Aib%||^9-h?i0D75-l{wj%AJTDDeb((k7;;W z7!Ip5ZrWkWM;wxDl(o`OUU&!dwuK~=pL$1a(1I-RP^)=7!a3Y{c&H9 z!B^Q=(uI~@WU1VcHHnT}K#u2LXo7~>mCX834vBWFd5Xv(v-t?j%#r5K_jNPCh}U4f zr0Ed-oG|J~zΤ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 E0*SBAV*mgE From 143f119a18e365b2ceb60d4541f56a01c4c56237 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:16:50 +0200 Subject: [PATCH 4/5] chore: re-trigger CI checks on regenerated golden baseline From 971b46c92b519682fcab85c526c0f656bbb20c5f Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:06:41 +0200 Subject: [PATCH 5/5] test: cover QrScannerView default error placeholder overflow-safety at high textScale --- .../widgets/scanner/qr_scanner_view_test.dart | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 test/widgets/scanner/qr_scanner_view_test.dart diff --git a/test/widgets/scanner/qr_scanner_view_test.dart b/test/widgets/scanner/qr_scanner_view_test.dart new file mode 100644 index 000000000..ac9c0b5bc --- /dev/null +++ b/test/widgets/scanner/qr_scanner_view_test.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:realunit_wallet/widgets/scanner/qr_scanner_view.dart'; + +import '../../helper/helper.dart'; + +void main() { + setUpAll(stubMobileScannerChannel); + + group('$QrScannerView default error placeholder', () { + testWidgets( + 'renders the compact icon placeholder without overflow at high textScale in a tight box', + (tester) async { + await tester.pumpApp( + MediaQuery( + data: const MediaQueryData(size: Size(400, 800)) + .copyWith(textScaler: const TextScaler.linear(3.0)), + child: Center( + child: SizedBox( + width: 60, + height: 60, + child: QrScannerView(onDetect: (_) {}), + ), + ), + ), + ); + + // Let the stubbed permission handshake resolve into the + // permission-denied error state so the default error builder paints. + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + expect(tester.takeException(), isNull); + expect(find.byIcon(Icons.error_outline), findsOneWidget); + final icon = tester.widget(find.byIcon(Icons.error_outline)); + expect(icon.size, 48); + }, + ); + }); +}