diff --git a/components.d.ts b/components.d.ts index 7f67bd5..5abaf80 100644 --- a/components.d.ts +++ b/components.d.ts @@ -18,10 +18,13 @@ declare module 'vue' { SystemUiconsSignalFull: typeof import('./src/components/icons/SystemUiconsSignalFull.vue')['default'] SystemUiconsSignalLow: typeof import('./src/components/icons/SystemUiconsSignalLow.vue')['default'] SystemUiconsSignalMedium: typeof import('./src/components/icons/SystemUiconsSignalMedium.vue')['default'] + TablerActivityHeartbeat: typeof import('./src/components/icons/TablerActivityHeartbeat.vue')['default'] TablerBluetooth: typeof import('./src/components/icons/TablerBluetooth.vue')['default'] TablerBluetoothConnected: typeof import('./src/components/icons/TablerBluetoothConnected.vue')['default'] TablerBluetoothOff: typeof import('./src/components/icons/TablerBluetoothOff.vue')['default'] TablerBluetoothX: typeof import('./src/components/icons/TablerBluetoothX.vue')['default'] + TablerCaretDownFilled: typeof import('./src/components/icons/TablerCaretDownFilled.vue')['default'] + TablerCaretUpFilled: typeof import('./src/components/icons/TablerCaretUpFilled.vue')['default'] TablerDeviceWatch: typeof import('./src/components/icons/TablerDeviceWatch.vue')['default'] TablerReload: typeof import('./src/components/icons/TablerReload.vue')['default'] } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 3d2c472..778520e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -2,10 +2,7 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] use btleplug::api::bleuuid::uuid_from_u16; -use btleplug::api::CentralEvent::{ - DeviceConnected, DeviceDisconnected, DeviceDiscovered, DeviceUpdated, - ManufacturerDataAdvertisement, ServiceDataAdvertisement, ServicesAdvertisement, -}; +use btleplug::api::CentralEvent::{DeviceDisconnected, DeviceDiscovered, DeviceUpdated}; use btleplug::api::{BDAddr, Central, Manager as _, Peripheral as _, ScanFilter}; use btleplug::platform::{Adapter, Manager as BtleManager, Peripheral, PeripheralId}; use futures::StreamExt; @@ -88,6 +85,7 @@ impl BleConnection { { return Err("Peripheral does not have the required service".into()); } + self.set_peripheral(Some(peripheral)).await; let peripheral = self.peripheral.lock().await; @@ -110,6 +108,40 @@ impl BleConnection { .rssi .unwrap(), }; + + let service = peripheral + .as_ref() + .unwrap() + .services() + .into_iter() + .find(|s| s.uuid == uuid_from_u16(0x180D)) + .unwrap(); + let characteristic = service + .characteristics + .into_iter() + .find(|c| c.uuid == uuid_from_u16(0x2A37)) + .unwrap(); + + let peripheral = peripheral.clone(); + peripheral + .as_ref() + .unwrap() + .subscribe(&characteristic) + .await?; + let app_clone = app.clone(); + + tokio::spawn(async move { + let mut notification_stream = + peripheral.as_ref().unwrap().notifications().await.unwrap(); + while let Some(notification) = notification_stream.next().await { + if notification.uuid == uuid_from_u16(0x2A37) { + let value = notification.value; + let heart_rate = value[1] as u16; + app_clone.emit_all("heart-rate", heart_rate).unwrap(); + } + } + }); + app.emit_all("device-connected", device).unwrap(); Ok(()) } @@ -127,7 +159,7 @@ impl BleConnection { let app_handle = app.clone(); // Clone the AppHandle to move into the tokio::spawn closure let mut event_stream = central.as_ref().unwrap().events().await.unwrap(); - let mut self_clone = self.clone(); // Clone the BleConnection to move into the tokio::spawn closure + let self_clone = self.clone(); // Clone the BleConnection to move into the tokio::spawn closure tokio::spawn(async move { while let Some(event) = event_stream.next().await { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 13614a2..c929920 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -6,8 +6,8 @@ "distDir": "../dist" }, "package": { - "productName": "heartbeat-cat", - "version": "0.0.1" + "productName": "HBCat", + "version": "1.0.1" }, "tauri": { "allowlist": { @@ -37,7 +37,8 @@ "minWidth": 800, "minHeight": 500, "width": 800, - "height": 500 + "height": 500, + "userAgent": "Heartbeat Cat" } ], "security": { @@ -47,9 +48,20 @@ "active": true, "targets": "all", "identifier": "ga.bh8.heartbeat-cat", + "publisher": "TimothyYin", + "copyright": "2024 TimothyYin", + "category": "Utility", + "shortDescription": "HBCat", + "longDescription": "Catch your heartbeat", "icon": [ "icons/icon.ico" - ] + ], + "windows": { + "nsis": { + "installerIcon": "icons/icon.ico", + "installMode": "both" + } + } } } -} +} \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 063cec8..0bd3eaf 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,10 +7,6 @@ const store = useBrcatStore(); invoke("register_central_events"); -listen("heart-rate", (hr) => { - console.log('Heart Rate', hr); -}) - listen("scan-list-update", (event) => { console.log('scan-list-update', event.payload); }) @@ -52,7 +48,7 @@ listen("device-disconnected", (event) => { --app-background: #f8f8f8; --title-bar-background: #e4e4e4; - --title-bar-color: #F25E86; + --title-bar-color: var(--primary-color); --title-bar-height: 25px; --drawer-bar-background: #eeeeee; diff --git a/src/assets/css/style.css b/src/assets/css/style.css index a2aaed7..7965745 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -71,7 +71,6 @@ } .btn { - border: none; outline: none; padding: 6px 12px; min-width: 30px; @@ -79,7 +78,6 @@ cursor: pointer; text-transform: uppercase; color: #fff; - background-color: #F25E86; -webkit-border-radius: 4px; -moz-border-radius: 4px; -ms-border-radius: 4px; @@ -90,22 +88,19 @@ -moz-transition: all .3s ease; -ms-transition: all .3s ease; -o-transition: all .3s ease; - @apply text-xs; + @apply text-xs bg-primary border-0; } .btn.outline { - background-color: transparent; - color: #F25E86; - border: 1px solid #F25E86; - box-shadow: none; + @apply text-primary bg-transparent border border-primary shadow-none; } .btn:hover { - box-shadow: 2px 2px 6px 1px rgb(0 0 0 / 20%); + box-shadow: 2px 2px 6px 1px rgb(0 0 0 / .1); } .btn:active { - box-shadow: 2px 2px 6px 1px rgb(0 0 0 / 20%), 2px 2px 6px 1px rgb(0 0 0 / 20%) inset; + box-shadow: 2px 2px 6px 1px rgb(0 0 0 / .1), 2px 2px 6px 1px rgb(0 0 0 / .1) inset; } .btn:disabled { diff --git a/src/components/DrawerContainer.vue b/src/components/DrawerContainer.vue index 6e74dbb..bce4324 100644 --- a/src/components/DrawerContainer.vue +++ b/src/components/DrawerContainer.vue @@ -21,12 +21,33 @@ const navList = ref([ {{ item.title }} -