Show remote activity on iPhone Home
This commit is contained in:
@@ -8,6 +8,12 @@ use std::{error::Error, fmt, sync::Arc};
|
||||
use ironstorage::{
|
||||
config::ConfigError,
|
||||
mobile::{self, MobileShellState as StorageShellState, MobileTab as StorageTab},
|
||||
mobile_home::{
|
||||
self, MobileHomeChangeKind as StorageHomeChangeKind,
|
||||
MobileHomeChangeStatus as StorageHomeChangeStatus, MobileHomeError as StorageHomeError,
|
||||
MobileHomeErrorKind as StorageHomeErrorKind, MobileHomeFreshness as StorageHomeFreshness,
|
||||
MobileHomePhase as StorageHomePhase,
|
||||
},
|
||||
mobile_onboarding::{
|
||||
self, MobileOnboardingError as StorageOnboardingError,
|
||||
MobileOnboardingErrorKind as StorageOnboardingErrorKind,
|
||||
@@ -97,6 +103,284 @@ pub struct MobileShell {
|
||||
pub pages: Vec<MobilePage>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileHomeFreshness {
|
||||
NeverRefreshed,
|
||||
Cached,
|
||||
Current,
|
||||
}
|
||||
|
||||
impl From<StorageHomeFreshness> for MobileHomeFreshness {
|
||||
fn from(freshness: StorageHomeFreshness) -> Self {
|
||||
match freshness {
|
||||
StorageHomeFreshness::NeverRefreshed => Self::NeverRefreshed,
|
||||
StorageHomeFreshness::Cached => Self::Cached,
|
||||
StorageHomeFreshness::Current => Self::Current,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileHomeChangeKind {
|
||||
PasswordEntry,
|
||||
RecipientPolicy,
|
||||
RecipientSignature,
|
||||
RepositoryFile,
|
||||
}
|
||||
|
||||
impl From<StorageHomeChangeKind> for MobileHomeChangeKind {
|
||||
fn from(kind: StorageHomeChangeKind) -> Self {
|
||||
match kind {
|
||||
StorageHomeChangeKind::PasswordEntry => Self::PasswordEntry,
|
||||
StorageHomeChangeKind::RecipientPolicy => Self::RecipientPolicy,
|
||||
StorageHomeChangeKind::RecipientSignature => Self::RecipientSignature,
|
||||
StorageHomeChangeKind::RepositoryFile => Self::RepositoryFile,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileHomeChangeStatus {
|
||||
Added,
|
||||
Modified,
|
||||
Deleted,
|
||||
}
|
||||
|
||||
impl From<StorageHomeChangeStatus> for MobileHomeChangeStatus {
|
||||
fn from(status: StorageHomeChangeStatus) -> Self {
|
||||
match status {
|
||||
StorageHomeChangeStatus::Added => Self::Added,
|
||||
StorageHomeChangeStatus::Modified => Self::Modified,
|
||||
StorageHomeChangeStatus::Deleted => Self::Deleted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileHomeSummaryRow {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
pub system_image: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileHomeChange {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
pub system_image: String,
|
||||
pub kind: MobileHomeChangeKind,
|
||||
pub status: MobileHomeChangeStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileHomeCommit {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
pub system_image: String,
|
||||
pub timestamp: i64,
|
||||
pub changes: Vec<MobileHomeChange>,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileHomeNotice {
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
pub system_image: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileHomePage {
|
||||
pub freshness: MobileHomeFreshness,
|
||||
pub refreshed_at: Option<i64>,
|
||||
pub summaries: Vec<MobileHomeSummaryRow>,
|
||||
pub incoming: Vec<MobileHomeCommit>,
|
||||
pub outgoing: Vec<MobileHomeCommit>,
|
||||
pub incoming_total: u32,
|
||||
pub outgoing_total: u32,
|
||||
pub notice: Option<MobileHomeNotice>,
|
||||
}
|
||||
|
||||
impl From<mobile_home::MobileHomePage> for MobileHomePage {
|
||||
fn from(page: mobile_home::MobileHomePage) -> Self {
|
||||
Self {
|
||||
freshness: page.freshness().into(),
|
||||
refreshed_at: page.refreshed_at(),
|
||||
summaries: page
|
||||
.summaries()
|
||||
.iter()
|
||||
.map(|row| MobileHomeSummaryRow {
|
||||
id: row.id().to_owned(),
|
||||
title: row.title().to_owned(),
|
||||
detail: row.detail().to_owned(),
|
||||
system_image: row.system_image().to_owned(),
|
||||
})
|
||||
.collect(),
|
||||
incoming: page.incoming().iter().map(mobile_home_commit).collect(),
|
||||
outgoing: page.outgoing().iter().map(mobile_home_commit).collect(),
|
||||
incoming_total: u32::try_from(page.incoming_total()).unwrap_or(u32::MAX),
|
||||
outgoing_total: u32::try_from(page.outgoing_total()).unwrap_or(u32::MAX),
|
||||
notice: page.notice().map(|notice| MobileHomeNotice {
|
||||
title: notice.title().to_owned(),
|
||||
detail: notice.detail().to_owned(),
|
||||
system_image: notice.system_image().to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mobile_home_commit(commit: &mobile_home::MobileHomeCommit) -> MobileHomeCommit {
|
||||
MobileHomeCommit {
|
||||
id: commit.id().to_owned(),
|
||||
title: commit.title().to_owned(),
|
||||
detail: commit.detail().to_owned(),
|
||||
system_image: commit.system_image().to_owned(),
|
||||
timestamp: commit.timestamp(),
|
||||
changes: commit
|
||||
.changes()
|
||||
.iter()
|
||||
.map(|change| MobileHomeChange {
|
||||
id: change.id().to_owned(),
|
||||
title: change.title().to_owned(),
|
||||
detail: change.detail().to_owned(),
|
||||
system_image: change.system_image().to_owned(),
|
||||
kind: change.kind().into(),
|
||||
status: change.status().into(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileHomePhase {
|
||||
Validating,
|
||||
Authenticating,
|
||||
Receiving,
|
||||
Integrating,
|
||||
Finishing,
|
||||
}
|
||||
|
||||
impl From<StorageHomePhase> for MobileHomePhase {
|
||||
fn from(phase: StorageHomePhase) -> Self {
|
||||
match phase {
|
||||
StorageHomePhase::Validating => Self::Validating,
|
||||
StorageHomePhase::Authenticating => Self::Authenticating,
|
||||
StorageHomePhase::Receiving => Self::Receiving,
|
||||
StorageHomePhase::Integrating => Self::Integrating,
|
||||
StorageHomePhase::Finishing => Self::Finishing,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileHomeProgress {
|
||||
pub phase: MobileHomePhase,
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileHomeErrorKind {
|
||||
MissingConfiguration,
|
||||
Configuration,
|
||||
Authentication,
|
||||
Conflict,
|
||||
DirtyLocalChanges,
|
||||
Offline,
|
||||
Interrupted,
|
||||
SecureStorage,
|
||||
Repository,
|
||||
PartialProgress,
|
||||
}
|
||||
|
||||
impl From<StorageHomeErrorKind> for MobileHomeErrorKind {
|
||||
fn from(kind: StorageHomeErrorKind) -> Self {
|
||||
match kind {
|
||||
StorageHomeErrorKind::MissingConfiguration => Self::MissingConfiguration,
|
||||
StorageHomeErrorKind::Configuration => Self::Configuration,
|
||||
StorageHomeErrorKind::Authentication => Self::Authentication,
|
||||
StorageHomeErrorKind::Conflict => Self::Conflict,
|
||||
StorageHomeErrorKind::DirtyLocalChanges => Self::DirtyLocalChanges,
|
||||
StorageHomeErrorKind::Offline => Self::Offline,
|
||||
StorageHomeErrorKind::Interrupted => Self::Interrupted,
|
||||
StorageHomeErrorKind::SecureStorage => Self::SecureStorage,
|
||||
StorageHomeErrorKind::Repository => Self::Repository,
|
||||
StorageHomeErrorKind::PartialProgress => Self::PartialProgress,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, uniffi::Error)]
|
||||
pub enum MobileHomeFfiError {
|
||||
Failed {
|
||||
kind: MobileHomeErrorKind,
|
||||
title: String,
|
||||
detail: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Display for MobileHomeFfiError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Failed { title, detail, .. } => write!(formatter, "{title}: {detail}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for MobileHomeFfiError {}
|
||||
|
||||
impl From<StorageHomeError> for MobileHomeFfiError {
|
||||
fn from(error: StorageHomeError) -> Self {
|
||||
Self::Failed {
|
||||
kind: error.kind().into(),
|
||||
title: error.title().to_owned(),
|
||||
detail: error.detail().to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct MobileHomeOperation {
|
||||
operation: mobile_home::MobileHomeOperation,
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
impl MobileHomeOperation {
|
||||
pub fn progress(&self) -> MobileHomeProgress {
|
||||
let progress = self.operation.progress();
|
||||
MobileHomeProgress {
|
||||
phase: progress.phase().into(),
|
||||
title: progress.title().to_owned(),
|
||||
detail: progress.detail().to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cached(&self) -> Result<MobileHomePage, MobileHomeFfiError> {
|
||||
self.operation.cached().map(Into::into).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn refresh_if_stale(&self) -> Result<MobileHomePage, MobileHomeFfiError> {
|
||||
self.operation
|
||||
.refresh_if_stale()
|
||||
.map(Into::into)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn refresh(&self) -> Result<MobileHomePage, MobileHomeFfiError> {
|
||||
self.operation.refresh().map(Into::into).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn pull(&self) -> Result<MobileHomePage, MobileHomeFfiError> {
|
||||
self.operation.pull().map(Into::into).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn cancel(&self) {
|
||||
self.operation.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
|
||||
pub enum MobileOnboardingPhase {
|
||||
Validating,
|
||||
@@ -301,6 +585,13 @@ pub fn set_selected_mobile_tab(tab: MobileTab) -> Result<(), MobilePreferenceErr
|
||||
mobile::store_selected_tab(tab.into()).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn mobile_home_operation() -> Arc<MobileHomeOperation> {
|
||||
Arc::new(MobileHomeOperation {
|
||||
operation: mobile_home::MobileHomeOperation::default(),
|
||||
})
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn mobile_onboarding_operation(
|
||||
server_url: String,
|
||||
@@ -333,7 +624,10 @@ pub fn replace_configured_mobile_application_token(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{MobileOnboardingErrorKind, MobileOnboardingFfiError, MobileShellState, MobileTab};
|
||||
use super::{
|
||||
MobileHomePhase, MobileOnboardingErrorKind, MobileOnboardingFfiError, MobileShellState,
|
||||
MobileTab,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn bridge_reads_product_name_from_storage_crate() {
|
||||
@@ -374,4 +668,12 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn home_operation_exposes_typed_progress_and_cancellation() {
|
||||
let operation = super::mobile_home_operation();
|
||||
assert_eq!(operation.progress().phase, MobileHomePhase::Validating);
|
||||
operation.cancel();
|
||||
assert_eq!(operation.progress().phase, MobileHomePhase::Validating);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user