mirror of
https://github.com/librekeys/picoforge.git
synced 2026-07-28 08:01:19 -07:00
chore(ui): refactor config view data/types
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "picoforge",
|
||||
"version": "0.3.0",
|
||||
"identifier": "in.suyogtandel.picoforge",
|
||||
"build": {
|
||||
"beforeDevCommand": "deno task dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
"beforeBuildCommand": "deno task build",
|
||||
"frontendDist": "../build"
|
||||
},
|
||||
"app": {
|
||||
"macOSPrivateApi": true,
|
||||
"windows": [
|
||||
{
|
||||
"title": "picoforge",
|
||||
"width": 1280,
|
||||
"height": 720,
|
||||
"minWidth": 500,
|
||||
"minHeight": 250,
|
||||
"resizable": true,
|
||||
"decorations": false,
|
||||
"transparent": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico",
|
||||
"icons/icon.png",
|
||||
"icons/in.suyogtandel.picoforge.svg"
|
||||
]
|
||||
}
|
||||
}
|
||||
+138
-109
@@ -1,3 +1,5 @@
|
||||
use gpui::SharedString;
|
||||
|
||||
use crate::device::types::{FidoDeviceInfo, FullDeviceStatus};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
@@ -27,114 +29,141 @@ impl GlobalDeviceState {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VendorData {
|
||||
pub value: &'static str,
|
||||
pub label: &'static str,
|
||||
pub vid: &'static str,
|
||||
pub pid: &'static str,
|
||||
// config view:
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum UsbIdentityPreset {
|
||||
Custom,
|
||||
Generic,
|
||||
PicoHsm,
|
||||
PicoFido,
|
||||
PicoOpenPgp,
|
||||
Pico,
|
||||
SoloKeys,
|
||||
NitroHsm,
|
||||
NitroFido2,
|
||||
NitroStart,
|
||||
NitroPro,
|
||||
NitroKey3,
|
||||
YubiKey5,
|
||||
YubiKeyNeo,
|
||||
YubiHsm2,
|
||||
Gnuk,
|
||||
GnuPg,
|
||||
}
|
||||
|
||||
pub const VENDORS: &[VendorData] = &[
|
||||
VendorData {
|
||||
value: "custom",
|
||||
label: "Custom (Manual Entry)",
|
||||
vid: "",
|
||||
pid: "",
|
||||
},
|
||||
VendorData {
|
||||
value: "generic",
|
||||
label: "Generic (FEFF:FCFD)",
|
||||
vid: "FEFF",
|
||||
pid: "FCFD",
|
||||
},
|
||||
VendorData {
|
||||
value: "pico-hsm",
|
||||
label: "Pico Keys HSM (2E8A:10FD)",
|
||||
vid: "2E8A",
|
||||
pid: "10FD",
|
||||
},
|
||||
VendorData {
|
||||
value: "pico-fido",
|
||||
label: "Pico Keys Fido (2E8A:10FE)",
|
||||
vid: "2E8A",
|
||||
pid: "10FE",
|
||||
},
|
||||
VendorData {
|
||||
value: "pico-openpgp",
|
||||
label: "Pico Keys OpenPGP (2E8A:10FF)",
|
||||
vid: "2E8A",
|
||||
pid: "10FF",
|
||||
},
|
||||
VendorData {
|
||||
value: "pico",
|
||||
label: "Pico (2E8A:0003)",
|
||||
vid: "2E8A",
|
||||
pid: "0003",
|
||||
},
|
||||
VendorData {
|
||||
value: "solokeys",
|
||||
label: "SoloKeys (0483:A2CA)",
|
||||
vid: "0483",
|
||||
pid: "A2CA",
|
||||
},
|
||||
VendorData {
|
||||
value: "nitrohsm",
|
||||
label: "NitroHSM (20A0:4230)",
|
||||
vid: "20A0",
|
||||
pid: "4230",
|
||||
},
|
||||
VendorData {
|
||||
value: "nitrofido2",
|
||||
label: "NitroFIDO2 (20A0:42D4)",
|
||||
vid: "20A0",
|
||||
pid: "42D4",
|
||||
},
|
||||
VendorData {
|
||||
value: "nitrostart",
|
||||
label: "NitroStart (20A0:4211)",
|
||||
vid: "20A0",
|
||||
pid: "4211",
|
||||
},
|
||||
VendorData {
|
||||
value: "nitropro",
|
||||
label: "NitroPro (20A0:4108)",
|
||||
vid: "20A0",
|
||||
pid: "4108",
|
||||
},
|
||||
VendorData {
|
||||
value: "nitro3",
|
||||
label: "Nitrokey 3 (20A0:42B2)",
|
||||
vid: "20A0",
|
||||
pid: "42B2",
|
||||
},
|
||||
VendorData {
|
||||
value: "yubikey5",
|
||||
label: "YubiKey 5 (1050:0407)",
|
||||
vid: "1050",
|
||||
pid: "0407",
|
||||
},
|
||||
VendorData {
|
||||
value: "yubikeyneo",
|
||||
label: "YubiKey Neo (1050:0116)",
|
||||
vid: "1050",
|
||||
pid: "0116",
|
||||
},
|
||||
VendorData {
|
||||
value: "yubihsm",
|
||||
label: "YubiHSM 2 (1050:0030)",
|
||||
vid: "1050",
|
||||
pid: "0030",
|
||||
},
|
||||
VendorData {
|
||||
value: "gnuk",
|
||||
label: "Gnuk Token (234B:0000)",
|
||||
vid: "234B",
|
||||
pid: "0000",
|
||||
},
|
||||
VendorData {
|
||||
value: "gnupg",
|
||||
label: "GnuPG (234B:0000)",
|
||||
vid: "234B",
|
||||
pid: "0000",
|
||||
},
|
||||
];
|
||||
impl UsbIdentityPreset {
|
||||
pub fn details(&self) -> (SharedString, Option<&'static str>, Option<&'static str>) {
|
||||
match self {
|
||||
Self::Custom => ("Custom (Manual Entry)".into(), None, None),
|
||||
Self::Generic => ("Generic (FEFF:FCFD)".into(), Some("FEFF"), Some("FCFD")),
|
||||
Self::PicoHsm => (
|
||||
"Pico Keys HSM (2E8A:10FD)".into(),
|
||||
Some("2E8A"),
|
||||
Some("10FD"),
|
||||
),
|
||||
Self::PicoFido => (
|
||||
"Pico Keys Fido (2E8A:10FE)".into(),
|
||||
Some("2E8A"),
|
||||
Some("10FE"),
|
||||
),
|
||||
Self::PicoOpenPgp => (
|
||||
"Pico Keys OpenPGP (2E8A:10FF)".into(),
|
||||
Some("2E8A"),
|
||||
Some("10FF"),
|
||||
),
|
||||
Self::Pico => ("Pico (2E8A:0003)".into(), Some("2E8A"), Some("0003")),
|
||||
Self::SoloKeys => ("SoloKeys (0483:A2CA)".into(), Some("0483"), Some("A2CA")),
|
||||
Self::NitroHsm => ("NitroHSM (20A0:4230)".into(), Some("20A0"), Some("4230")),
|
||||
Self::NitroFido2 => ("NitroFIDO2 (20A0:42D4)".into(), Some("20A0"), Some("42D4")),
|
||||
Self::NitroStart => ("NitroStart (20A0:4211)".into(), Some("20A0"), Some("4211")),
|
||||
Self::NitroPro => ("NitroPro (20A0:4108)".into(), Some("20A0"), Some("4108")),
|
||||
Self::NitroKey3 => ("Nitrokey 3 (20A0:42B2)".into(), Some("20A0"), Some("42B2")),
|
||||
Self::YubiKey5 => ("YubiKey 5 (1050:0407)".into(), Some("1050"), Some("0407")),
|
||||
Self::YubiKeyNeo => ("YubiKey Neo (1050:0116)".into(), Some("1050"), Some("0116")),
|
||||
Self::YubiHsm2 => ("YubiHSM 2 (1050:0030)".into(), Some("1050"), Some("0030")),
|
||||
Self::Gnuk => ("Gnuk Token (234B:0000)".into(), Some("234B"), Some("0000")),
|
||||
Self::GnuPg => ("GnuPG (234B:0000)".into(), Some("234B"), Some("0000")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to find a preset by VID/PID string matching
|
||||
pub fn from_vid_pid(vid: &str, pid: &str) -> Self {
|
||||
let vid = vid.to_uppercase();
|
||||
let pid = pid.to_uppercase();
|
||||
|
||||
match (vid.as_str(), pid.as_str()) {
|
||||
("FEFF", "FCFD") => Self::Generic,
|
||||
("2E8A", "10FD") => Self::PicoHsm,
|
||||
("2E8A", "10FE") => Self::PicoFido,
|
||||
("2E8A", "10FF") => Self::PicoOpenPgp,
|
||||
("2E8A", "0003") => Self::Pico,
|
||||
("0483", "A2CA") => Self::SoloKeys,
|
||||
("20A0", "4230") => Self::NitroHsm,
|
||||
("20A0", "42D4") => Self::NitroFido2,
|
||||
("20A0", "4211") => Self::NitroStart,
|
||||
("20A0", "4108") => Self::NitroPro,
|
||||
("20A0", "42B2") => Self::NitroKey3,
|
||||
("1050", "0407") => Self::YubiKey5,
|
||||
("1050", "0116") => Self::YubiKeyNeo,
|
||||
("1050", "0030") => Self::YubiHsm2,
|
||||
("234B", "0000") => Self::Gnuk,
|
||||
_ => Self::Custom,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all() -> &'static [Self] {
|
||||
&[
|
||||
Self::Custom,
|
||||
Self::Generic,
|
||||
Self::PicoHsm,
|
||||
Self::PicoFido,
|
||||
Self::PicoOpenPgp,
|
||||
Self::Pico,
|
||||
Self::SoloKeys,
|
||||
Self::NitroHsm,
|
||||
Self::NitroFido2,
|
||||
Self::NitroStart,
|
||||
Self::NitroPro,
|
||||
Self::NitroKey3,
|
||||
Self::YubiKey5,
|
||||
Self::YubiKeyNeo,
|
||||
Self::YubiHsm2,
|
||||
Self::Gnuk,
|
||||
Self::GnuPg,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LedDriverType {
|
||||
PicoGpio = 1,
|
||||
PimoroniRgb = 2,
|
||||
Ws2812Neopixel = 3,
|
||||
Esp32Neopixel = 5,
|
||||
}
|
||||
|
||||
impl LedDriverType {
|
||||
pub fn label(&self) -> SharedString {
|
||||
match self {
|
||||
Self::PicoGpio => "Pico (Standard GPIO)".into(),
|
||||
Self::PimoroniRgb => "Pimoroni (RGB)".into(),
|
||||
Self::Ws2812Neopixel => "WS2812 (Neopixel)".into(),
|
||||
Self::Esp32Neopixel => "ESP32 Neopixel".into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the u8 value expected by the firmware configuration
|
||||
pub fn value(&self) -> u8 {
|
||||
*self as u8
|
||||
}
|
||||
|
||||
pub fn all() -> &'static [Self] {
|
||||
&[
|
||||
Self::PicoGpio,
|
||||
Self::PimoroniRgb,
|
||||
Self::Ws2812Neopixel,
|
||||
Self::Esp32Neopixel,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+65
-67
@@ -1,7 +1,7 @@
|
||||
use crate::device::io;
|
||||
use crate::device::types::{AppConfigInput, FullDeviceStatus};
|
||||
use crate::ui::components::{card::Card, page_view::PageView};
|
||||
use crate::ui::ui_types::VENDORS;
|
||||
use crate::ui::ui_types::{LedDriverType, UsbIdentityPreset};
|
||||
use gpui::*;
|
||||
use gpui_component::{
|
||||
ActiveTheme, Disableable, Icon, Theme,
|
||||
@@ -14,48 +14,48 @@ use gpui_component::{
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct VendorItem {
|
||||
value: SharedString,
|
||||
struct VendorSelectOption {
|
||||
preset: UsbIdentityPreset,
|
||||
label: SharedString,
|
||||
}
|
||||
|
||||
impl SelectItem for VendorItem {
|
||||
type Value = SharedString;
|
||||
impl SelectItem for VendorSelectOption {
|
||||
type Value = UsbIdentityPreset;
|
||||
|
||||
fn title(&self) -> SharedString {
|
||||
self.label.clone()
|
||||
}
|
||||
|
||||
fn value(&self) -> &Self::Value {
|
||||
&self.value
|
||||
&self.preset
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct DriverItem {
|
||||
value: u8,
|
||||
struct DriverSelectOption {
|
||||
driver_type: LedDriverType,
|
||||
label: SharedString,
|
||||
}
|
||||
|
||||
impl SelectItem for DriverItem {
|
||||
type Value = u8;
|
||||
impl SelectItem for DriverSelectOption {
|
||||
type Value = LedDriverType;
|
||||
|
||||
fn title(&self) -> SharedString {
|
||||
self.label.clone()
|
||||
}
|
||||
|
||||
fn value(&self) -> &Self::Value {
|
||||
&self.value
|
||||
&self.driver_type
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConfigView {
|
||||
vendor_select: Entity<SelectState<Vec<VendorItem>>>,
|
||||
vendor_select: Entity<SelectState<Vec<VendorSelectOption>>>,
|
||||
vid_input: Entity<InputState>,
|
||||
pid_input: Entity<InputState>,
|
||||
product_name_input: Entity<InputState>,
|
||||
led_gpio_input: Entity<InputState>,
|
||||
led_driver_select: Entity<SelectState<Vec<DriverItem>>>,
|
||||
led_driver_select: Entity<SelectState<Vec<DriverSelectOption>>>,
|
||||
led_brightness_slider: Entity<SliderState>,
|
||||
led_dimmable: bool,
|
||||
led_steady: bool,
|
||||
@@ -75,34 +75,28 @@ impl ConfigView {
|
||||
) -> Self {
|
||||
let config = device_status.as_ref().map(|s| &s.config);
|
||||
|
||||
let vendors: Vec<VendorItem> = VENDORS
|
||||
// Prepare Vendor Options
|
||||
let vendors: Vec<VendorSelectOption> = UsbIdentityPreset::all()
|
||||
.iter()
|
||||
.map(|v| VendorItem {
|
||||
value: v.value.into(),
|
||||
label: v.label.into(),
|
||||
.map(|preset| {
|
||||
let (label, _, _) = preset.details();
|
||||
VendorSelectOption {
|
||||
preset: *preset,
|
||||
label,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let drivers = vec![
|
||||
DriverItem {
|
||||
value: 1,
|
||||
label: "Pico (Standard GPIO)".into(),
|
||||
},
|
||||
DriverItem {
|
||||
value: 2,
|
||||
label: "Pimoroni (RGB)".into(),
|
||||
},
|
||||
DriverItem {
|
||||
value: 3,
|
||||
label: "WS2812 (Neopixel)".into(),
|
||||
},
|
||||
DriverItem {
|
||||
value: 5,
|
||||
label: "ESP32 Neopixel".into(),
|
||||
},
|
||||
];
|
||||
// Prepare Driver Options
|
||||
let drivers: Vec<DriverSelectOption> = LedDriverType::all()
|
||||
.iter()
|
||||
.map(|driver| DriverSelectOption {
|
||||
driver_type: *driver,
|
||||
label: driver.label(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Determine initial vendor selection
|
||||
// Determine Initial State
|
||||
let current_vid: SharedString = config
|
||||
.map(|c| c.vid.clone().into())
|
||||
.unwrap_or_else(|| "CAFE".into());
|
||||
@@ -120,22 +114,15 @@ impl ConfigView {
|
||||
.unwrap_or_else(|| "10".into());
|
||||
let current_brightness = config.map(|c| c.led_brightness as f32).unwrap_or(8.0);
|
||||
|
||||
let mut initial_vendor_idx = 0; // Default to first item (Custom)
|
||||
let mut is_custom_vendor = true;
|
||||
// Identify Preset
|
||||
let initial_preset = UsbIdentityPreset::from_vid_pid(¤t_vid, ¤t_pid);
|
||||
let is_custom_vendor = initial_preset == UsbIdentityPreset::Custom;
|
||||
|
||||
for (i, vendor) in VENDORS.iter().enumerate() {
|
||||
// Check matching VID/PID, but skip the generic "custom" entries if they don't have specific values
|
||||
if vendor.value == "custom" && vendor.vid.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if vendor.vid.eq_ignore_ascii_case(current_vid.as_ref())
|
||||
&& vendor.pid.eq_ignore_ascii_case(current_pid.as_ref())
|
||||
{
|
||||
initial_vendor_idx = i;
|
||||
is_custom_vendor = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Find index for the SelectState
|
||||
let initial_vendor_idx = UsbIdentityPreset::all()
|
||||
.iter()
|
||||
.position(|p| *p == initial_preset)
|
||||
.unwrap_or(0);
|
||||
|
||||
let vendor_select = cx.new(|cx| {
|
||||
SelectState::new(
|
||||
@@ -154,11 +141,17 @@ impl ConfigView {
|
||||
let led_gpio_input =
|
||||
cx.new(|cx| InputState::new(window, cx).default_value(current_led_gpio.clone()));
|
||||
|
||||
let _initial_driver_idx = config.and_then(|c| c.led_driver).unwrap_or(0) as usize;
|
||||
// Identify Driver
|
||||
let current_driver_val = config.and_then(|c| c.led_driver).unwrap_or(0);
|
||||
let initial_driver_idx = LedDriverType::all()
|
||||
.iter()
|
||||
.position(|d| d.value() == current_driver_val)
|
||||
.unwrap_or(0);
|
||||
|
||||
let led_driver_select = cx.new(|cx| {
|
||||
SelectState::new(
|
||||
drivers,
|
||||
Some(gpui_component::IndexPath::default()),
|
||||
Some(gpui_component::IndexPath::default().row(initial_driver_idx)),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
@@ -168,18 +161,20 @@ impl ConfigView {
|
||||
&vendor_select,
|
||||
window,
|
||||
|this: &mut Self, _, event, window, cx| {
|
||||
if let gpui_component::select::SelectEvent::Confirm(Some(value)) = event {
|
||||
if let Some(vendor) = VENDORS.iter().find(|v| value == v.value) {
|
||||
this.is_custom_vendor = vendor.value == "custom";
|
||||
if let gpui_component::select::SelectEvent::Confirm(Some(preset)) = event {
|
||||
let (_, vid_opt, pid_opt) = preset.details();
|
||||
|
||||
if !this.is_custom_vendor {
|
||||
this.vid_input
|
||||
.update(cx, |input, cx| input.set_value(vendor.vid, window, cx));
|
||||
this.pid_input
|
||||
.update(cx, |input, cx| input.set_value(vendor.pid, window, cx));
|
||||
}
|
||||
cx.notify();
|
||||
if let (Some(vid), Some(pid)) = (vid_opt, pid_opt) {
|
||||
this.is_custom_vendor = false;
|
||||
this.vid_input
|
||||
.update(cx, |input, cx| input.set_value(vid, window, cx));
|
||||
this.pid_input
|
||||
.update(cx, |input, cx| input.set_value(pid, window, cx));
|
||||
} else {
|
||||
// Custom selected
|
||||
this.is_custom_vendor = true;
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -259,12 +254,15 @@ impl ConfigView {
|
||||
}
|
||||
}
|
||||
|
||||
// Get Driver Value
|
||||
let driver_idx = self.led_driver_select.read(cx).selected_index(cx);
|
||||
if let Some(idx) = driver_idx {
|
||||
// Assuming values are 0, 1, 2 matches index
|
||||
let val = idx.row as u8;
|
||||
if Some(val) != current_config.led_driver {
|
||||
changes.led_driver = Some(val);
|
||||
// Map index back to enum value safely
|
||||
if let Some(driver) = LedDriverType::all().get(idx.row) {
|
||||
let val = driver.value();
|
||||
if Some(val) != current_config.led_driver {
|
||||
changes.led_driver = Some(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user