Implement structured desktop entry viewer

This commit is contained in:
2026-08-10 16:27:47 +02:00
parent f363081fa2
commit f6e74cbb1d
3 changed files with 428 additions and 11 deletions

View File

@@ -12,14 +12,25 @@ use ironstorage::{
pub struct EntryEditor {
document: EntryDocument,
revealed: BTreeSet<EntryFieldId>,
focused: Option<EntryFieldId>,
dirty: bool,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FieldNavigation {
First,
Last,
Next,
Previous,
}
impl EntryEditor {
pub fn new(document: EntryDocument) -> Self {
let focused = document.fields().first().map(EntryField::id);
Self {
document,
revealed: BTreeSet::new(),
focused,
dirty: false,
}
}
@@ -44,6 +55,44 @@ impl EntryEditor {
self.revealed.contains(&id)
}
pub fn focused(&self) -> Option<EntryFieldId> {
self.focused
}
pub fn focused_ratio(&self) -> f32 {
let fields = self.document.fields();
self.focused
.and_then(|id| fields.iter().position(|field| field.id() == id))
.map_or(0.0, |index| {
index as f32 / fields.len().saturating_sub(1).max(1) as f32
})
}
pub fn select(&mut self, id: EntryFieldId) {
if self.document.field(id).is_some() {
self.focused = Some(id);
}
}
pub fn navigate(&mut self, navigation: FieldNavigation) {
let fields = self.document.fields();
if fields.is_empty() {
self.focused = None;
return;
}
let current = self
.focused
.and_then(|id| fields.iter().position(|field| field.id() == id))
.unwrap_or(0);
let index = match navigation {
FieldNavigation::First => 0,
FieldNavigation::Last => fields.len() - 1,
FieldNavigation::Next => (current + 1).min(fields.len() - 1),
FieldNavigation::Previous => current.saturating_sub(1),
};
self.focused = Some(fields[index].id());
}
pub fn toggle_reveal(&mut self, id: EntryFieldId) -> Result<(), DocumentError> {
let field = self
.document
@@ -81,14 +130,27 @@ impl EntryEditor {
.position(|field| field.id() == id)
})
.map_or(self.document.fields().len(), |index| index + 1);
self.document.add(index, EntryFieldDraft::blank())?;
self.focused = Some(self.document.add(index, EntryFieldDraft::blank())?);
self.dirty = true;
Ok(())
}
pub fn remove(&mut self, id: EntryFieldId) -> Result<(), DocumentError> {
let index = self
.document
.fields()
.iter()
.position(|field| field.id() == id)
.ok_or(DocumentError::UnknownField { id })?;
self.document.remove(id)?;
self.revealed.remove(&id);
if self.focused == Some(id) {
self.focused = self
.document
.fields()
.get(index.min(self.document.fields().len().saturating_sub(1)))
.map(EntryField::id);
}
self.dirty = true;
Ok(())
}
@@ -148,6 +210,7 @@ impl fmt::Debug for EntryEditor {
.debug_struct("EntryEditor")
.field("document", &self.document)
.field("revealed", &self.revealed)
.field("focused", &self.focused)
.field("dirty", &self.dirty)
.finish()
}