diff --git a/src/device/preview/preview-fixtures.ts b/src/device/preview/preview-fixtures.ts index b0d74d87..a30d5061 100644 --- a/src/device/preview/preview-fixtures.ts +++ b/src/device/preview/preview-fixtures.ts @@ -343,6 +343,37 @@ const ATTACKSHARK: MouseStatus = { firmware: ["Mouse 1.0.4", "Dongle 1.0.3"], }; +/** + * The Cosmic Byte Kilonova 3335IC through its receiver (SinoWealth + * `258a:002f`), browser transport: identity, battery, link, and read-only DPI. + * The driver refuses writes until the full bank is decoded, so the shell shows + * DPI read-out but no settings cards. + */ +const KILONOVA: MouseStatus = { + brand: "Cosmic Byte" as MouseStatus["brand"], + name: "Cosmic Byte Kilonova 3335IC", + ui: { + family: "sinowealth-kilonova-3335ic", + settingsReady: false, + valuesVerified: true, + forceShowBattery: true, + hideProcessingCard: true, + defaultDisplayName: "Cosmic Byte Kilonova 3335IC", + statusNote: "OpenMouse reads this Cosmic Byte Kilonova 3335IC's DPI from its onboard memory; other settings are not decoded and changes are refused. The battery and awake check need OpenMouse Bridge.", + }, + batteryPercent: null, + batteryState: "Unknown", + dpi: 1600, + dpiStages: [400, 800, 1600, 3200, 6400, 16000], + activeDpiStage: 2, + pollingRateHz: 0, + activeProfile: null, + connectionType: "Wireless", + connectionDetail: "2.4 GHz receiver", + liftOffDistance: null, + firmware: [], +}; + const M3K: MouseStatus = { brand: "Zaunkoenig" as MouseStatus["brand"], name: "Zaunkoenig M3K", @@ -1086,6 +1117,7 @@ export const PREVIEW_FIXTURES: Record = { wlmouse: { label: "WLMouse BEAST X", status: WLMOUSE }, lamzu: { label: "Lamzu Atlantis OG V2", status: LAMZU }, "attack-shark": { label: "Attack Shark R5 Ultra", status: ATTACKSHARK }, + kilonova: { label: "Cosmic Byte Kilonova 3335IC", status: KILONOVA }, crdrako: { label: "CRDRAKO KO-ONE", status: CRDRAKO }, m3k: { label: "Zaunkoenig M3K", status: M3K }, atk: { label: "ATK A9 Ultra", status: ATK }, diff --git a/src/device/preview/preview-modes.ts b/src/device/preview/preview-modes.ts index cea4d4d5..43011eaf 100644 --- a/src/device/preview/preview-modes.ts +++ b/src/device/preview/preview-modes.ts @@ -20,6 +20,7 @@ export const PREVIEW_KEYS = [ "wlmouse", "lamzu", "attack-shark", + "kilonova", "crdrako", "m3k", "atk", @@ -74,6 +75,7 @@ export function parsePreviewMode(value: string | null): PreviewMode | null { case "wlmouse": return "wlmouse"; case "lamzu": return "lamzu"; case "attack-shark": return "attack-shark"; + case "kilonova": return "kilonova"; case "crdrako": return "crdrako"; case "m3k": return "m3k"; case "atk": return "atk"; diff --git a/src/features/devices/DeviceHero.tsx b/src/features/devices/DeviceHero.tsx index 37e080fd..eb294d1c 100644 --- a/src/features/devices/DeviceHero.tsx +++ b/src/features/devices/DeviceHero.tsx @@ -159,6 +159,8 @@ export function CurrentSetupPanel({ snapshot }: { snapshot: ControlSnapshot }): unit: "%", sub: displayText(locale, status.batteryState), }); + } else if (status.ui?.forceShowBattery === true) { + figures.push({ key: "battery", label: t(locale, "ov.batteryLabel"), value: "–" }); } if (status.activeProfile != null) { figures.push({ key: "profile", label: t(locale, "ov.onboardProfile"), value: String(status.activeProfile) }); diff --git a/src/features/devices/DeviceStats.tsx b/src/features/devices/DeviceStats.tsx index 1552cf09..cc77b77d 100644 --- a/src/features/devices/DeviceStats.tsx +++ b/src/features/devices/DeviceStats.tsx @@ -41,6 +41,11 @@ export function DeviceStats({ {status.batteryPercent}% {estimate && full ? {estimate.time} : null} + ) : status.ui?.forceShowBattery === true ? ( + + + {"–"} + ) : null} {status.pollingRateHz > 0 ? (