Add visible styled keyboard quick reference in bottom panel
This commit is contained in:
@@ -39,6 +39,14 @@ pub enum FormAction {
|
||||
Feedback(String),
|
||||
}
|
||||
|
||||
/// Public, secret-free summary of keyboard capabilities for the active form.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct FormKeyContext {
|
||||
pub enter_action: Option<&'static str>,
|
||||
pub supports_tab: bool,
|
||||
pub supports_selection: bool,
|
||||
}
|
||||
|
||||
enum Form {
|
||||
Setup {
|
||||
password: SecretInput,
|
||||
@@ -153,6 +161,67 @@ impl FormController {
|
||||
matches!(self.active, Some(Form::DraftReview))
|
||||
}
|
||||
|
||||
/// Describes only keys handled by the active form; never exposes form data.
|
||||
pub fn key_context(&self) -> Option<FormKeyContext> {
|
||||
self.active.as_ref().map(|form| match form {
|
||||
Form::Setup { .. } => FormKeyContext {
|
||||
enter_action: Some("next / submit"),
|
||||
supports_tab: true,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::Create { .. } => FormKeyContext {
|
||||
enter_action: Some("next / submit"),
|
||||
supports_tab: true,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::Rename { .. } => FormKeyContext {
|
||||
enter_action: Some("submit"),
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::Import { .. } => FormKeyContext {
|
||||
enter_action: Some("submit"),
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::Confirm(_) => FormKeyContext {
|
||||
enter_action: Some("confirm"),
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::DraftReview => FormKeyContext {
|
||||
enter_action: None,
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::DeliveryPath { .. } => FormKeyContext {
|
||||
enter_action: Some("prepare file"),
|
||||
supports_tab: true,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::ReissuePassword { .. } => FormKeyContext {
|
||||
enter_action: Some("submit password"),
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::Backups { items, .. } => FormKeyContext {
|
||||
enter_action: (!items.is_empty()).then_some("preview restore"),
|
||||
supports_tab: false,
|
||||
supports_selection: !items.is_empty(),
|
||||
},
|
||||
Form::Restore(_) => FormKeyContext {
|
||||
enter_action: Some("confirm restore"),
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
},
|
||||
Form::Disclosure { .. } => FormKeyContext {
|
||||
enter_action: None,
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn qr_output(&self) -> Option<&QrCodeOutput> {
|
||||
match self.active.as_ref() {
|
||||
Some(Form::Disclosure { qr, .. }) => Some(qr),
|
||||
@@ -888,6 +957,64 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::backup::{BackupReason, HistoricalApplyStatus};
|
||||
|
||||
#[test]
|
||||
fn key_context_matches_tabbed_forms_and_inert_draft_review() {
|
||||
let mut form = FormController::default();
|
||||
form.open_setup();
|
||||
assert_eq!(
|
||||
form.key_context(),
|
||||
Some(FormKeyContext {
|
||||
enter_action: Some("next / submit"),
|
||||
supports_tab: true,
|
||||
supports_selection: false,
|
||||
})
|
||||
);
|
||||
form.open_create();
|
||||
assert!(form.key_context().unwrap().supports_tab);
|
||||
assert_eq!(
|
||||
form.key_context().unwrap().enter_action,
|
||||
Some("next / submit")
|
||||
);
|
||||
form.open_draft_review();
|
||||
assert_eq!(
|
||||
form.key_context(),
|
||||
Some(FormKeyContext {
|
||||
enter_action: None,
|
||||
supports_tab: false,
|
||||
supports_selection: false,
|
||||
})
|
||||
);
|
||||
assert!(matches!(form.handle_key(KeyCode::Enter), FormAction::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delivery_path_and_backup_selection_expose_their_actual_keys() {
|
||||
let identity = PublicKey::from_bytes([0x61; 32]);
|
||||
let mut form = FormController::default();
|
||||
form.open_delivery(identity, false);
|
||||
assert!(form.key_context().unwrap().supports_tab);
|
||||
assert_eq!(
|
||||
form.key_context().unwrap().enter_action,
|
||||
Some("prepare file")
|
||||
);
|
||||
form.open_backups(vec![ArchiveSummary {
|
||||
file_name: "backup.zip".to_owned(),
|
||||
created_at_utc: "2026-01-01T00:00:00Z".to_owned(),
|
||||
reason: BackupReason::Manual,
|
||||
historical_apply: HistoricalApplyStatus::Unknown,
|
||||
}]);
|
||||
assert_eq!(
|
||||
form.key_context(),
|
||||
Some(FormKeyContext {
|
||||
enter_action: Some("preview restore"),
|
||||
supports_tab: false,
|
||||
supports_selection: true,
|
||||
})
|
||||
);
|
||||
form.open_backups(Vec::new());
|
||||
assert_eq!(form.key_context().unwrap().enter_action, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setup_password_is_masked_confirmation_required_and_secret_command_has_no_debug() {
|
||||
let mut form = FormController::default();
|
||||
|
||||
Reference in New Issue
Block a user