Build native iPhone application shell
This commit is contained in:
@@ -3,17 +3,181 @@
|
||||
|
||||
//! Mechanical UniFFI exports for Apple presentation code.
|
||||
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
use ironstorage::{
|
||||
config::ConfigError,
|
||||
mobile::{self, MobileShellState as StorageShellState, MobileTab as StorageTab},
|
||||
};
|
||||
|
||||
uniffi::setup_scaffolding!();
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileTab {
|
||||
Home,
|
||||
Passwords,
|
||||
Totp,
|
||||
Preferences,
|
||||
}
|
||||
|
||||
impl From<StorageTab> for MobileTab {
|
||||
fn from(tab: StorageTab) -> Self {
|
||||
match tab {
|
||||
StorageTab::Home => Self::Home,
|
||||
StorageTab::Passwords => Self::Passwords,
|
||||
StorageTab::Totp => Self::Totp,
|
||||
StorageTab::Preferences => Self::Preferences,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MobileTab> for StorageTab {
|
||||
fn from(tab: MobileTab) -> Self {
|
||||
match tab {
|
||||
MobileTab::Home => Self::Home,
|
||||
MobileTab::Passwords => Self::Passwords,
|
||||
MobileTab::Totp => Self::Totp,
|
||||
MobileTab::Preferences => Self::Preferences,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileShellState {
|
||||
Loading,
|
||||
Empty,
|
||||
Ready,
|
||||
Locked,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl From<StorageShellState> for MobileShellState {
|
||||
fn from(state: StorageShellState) -> Self {
|
||||
match state {
|
||||
StorageShellState::Loading => Self::Loading,
|
||||
StorageShellState::Empty => Self::Empty,
|
||||
StorageShellState::Ready => Self::Ready,
|
||||
StorageShellState::Locked => Self::Locked,
|
||||
StorageShellState::Error => Self::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MobileShellState> for StorageShellState {
|
||||
fn from(state: MobileShellState) -> Self {
|
||||
match state {
|
||||
MobileShellState::Loading => Self::Loading,
|
||||
MobileShellState::Empty => Self::Empty,
|
||||
MobileShellState::Ready => Self::Ready,
|
||||
MobileShellState::Locked => Self::Locked,
|
||||
MobileShellState::Error => Self::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobilePage {
|
||||
pub tab: MobileTab,
|
||||
pub title: String,
|
||||
pub system_image: String,
|
||||
pub selected_system_image: String,
|
||||
pub state: MobileShellState,
|
||||
pub state_title: String,
|
||||
pub state_detail: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileShell {
|
||||
pub selected_tab: MobileTab,
|
||||
pub pages: Vec<MobilePage>,
|
||||
}
|
||||
|
||||
impl From<mobile::MobileShell> for MobileShell {
|
||||
fn from(shell: mobile::MobileShell) -> Self {
|
||||
Self {
|
||||
selected_tab: shell.selected_tab().into(),
|
||||
pages: shell
|
||||
.pages()
|
||||
.iter()
|
||||
.map(|page| MobilePage {
|
||||
tab: page.tab().into(),
|
||||
title: page.title().to_owned(),
|
||||
system_image: page.system_image().to_owned(),
|
||||
selected_system_image: page.selected_system_image().to_owned(),
|
||||
state: page.state().into(),
|
||||
state_title: page.state_title().to_owned(),
|
||||
state_detail: page.state_detail().to_owned(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, uniffi::Error)]
|
||||
pub enum MobilePreferenceError {
|
||||
Configuration { message: String },
|
||||
}
|
||||
|
||||
impl fmt::Display for MobilePreferenceError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Configuration { message } => formatter.write_str(message),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for MobilePreferenceError {}
|
||||
|
||||
impl From<ConfigError> for MobilePreferenceError {
|
||||
fn from(error: ConfigError) -> Self {
|
||||
Self::Configuration {
|
||||
message: error.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn product_name() -> String {
|
||||
ironstorage::PRODUCT_NAME.to_owned()
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn mobile_shell() -> MobileShell {
|
||||
mobile::MobileShell::load().into()
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn mobile_shell_fixture(state: MobileShellState) -> MobileShell {
|
||||
mobile::MobileShell::fixture(state.into()).into()
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn set_selected_mobile_tab(tab: MobileTab) -> Result<(), MobilePreferenceError> {
|
||||
mobile::store_selected_tab(tab.into()).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{MobileShellState, MobileTab};
|
||||
|
||||
#[test]
|
||||
fn bridge_reads_product_name_from_storage_crate() {
|
||||
assert_eq!(super::product_name(), ironstorage::PRODUCT_NAME);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bridge_exposes_every_view_ready_shell_fixture() {
|
||||
for state in [
|
||||
MobileShellState::Loading,
|
||||
MobileShellState::Empty,
|
||||
MobileShellState::Ready,
|
||||
MobileShellState::Locked,
|
||||
MobileShellState::Error,
|
||||
] {
|
||||
let shell = super::mobile_shell_fixture(state);
|
||||
assert_eq!(shell.selected_tab, MobileTab::Home);
|
||||
assert_eq!(shell.pages.len(), 4);
|
||||
assert!(shell.pages.iter().all(|page| page.state == state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user