diff --git a/app/lib/backend/http/api/hardware.dart b/app/lib/backend/http/api/hardware.dart new file mode 100644 index 0000000000..4ac89b75e0 --- /dev/null +++ b/app/lib/backend/http/api/hardware.dart @@ -0,0 +1,24 @@ +import 'dart:convert'; +import 'dart:ffi'; + +import 'package:flutter/material.dart'; +import 'package:friend_private/backend/http/shared.dart'; +import 'package:friend_private/env/env.dart'; + +Future saveFcmTokenServer( + {required String token, required String timeZone}) async { + var response = await makeApiCall( + url: '${Env.apiBaseUrl}v1/firmware/battery-alert', + headers: {'Content-Type': 'application/json'}, + method: 'POST', + body: jsonEncode({'fcm_token': token, 'time_zone': timeZone}), + ); + + debugPrint('saveToken: ${response?.body}'); + if (response?.statusCode == 200) { + debugPrint("Token saved successfully"); + } else { + debugPrint("Failed to save token"); + } +} + diff --git a/app/lib/providers/device_provider.dart b/app/lib/providers/device_provider.dart index adcc88bf6f..9548d28e49 100644 --- a/app/lib/providers/device_provider.dart +++ b/app/lib/providers/device_provider.dart @@ -10,7 +10,10 @@ import 'package:friend_private/services/services.dart'; import 'package:friend_private/utils/analytics/mixpanel.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption { +class DeviceProvider extends ChangeNotifier + implements IDeviceServiceSubsciption { + + CaptureProvider? captureProvider; bool isConnecting = false; @@ -22,6 +25,7 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption int batteryLevel = -1; Timer? _reconnectionTimer; int connectionCheckSeconds = 4; + bool lowBatteryNotified = false; Timer? _disconnectNotificationTimer; @@ -44,10 +48,13 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption Future getDeviceInfo() async { if (connectedDevice != null) { - if (pairedDevice?.firmwareRevision != null && pairedDevice?.firmwareRevision != 'Unknown') { + if (pairedDevice?.firmwareRevision != null && + pairedDevice?.firmwareRevision != 'Unknown') { return; } - var connection = await ServiceManager.instance().device.ensureConnection(connectedDevice!.id); + var connection = await ServiceManager.instance() + .device + .ensureConnection(connectedDevice!.id); pairedDevice = await connectedDevice!.getDeviceInfo(connection); SharedPreferencesUtil().btDevice = pairedDevice!; } else { @@ -66,16 +73,19 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption void Function(int)? onBatteryLevelChange, }) async { { - var connection = await ServiceManager.instance().device.ensureConnection(deviceId); + var connection = + await ServiceManager.instance().device.ensureConnection(deviceId); if (connection == null) { return Future.value(null); } - return connection.getBleBatteryLevelListener(onBatteryLevelChange: onBatteryLevelChange); + return connection.getBleBatteryLevelListener( + onBatteryLevelChange: onBatteryLevelChange); } } Future> _getStorageList(String deviceId) async { - var connection = await ServiceManager.instance().device.ensureConnection(deviceId); + var connection = + await ServiceManager.instance().device.ensureConnection(deviceId); if (connection == null) { return []; } @@ -87,7 +97,8 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption if (deviceId.isEmpty) { return null; } - var connection = await ServiceManager.instance().device.ensureConnection(deviceId); + var connection = + await ServiceManager.instance().device.ensureConnection(deviceId); return connection?.device; } @@ -98,6 +109,21 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption connectedDevice!.id, onBatteryLevelChange: (int value) { batteryLevel = value; + + if (batteryLevel < 20) { + if (!lowBatteryNotified) { + NotificationService.instance.createNotification( + title: 'Charge your OMI necklace🪫!', + body: 'Your OMI necklace is running low on battery. Please charge it to avoid any interruptions.', + ); + lowBatteryNotified = true; + } + } else { + // Reset flag when battery charges above 20% + lowBatteryNotified = false; + } + + notifyListeners(); }, ); notifyListeners(); @@ -106,7 +132,8 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption Future periodicConnect(String printer) async { debugPrint("period connect"); _reconnectionTimer?.cancel(); - _reconnectionTimer = Timer.periodic(Duration(seconds: connectionCheckSeconds), (t) async { + _reconnectionTimer = + Timer.periodic(Duration(seconds: connectionCheckSeconds), (t) async { debugPrint("period connect..."); print(printer); print('seconds: $connectionCheckSeconds'); @@ -115,7 +142,8 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption if (SharedPreferencesUtil().btDevice.id.isEmpty) { return; } - print("isConnected: $isConnected, isConnecting: $isConnecting, connectedDevice: $connectedDevice"); + print( + "isConnected: $isConnected, isConnecting: $isConnecting, connectedDevice: $connectedDevice"); if ((!isConnected && connectedDevice == null)) { if (isConnecting) { return; @@ -127,7 +155,8 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption }); } - Future _scanAndConnectDevice({bool autoConnect = true, bool timeout = false}) async { + Future _scanAndConnectDevice( + {bool autoConnect = true, bool timeout = false}) async { var device = await _getConnectedDevice(); if (device != null) { return device; @@ -136,7 +165,9 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption int timeoutCounter = 0; while (true) { if (timeout && timeoutCounter >= 10) return null; - await ServiceManager.instance().device.discover(desirableDeviceId: SharedPreferencesUtil().btDevice.id); + await ServiceManager.instance() + .device + .discover(desirableDeviceId: SharedPreferencesUtil().btDevice.id); if (connectedDevice != null) { return connectedDevice; } @@ -270,11 +301,14 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption } @override - void onDeviceConnectionStateChanged(String deviceId, DeviceConnectionState state) async { - debugPrint("provider > device connection state changed...${deviceId}...${state}...${connectedDevice?.id}"); + void onDeviceConnectionStateChanged( + String deviceId, DeviceConnectionState state) async { + debugPrint( + "provider > device connection state changed...${deviceId}...${state}...${connectedDevice?.id}"); switch (state) { case DeviceConnectionState.connected: - var connection = await ServiceManager.instance().device.ensureConnection(deviceId); + var connection = + await ServiceManager.instance().device.ensureConnection(deviceId); if (connection == null) { return; } @@ -294,4 +328,4 @@ class DeviceProvider extends ChangeNotifier implements IDeviceServiceSubsciption @override void onStatusChanged(DeviceServiceStatus status) {} -} +} \ No newline at end of file diff --git a/backend/routers/firmware.py b/backend/routers/firmware.py index 571f5e1a9e..8b075d582b 100644 --- a/backend/routers/firmware.py +++ b/backend/routers/firmware.py @@ -4,6 +4,9 @@ import httpx from fastapi import APIRouter, HTTPException +from utils.notifications import send_notification +from database.notifications import get_token_only + router = APIRouter() @@ -69,6 +72,7 @@ async def get_latest_version(device: int): } + def extract_key_value_pairs(markdown_content): key_value_pattern = re.compile(r'', re.DOTALL) key_value_match = key_value_pattern.search(markdown_content) @@ -88,3 +92,8 @@ def extract_key_value_pairs(markdown_content): key_value_map[key] = value return key_value_map + + + + +