feat: 蓝牙血压计基础架构 + UI配色体系升级
- 新增 AppColors 配色体系(紫蓝渐变 + 超大圆角 + 漂浮卡片) - 新增 OmronBleService(BLE 扫描/连接/SFLOAT 协议解析) - 新增 BpReading 数据模型 + 血压数据自动同步后端 - 新增 DeviceScanPage(血压计扫描绑定页)+ DeviceBindPage(已绑定管理页) - 侧边栏新增"蓝牙设备"入口,ProfilePage 移除设备管理 - Android/iOS BLE 权限配置(BLUETOOTH_SCAN/CONNECT) - AppTheme 升级:新阴影系统、新语义色、圆角放大
This commit is contained in:
92
health_app/lib/providers/omron_device_provider.dart
Normal file
92
health_app/lib/providers/omron_device_provider.dart
Normal file
@@ -0,0 +1,92 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'auth_provider.dart';
|
||||
import 'data_providers.dart';
|
||||
import '../models/bp_reading.dart';
|
||||
import '../services/omron_ble_service.dart';
|
||||
|
||||
/// BLE 服务单例
|
||||
final omronBleServiceProvider = Provider<OmronBleService>((ref) {
|
||||
return OmronBleService();
|
||||
});
|
||||
|
||||
/// 设备绑定状态
|
||||
class DeviceBindState {
|
||||
final bool isBound;
|
||||
final String? mac;
|
||||
final String? name;
|
||||
final String? lastSync;
|
||||
final bool isConnected;
|
||||
final BpReading? lastReading;
|
||||
|
||||
const DeviceBindState({
|
||||
this.isBound = false,
|
||||
this.mac,
|
||||
this.name,
|
||||
this.lastSync,
|
||||
this.isConnected = false,
|
||||
this.lastReading,
|
||||
});
|
||||
|
||||
DeviceBindState copyWith({
|
||||
bool? isBound,
|
||||
String? mac,
|
||||
String? name,
|
||||
String? lastSync,
|
||||
bool? isConnected,
|
||||
BpReading? lastReading,
|
||||
}) => DeviceBindState(
|
||||
isBound: isBound ?? this.isBound,
|
||||
mac: mac ?? this.mac,
|
||||
name: name ?? this.name,
|
||||
lastSync: lastSync ?? this.lastSync,
|
||||
isConnected: isConnected ?? this.isConnected,
|
||||
lastReading: lastReading ?? this.lastReading,
|
||||
);
|
||||
}
|
||||
|
||||
class DeviceBindNotifier extends Notifier<DeviceBindState> {
|
||||
@override
|
||||
DeviceBindState build() {
|
||||
_loadBinding();
|
||||
return const DeviceBindState();
|
||||
}
|
||||
|
||||
Future<void> _loadBinding() async {
|
||||
final db = ref.read(localDbProvider);
|
||||
final mac = await db.read('bp_device_mac');
|
||||
final name = await db.read('bp_device_name');
|
||||
final lastSync = await db.read('bp_last_sync');
|
||||
if (mac != null && mac.isNotEmpty) {
|
||||
state = state.copyWith(isBound: true, mac: mac, name: name, lastSync: lastSync);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> bind(String mac, String name) async {
|
||||
final db = ref.read(localDbProvider);
|
||||
await db.write('bp_device_mac', mac);
|
||||
await db.write('bp_device_name', name);
|
||||
state = state.copyWith(isBound: true, mac: mac, name: name);
|
||||
}
|
||||
|
||||
Future<void> unbind() async {
|
||||
final db = ref.read(localDbProvider);
|
||||
await db.delete('bp_device_mac');
|
||||
await db.delete('bp_device_name');
|
||||
await db.delete('bp_last_sync');
|
||||
state = const DeviceBindState();
|
||||
}
|
||||
|
||||
void setConnected(bool connected) {
|
||||
state = state.copyWith(isConnected: connected);
|
||||
}
|
||||
|
||||
Future<void> onReading(BpReading reading) async {
|
||||
final db = ref.read(localDbProvider);
|
||||
final lastSync = '${reading.timestamp.month}/${reading.timestamp.day} ${reading.timestamp.hour}:${reading.timestamp.minute.toString().padLeft(2, '0')}';
|
||||
await db.write('bp_last_sync', lastSync);
|
||||
state = state.copyWith(lastSync: lastSync, lastReading: reading);
|
||||
ref.invalidate(latestHealthProvider);
|
||||
}
|
||||
}
|
||||
|
||||
final omronDeviceProvider = NotifierProvider<DeviceBindNotifier, DeviceBindState>(DeviceBindNotifier.new);
|
||||
Reference in New Issue
Block a user