From a55650bc40999d1bda3c866f2266283dd3a4a097 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Tue, 14 Apr 2026 06:53:51 +0200 Subject: [PATCH] fix: skip QR scanner on devices without cameras --- android/app/src/main/AndroidManifest.xml | 3 ++ .../kotlin/com/edde746/plezy/MainActivity.kt | 3 ++ .../companion_remote/pairing_screen.dart | 36 +++++++++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a26ccc5a..8fefa56f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -23,6 +23,9 @@ + + + diff --git a/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt b/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt index 1ba23782..d2a92aad 100644 --- a/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt +++ b/android/app/src/main/kotlin/com/edde746/plezy/MainActivity.kt @@ -253,6 +253,9 @@ class MainActivity : FlutterActivity() { MethodChannel(flutterEngine.dartExecutor.binaryMessenger, THEME_CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "getRenderer" -> result.success(if (usingSkia) "Skia" else "Impeller") + "hasCamera" -> result.success( + packageManager.hasSystemFeature(android.content.pm.PackageManager.FEATURE_CAMERA_ANY) + ) "setSplashTheme" -> { val mode = call.argument("mode") diff --git a/lib/screens/companion_remote/pairing_screen.dart b/lib/screens/companion_remote/pairing_screen.dart index 2110980b..23855234 100644 --- a/lib/screens/companion_remote/pairing_screen.dart +++ b/lib/screens/companion_remote/pairing_screen.dart @@ -28,12 +28,34 @@ class _PairingScreenState extends State { // QR scanner state MobileScannerController? _scannerController; String? _lastScannedCode; + bool _hasCamera = false; - bool get _isMobile => Platform.isAndroid || Platform.isIOS; + bool get _canScan => (Platform.isAndroid || Platform.isIOS) && _hasCamera; - // Tab indices: mobile gets Scan (0) + Manual (1), desktop gets Manual (0) - int get _scanTabIndex => _isMobile ? 0 : -1; - int get _manualTabIndex => _isMobile ? 1 : 0; + // Tab indices: scannable gets Scan (0) + Manual (1), otherwise Manual (0) + int get _scanTabIndex => _canScan ? 0 : -1; + int get _manualTabIndex => _canScan ? 1 : 0; + + @override + void initState() { + super.initState(); + _checkCamera(); + } + + Future _checkCamera() async { + if (Platform.isIOS) { + setState(() => _hasCamera = true); + return; + } + if (!Platform.isAndroid) return; + try { + const channel = MethodChannel('com.plezy/theme'); + final result = await channel.invokeMethod('hasCamera'); + if (mounted) setState(() => _hasCamera = result ?? false); + } catch (e) { + debugPrint('Camera check failed: $e'); + } + } @override void dispose() { @@ -158,7 +180,7 @@ class _PairingScreenState extends State { ), body: Column( children: [ - if (_isMobile) + if (_canScan) SegmentedButton( segments: [ ButtonSegment( @@ -186,7 +208,7 @@ class _PairingScreenState extends State { } Widget _buildTabContent() { - if (_selectedTab == _scanTabIndex && _isMobile) return _buildScanTab(); + if (_selectedTab == _scanTabIndex && _canScan) return _buildScanTab(); return _buildManualEntryTab(); } @@ -416,7 +438,7 @@ class _PairingScreenState extends State { Text(t.companionRemote.pairing.tips, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), _buildTipCard(context, Icons.computer, t.companionRemote.pairing.tipDesktop), - if (_isMobile) ...[ + if (_canScan) ...[ const SizedBox(height: 8), _buildTipCard(context, Icons.qr_code, t.companionRemote.pairing.tipScan), ],