payfrit-app/lib/services/beacon_permissions.dart
John Mizerek 1d08b18568 Fix beacon scanning and Bluetooth permissions
- Remove neverForLocation flag from BLUETOOTH_SCAN (was blocking beacon detection)
- Add Bluetooth state check before scanning with prompt to enable
- Add iOS Bluetooth/Location permission descriptions and UIBackgroundModes
- Fix exclusive modifier selection (deselect siblings when max=1)
- Update cart service point when existing cart found
- Add delivery fee support to cart and stripe service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 15:09:24 -08:00

135 lines
5 KiB
Dart

import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:dchs_flutter_beacon/dchs_flutter_beacon.dart';
class BeaconPermissions {
static Future<bool> requestPermissions() async {
try {
// Request location permission (required for Bluetooth scanning)
final locationStatus = await Permission.locationWhenInUse.request();
debugPrint('[BeaconPermissions] Location: $locationStatus');
bool bluetoothGranted = true;
if (Platform.isIOS) {
// iOS uses a single Bluetooth permission
final bluetoothStatus = await Permission.bluetooth.request();
debugPrint('[BeaconPermissions] Bluetooth (iOS): $bluetoothStatus');
bluetoothGranted = bluetoothStatus.isGranted;
} else {
// Android 12+ requires separate scan/connect permissions
final bluetoothScan = await Permission.bluetoothScan.request();
final bluetoothConnect = await Permission.bluetoothConnect.request();
debugPrint('[BeaconPermissions] BluetoothScan: $bluetoothScan, BluetoothConnect: $bluetoothConnect');
bluetoothGranted = bluetoothScan.isGranted && bluetoothConnect.isGranted;
}
final allGranted = locationStatus.isGranted && bluetoothGranted;
if (allGranted) {
debugPrint('[BeaconPermissions] ✅ All permissions granted');
} else {
debugPrint('[BeaconPermissions] ❌ Permissions denied');
}
return allGranted;
} catch (e) {
debugPrint('[BeaconPermissions] Error requesting permissions: $e');
return false;
}
}
/// Check if Bluetooth is enabled - returns current state without prompting
static Future<bool> isBluetoothEnabled() async {
try {
final bluetoothState = await flutterBeacon.bluetoothState;
return bluetoothState == BluetoothState.stateOn;
} catch (e) {
debugPrint('[BeaconPermissions] Error checking Bluetooth state: $e');
return false;
}
}
/// Request to enable Bluetooth via system prompt (Android only)
static Future<bool> requestEnableBluetooth() async {
try {
debugPrint('[BeaconPermissions] 📶 Requesting Bluetooth enable...');
// This opens a system dialog on Android asking user to turn on Bluetooth
final result = await flutterBeacon.requestAuthorization;
debugPrint('[BeaconPermissions] Request authorization result: $result');
return result;
} catch (e) {
debugPrint('[BeaconPermissions] Error requesting Bluetooth enable: $e');
return false;
}
}
/// Open Bluetooth settings
static Future<bool> openBluetoothSettings() async {
try {
debugPrint('[BeaconPermissions] Opening Bluetooth settings...');
final opened = await flutterBeacon.openBluetoothSettings;
debugPrint('[BeaconPermissions] Open Bluetooth settings result: $opened');
return opened;
} catch (e) {
debugPrint('[BeaconPermissions] Error opening Bluetooth settings: $e');
return false;
}
}
/// Check if Bluetooth is enabled, and try to enable it if not
static Future<bool> ensureBluetoothEnabled() async {
try {
// Check current Bluetooth state
final bluetoothState = await flutterBeacon.bluetoothState;
debugPrint('[BeaconPermissions] 📶 Bluetooth state: $bluetoothState');
if (bluetoothState == BluetoothState.stateOn) {
debugPrint('[BeaconPermissions] ✅ Bluetooth is ON');
return true;
}
// Request to enable Bluetooth via system prompt
debugPrint('[BeaconPermissions] ⚠️ Bluetooth is OFF, requesting enable...');
await requestEnableBluetooth();
// Poll for Bluetooth state change (wait up to 10 seconds)
for (int i = 0; i < 20; i++) {
await Future.delayed(const Duration(milliseconds: 500));
final newState = await flutterBeacon.bluetoothState;
debugPrint('[BeaconPermissions] 📶 Polling Bluetooth state ($i): $newState');
if (newState == BluetoothState.stateOn) {
debugPrint('[BeaconPermissions] ✅ Bluetooth is now ON');
return true;
}
}
debugPrint('[BeaconPermissions] ❌ Bluetooth still OFF after waiting');
return false;
} catch (e) {
debugPrint('[BeaconPermissions] Error checking Bluetooth state: $e');
return false;
}
}
static Future<bool> checkPermissions() async {
final locationStatus = await Permission.locationWhenInUse.status;
bool bluetoothGranted = true;
if (Platform.isIOS) {
final bluetoothStatus = await Permission.bluetooth.status;
bluetoothGranted = bluetoothStatus.isGranted;
} else {
final bluetoothScan = await Permission.bluetoothScan.status;
final bluetoothConnect = await Permission.bluetoothConnect.status;
bluetoothGranted = bluetoothScan.isGranted && bluetoothConnect.isGranted;
}
return locationStatus.isGranted && bluetoothGranted;
}
static Future<void> openSettings() async {
await openAppSettings();
}
}