Skip to content

Commit ef5c548

Browse files
committed
keep app awake, rework scanning, and remove always scan toggle
1 parent 8be5bb6 commit ef5c548

15 files changed

+236
-294
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
### V 1.2.2
1+
### V 1.3.0
22

33
- Fix bug when selecting a color
44
- Fix a bug with translations not applying to triggers
55
- Set default actions for more triggers
66
- Add gear pairing to onboarding
77
- Add marketing notifications toggle
88
- Add UwU toggle (Whats this?)
9+
- Removed option to disable always scanning for gear.
910

1011
### V 1.2.1
1112

android/gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ org.gradle.jvmargs=-Xmx10g -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g
22
android.useAndroidX=true
33
android.enableJetifier=true
44
android.nonTransitiveRClass=true
5-
android.nonFinalResIds=false
5+
android.nonFinalResIds=true
66
kotlin.jvm.target.validation.mode=IGNORE
77
org.gradle.parallel=true
8-
org.gradle.caching=false
8+
org.gradle.caching=true
99
android.enableR8.fullMode=false

lib/Backend/Bluetooth/bluetooth_manager_plus.dart

Lines changed: 94 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:flutter_foreground_task/flutter_foreground_task.dart';
1111
import 'package:hive_ce_flutter/adapters.dart';
1212
import 'package:logging/logging.dart' as log;
1313
import 'package:permission_handler/permission_handler.dart';
14+
import 'package:riverpod/src/framework.dart';
1415
import 'package:riverpod_annotation/riverpod_annotation.dart';
1516
import 'package:tail_app/Backend/command_history.dart';
1617
import 'package:tail_app/Backend/command_queue.dart';
@@ -42,7 +43,7 @@ class InitFlutterBluePlus extends _$InitFlutterBluePlus {
4243

4344
@override
4445
Future<void> build() async {
45-
if (ref.read(getBluetoothPermissionProvider.future) == BluetoothPermissionStatus.denied) {
46+
if (await ref.read(getBluetoothPermissionProvider.future) == BluetoothPermissionStatus.denied) {
4647
ref.invalidateSelf();
4748
_bluetoothPlusLogger.info("Bluetooth permission not granted");
4849
return;
@@ -79,7 +80,6 @@ class InitFlutterBluePlus extends _$InitFlutterBluePlus {
7980
ref.watch(_onScanResultsProvider);
8081
// Shut down bluetooth related things
8182
ref.onDispose(() async {
82-
stopScan();
8383
//Disconnect any gear
8484
for (var element in FlutterBluePlus.connectedDevices) {
8585
await disconnect(element.remoteId.str);
@@ -102,7 +102,7 @@ class InitFlutterBluePlus extends _$InitFlutterBluePlus {
102102
isBluetoothEnabled.value = false;
103103
_didInitFlutterBluePlus = false; // Allow restarting ble stack
104104
});
105-
ref.read(scanMonitorProvider);
105+
ref.read(scanProvider);
106106
}
107107
}
108108

@@ -242,17 +242,19 @@ class _OnConnectionStateChanged extends _$OnConnectionStateChanged {
242242
..fine('Requesting notification permission')
243243
..finer('Requesting notification permission result${await Permission.notification.request()}'); // Used only for Foreground service
244244
FlutterForegroundTask.init(
245-
androidNotificationOptions: AndroidNotificationOptions(
246-
channelId: 'foreground_service',
247-
channelName: 'Gear Connected',
248-
channelDescription: 'This notification appears when any gear is running.',
249-
channelImportance: NotificationChannelImportance.LOW,
250-
priority: NotificationPriority.LOW,
251-
),
252-
iosNotificationOptions: const IOSNotificationOptions(),
253-
foregroundTaskOptions: ForegroundTaskOptions(
254-
eventAction: ForegroundTaskEventAction.nothing(),
255-
));
245+
androidNotificationOptions: AndroidNotificationOptions(
246+
channelId: 'foreground_service',
247+
channelName: 'Gear Connected',
248+
channelDescription: 'This notification appears when any gear is running.',
249+
channelImportance: NotificationChannelImportance.LOW,
250+
priority: NotificationPriority.LOW,
251+
),
252+
iosNotificationOptions: const IOSNotificationOptions(),
253+
foregroundTaskOptions: ForegroundTaskOptions(
254+
eventAction: ForegroundTaskEventAction.repeat(500),
255+
allowWakeLock: true,
256+
),
257+
);
256258
FlutterForegroundTask.startService(
257259
notificationTitle: "Gear Connected",
258260
notificationText: "Gear is connected to The Tail Company app",
@@ -520,41 +522,86 @@ Future<void> connect(String id) async {
520522
}
521523
}
522524

523-
enum ScanReason { background, addGear, manual, notScanning }
525+
@Riverpod(keepAlive: true)
526+
class Scan extends _$Scan {
527+
StreamSubscription<bool>? isScanningStreamSubscription;
528+
@override
529+
ScanReason build() {
530+
isScanningStreamSubscription = FlutterBluePlus.isScanning.listen(onIsScanningChange);
524531

525-
ScanReason _scanReason = ScanReason.notScanning;
532+
ref.listen(isAllKnownGearConnectedProvider, isAllKnownGearConnectedProviderListener);
526533

527-
Future<void> beginScan({required ScanReason scanReason, Duration? timeout}) async {
528-
if (_didInitFlutterBluePlus && !FlutterBluePlus.isScanningNow && isBluetoothEnabled.value) {
529-
_bluetoothPlusLogger.info("Starting scan");
530-
_scanReason = scanReason;
531-
await FlutterBluePlus.startScan(withServices: DeviceRegistry.getAllIds().map(Guid.new).toList(), continuousUpdates: timeout == null, androidScanMode: AndroidScanMode.lowPower, timeout: timeout);
534+
Hive.box(settings).listenable(keys: [hasCompletedOnboarding])
535+
..removeListener(isAllGearConnectedListener)
536+
..addListener(isAllGearConnectedListener);
537+
isBluetoothEnabled
538+
..removeListener(isAllGearConnectedListener)
539+
..addListener(isAllGearConnectedListener);
540+
Future.delayed(
541+
Duration(milliseconds: 5),
542+
() => isAllGearConnectedListener(),
543+
);
544+
545+
ref.onDispose(
546+
() {
547+
isScanningStreamSubscription?.cancel();
548+
stopScan();
549+
},
550+
);
551+
return ScanReason.notScanning;
532552
}
533-
}
534553

535-
bool isScanningNow() {
536-
if (!_didInitFlutterBluePlus) {
537-
return false;
554+
void isAllKnownGearConnectedProviderListener(bool? previous, bool next) {
555+
isAllGearConnectedListener();
538556
}
539-
return FlutterBluePlus.isScanningNow;
540-
}
541557

542-
Stream<bool> isScanning() {
543-
if (!_didInitFlutterBluePlus) {
544-
return Stream.value(false);
558+
void onIsScanningChange(bool isScanning) {
559+
if (state != ScanReason.notScanning && !isScanning) {
560+
state = ScanReason.notScanning;
561+
}
545562
}
546-
return FlutterBluePlus.isScanning;
547-
}
548563

549-
Future<void> stopScan() async {
550-
if (!_didInitFlutterBluePlus) {
551-
return;
564+
Future<void> beginScan({required ScanReason scanReason, Duration? timeout}) async {
565+
if (_didInitFlutterBluePlus && !FlutterBluePlus.isScanningNow && isBluetoothEnabled.value) {
566+
_bluetoothPlusLogger.info("Starting scan");
567+
state = scanReason;
568+
await FlutterBluePlus.startScan(withServices: DeviceRegistry.getAllIds().map(Guid.new).toList(), continuousUpdates: timeout == null, androidScanMode: AndroidScanMode.lowPower, timeout: timeout);
569+
}
570+
}
571+
572+
void stopActiveScan() {
573+
if (state == ScanReason.addGear) {
574+
state = ScanReason.background;
575+
}
576+
isAllGearConnectedListener();
577+
}
578+
579+
Future<void> stopScan() async {
580+
if (!_didInitFlutterBluePlus) {
581+
return;
582+
}
583+
_bluetoothPlusLogger.info("stopScan called");
584+
await FlutterBluePlus.stopScan();
585+
state = ScanReason.notScanning;
586+
}
587+
588+
void isAllGearConnectedListener() {
589+
if (!ref.exists(isAllKnownGearConnectedProvider)) {
590+
return;
591+
}
592+
593+
bool allConnected = ref.read(isAllKnownGearConnectedProvider);
594+
bool isInOnboarding = HiveProxy.getOrDefault(settings, hasCompletedOnboarding, defaultValue: hasCompletedOnboardingDefault) < hasCompletedOnboardingVersionToAgree;
595+
if ((!allConnected || isInOnboarding) && isBluetoothEnabled.value) {
596+
beginScan(scanReason: ScanReason.background);
597+
} else if ((allConnected && !isInOnboarding && state == ScanReason.background) || !isBluetoothEnabled.value) {
598+
stopScan();
599+
}
552600
}
553-
_bluetoothPlusLogger.info("stopScan called");
554-
await FlutterBluePlus.stopScan();
555-
_scanReason = ScanReason.notScanning;
556601
}
557602

603+
enum ScanReason { background, addGear, notScanning }
604+
558605
Future<void> sendMessage(BaseStatefulDevice device, List<int> message, {bool withoutResponse = false}) async {
559606
if (!_didInitFlutterBluePlus) {
560607
return;
@@ -578,27 +625,16 @@ Future<void> sendMessage(BaseStatefulDevice device, List<int> message, {bool wit
578625
}
579626
}
580627

581-
@Riverpod(keepAlive: true)
582-
class ScanMonitor extends _$ScanMonitor {
583-
@override
584-
void build() {
585-
ref.watch(isAllKnownGearConnectedProvider);
586-
Hive.box(settings).listenable(keys: [alwaysScanning])
587-
..removeListener(listener)
588-
..addListener(listener);
589-
isBluetoothEnabled
590-
..removeListener(listener)
591-
..addListener(listener);
592-
listener();
628+
bool isScanningNow() {
629+
if (!_didInitFlutterBluePlus) {
630+
return false;
593631
}
632+
return FlutterBluePlus.isScanningNow;
633+
}
594634

595-
void listener() {
596-
bool allConnected = ref.read(isAllKnownGearConnectedProvider);
597-
bool alwaysScanningValue = HiveProxy.getOrDefault(settings, alwaysScanning, defaultValue: alwaysScanningDefault);
598-
if (!allConnected && alwaysScanningValue && isBluetoothEnabled.value) {
599-
beginScan(scanReason: ScanReason.background);
600-
} else if ((allConnected && _scanReason == ScanReason.background) || !isBluetoothEnabled.value) {
601-
stopScan();
602-
}
635+
Stream<bool> isScanning() {
636+
if (!_didInitFlutterBluePlus) {
637+
return Stream.value(false);
603638
}
639+
return FlutterBluePlus.isScanning;
604640
}

0 commit comments

Comments
 (0)