Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions crates/prism-client/src/config/servers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ fn hsl_to_rgb(h: f64, s: f64, l: f64) -> [u8; 3] {
]
}

// ---------------------------------------------------------------------------
// ServerStatus
// ---------------------------------------------------------------------------

/// Derived connection status for UI rendering.
/// TODO: Replace heuristic derivation with runtime discovery/ping probe.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ServerStatus {
Online,
Sleeping,
Unreachable,
}

// ---------------------------------------------------------------------------
// SavedServer
// ---------------------------------------------------------------------------
Expand All @@ -75,6 +88,14 @@ pub struct SavedServer {
pub last_resolution: Option<(u32, u32)>,
pub last_codec: Option<String>,
pub created_at: u64,
#[serde(default)]
pub os_label: Option<String>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub wol_supported: bool,
#[serde(default)]
pub last_latency_ms: Option<u32>,
}

impl SavedServer {
Expand All @@ -98,6 +119,33 @@ impl SavedServer {
last_resolution: None,
last_codec: None,
created_at,
os_label: None,
tags: Vec::new(),
wol_supported: false,
last_latency_ms: None,
}
}

/// Heuristic status until real-time probing is implemented.
pub fn derived_status(&self) -> ServerStatus {
const SECS_6H: u64 = 6 * 60 * 60;
const SECS_7D: u64 = 7 * 24 * 60 * 60;
match self.last_connected {
None => ServerStatus::Unreachable,
Some(epoch_secs) => {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
let age = now.saturating_sub(epoch_secs);
if age < SECS_6H {
ServerStatus::Online
} else if age < SECS_7D {
ServerStatus::Sleeping
} else {
ServerStatus::Unreachable
}
}
}
}
}
Expand Down
28 changes: 14 additions & 14 deletions crates/prism-client/src/ui/launcher/card_grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ impl CardGrid {
.cards
.iter()
.enumerate()
.filter_map(|(index, card)| card.matches_filter(self.active_filter).then_some(index))
.filter_map(|(index, card)| card.matches_filter(&self.active_filter).then_some(index))
.collect();
}

Expand All @@ -155,7 +155,7 @@ impl CardGrid {
CardFilter::Dormant,
CardFilter::New,
] {
let label = filter.label(self.cards.len());
let label = filter.label();
let w = theme::text_width(&label, 11.0) + 28.0;
let rect = Rect::new(x, y, w, FILTER_H);
self.filter_chip_rects.push((filter, rect));
Expand Down Expand Up @@ -292,8 +292,8 @@ impl Widget for CardGrid {
fn paint(&self, ctx: &mut PaintContext) {
if self.show_filters {
for (filter, rect) in &self.filter_chip_rects {
let active = *filter == self.active_filter;
let hovered = self.hovered_filter == Some(*filter);
let active = filter == &self.active_filter;
let hovered = self.hovered_filter.as_ref() == Some(filter);

let pill_radius = 16.0;
if active {
Expand All @@ -312,10 +312,10 @@ impl Widget for CardGrid {
ctx.push_text_run(TextRun {
x: rect.x + 14.0,
y: rect.y + 10.0,
text: filter.label(self.cards.len()),
text: filter.label(),
font_size: 11.0,
color: [1.0, 1.0, 1.0, 1.0],
monospace: false,
..Default::default()
});
} else {
// Light frosted pill for inactive
Expand All @@ -331,10 +331,10 @@ impl Widget for CardGrid {
ctx.push_text_run(TextRun {
x: rect.x + 14.0,
y: rect.y + 10.0,
text: filter.label(self.cards.len()),
text: filter.label(),
font_size: 11.0,
color: theme::LT_TEXT_SECONDARY,
monospace: false,
..Default::default()
});
}
}
Expand All @@ -352,7 +352,7 @@ impl Widget for CardGrid {
text: "No saved desktops match this filter.".to_string(),
font_size: 12.0,
color: theme::LT_TEXT_MUTED,
monospace: false,
..Default::default()
});
}

Expand Down Expand Up @@ -398,7 +398,7 @@ impl Widget for CardGrid {
text: plus.to_string(),
font_size: 28.0,
color: theme::PRIMARY_BLUE,
monospace: false,
..Default::default()
});

let title = "Add New Connection";
Expand All @@ -408,7 +408,7 @@ impl Widget for CardGrid {
text: title.to_string(),
font_size: 14.0,
color: theme::LT_TEXT_PRIMARY,
monospace: false,
..Default::default()
});

let body = "Manual IP or Network Discovery";
Expand All @@ -418,7 +418,7 @@ impl Widget for CardGrid {
text: body.to_string(),
font_size: 11.0,
color: theme::LT_TEXT_MUTED,
monospace: false,
..Default::default()
});
}
}
Expand All @@ -429,7 +429,7 @@ impl Widget for CardGrid {
self.hovered_filter = self
.filter_chip_rects
.iter()
.find_map(|(filter, rect)| rect.contains(*x, *y).then_some(*filter));
.find_map(|(filter, rect)| rect.contains(*x, *y).then_some(filter.clone()));
}
UiEvent::MouseDown {
x,
Expand All @@ -442,7 +442,7 @@ impl Widget for CardGrid {
.find(|(_, rect)| rect.contains(*x, *y))
{
if self.active_filter != *filter {
self.active_filter = *filter;
self.active_filter = filter.clone();
self.recompute_layout();
}
return EventResponse::Consumed;
Expand Down
8 changes: 4 additions & 4 deletions crates/prism-client/src/ui/launcher/nav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ impl Widget for LauncherNav {
text: "PRISM".into(),
font_size: 20.0,
color: theme::LT_TEXT_PRIMARY,
monospace: false,
..Default::default()
});
ctx.push_text_run(TextRun {
x: self.rect.x + 18.0,
y: self.rect.y + 48.0,
text: "Remote client".into(),
font_size: 11.0,
color: theme::LT_TEXT_MUTED,
monospace: false,
..Default::default()
});

for (tab, rect) in &self.primary_items {
Expand All @@ -110,7 +110,7 @@ impl Widget for LauncherNav {
} else {
theme::LT_TEXT_SECONDARY
},
monospace: false,
..Default::default()
});
}

Expand All @@ -132,7 +132,7 @@ impl Widget for LauncherNav {
} else {
theme::LT_TEXT_SECONDARY
},
monospace: false,
..Default::default()
});
}

Expand Down
16 changes: 8 additions & 8 deletions crates/prism-client/src/ui/launcher/profiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ impl Widget for ProfilesPanel {
text: "Presets".into(),
font_size: theme::FONT_LABEL,
color: theme::LT_TEXT_MUTED,
monospace: false,
..Default::default()
});

for (idx, row) in self.list_rows.iter().enumerate() {
Expand Down Expand Up @@ -451,7 +451,7 @@ impl Widget for ProfilesPanel {
} else {
theme::LT_TEXT_SECONDARY
},
monospace: false,
..Default::default()
});

let subtitle = if profile.builtin {
Expand All @@ -474,7 +474,7 @@ impl Widget for ProfilesPanel {
text: subtitle,
font_size: 11.0,
color: theme::LT_TEXT_MUTED,
monospace: false,
..Default::default()
});
}

Expand All @@ -493,7 +493,7 @@ impl Widget for ProfilesPanel {
text: draft.name.clone(),
font_size: theme::FONT_HERO,
color: theme::LT_TEXT_PRIMARY,
monospace: false,
..Default::default()
});

if draft.builtin {
Expand All @@ -510,7 +510,7 @@ impl Widget for ProfilesPanel {
text: "SYSTEM".to_string(),
font_size: 10.0,
color: theme::launcher_chip_text_color(theme::ChipTone::Success),
monospace: false,
..Default::default()
});
}

Expand All @@ -525,7 +525,7 @@ impl Widget for ProfilesPanel {
text: "UNSAVED".to_string(),
font_size: 10.0,
color: theme::launcher_chip_text_color(theme::ChipTone::Warning),
monospace: false,
..Default::default()
});
}

Expand All @@ -535,7 +535,7 @@ impl Widget for ProfilesPanel {
text: "Optimized for high-performance interaction".to_string(),
font_size: theme::FONT_BODY,
color: theme::LT_TEXT_SECONDARY,
monospace: false,
..Default::default()
});
}

Expand All @@ -552,7 +552,7 @@ impl Widget for ProfilesPanel {
text: text.to_string(),
font_size: theme::FONT_CAPTION,
color: theme::LT_TEXT_MUTED,
monospace: false,
..Default::default()
});
};

Expand Down
4 changes: 2 additions & 2 deletions crates/prism-client/src/ui/launcher/quick_connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl Widget for QuickConnect {
text: title.into(),
font_size: theme::FONT_HERO,
color: theme::LT_TEXT_PRIMARY,
monospace: false,
..Default::default()
});

let subtitle = "Enter a hostname or IP address";
Expand All @@ -89,7 +89,7 @@ impl Widget for QuickConnect {
text: subtitle.into(),
font_size: theme::FONT_BODY,
color: theme::LT_TEXT_MUTED,
monospace: false,
..Default::default()
});

self.address_input.paint(ctx);
Expand Down
Loading
Loading