app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 5f91de8bc6664d32c71a174c972117e14b1f7b35
parent d8bd378799edd344daf832809aecc310af2f9580
Author: triesap <triesap@radroots.dev>
Date:   Mon, 19 Jan 2026 00:52:56 +0000

app-core: add notifications types

- define resolve status and notification permission enums
- add dialog and notification option types for notifications
- introduce async notifications trait for core operations
- add unit tests for enum string roundtrips

Diffstat:
Mcrates/core/src/notifications/mod.rs | 10++++++++++
Acrates/core/src/notifications/types.rs | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/crates/core/src/notifications/mod.rs b/crates/core/src/notifications/mod.rs @@ -1,3 +1,13 @@ pub mod error; +pub mod types; pub use error::{RadrootsClientNotificationsError, RadrootsClientNotificationsErrorMessage}; +pub use types::{ + RadrootsClientNotifications, + RadrootsClientNotificationsConfig, + RadrootsClientNotificationsDialogConfirmOpts, + RadrootsClientNotificationsPermission, + RadrootsClientNotificationsResult, + RadrootsClientNotificationsSendOptions, + RadrootsClientResolveStatus, +}; diff --git a/crates/core/src/notifications/types.rs b/crates/core/src/notifications/types.rs @@ -0,0 +1,143 @@ +use async_trait::async_trait; + +use super::RadrootsClientNotificationsError; + +pub type RadrootsClientNotificationsResult<T> = + Result<T, RadrootsClientNotificationsError>; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RadrootsClientResolveStatus { + Info, + Warning, + Error, + Success, +} + +impl RadrootsClientResolveStatus { + pub const fn as_str(self) -> &'static str { + match self { + RadrootsClientResolveStatus::Info => "info", + RadrootsClientResolveStatus::Warning => "warning", + RadrootsClientResolveStatus::Error => "error", + RadrootsClientResolveStatus::Success => "success", + } + } + + pub fn parse(value: &str) -> Option<Self> { + match value { + "info" => Some(RadrootsClientResolveStatus::Info), + "warning" => Some(RadrootsClientResolveStatus::Warning), + "error" => Some(RadrootsClientResolveStatus::Error), + "success" => Some(RadrootsClientResolveStatus::Success), + _ => None, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RadrootsClientNotificationsPermission { + Granted, + Denied, + Default, + Unavailable, +} + +impl RadrootsClientNotificationsPermission { + pub const fn as_str(self) -> &'static str { + match self { + RadrootsClientNotificationsPermission::Granted => "granted", + RadrootsClientNotificationsPermission::Denied => "denied", + RadrootsClientNotificationsPermission::Default => "default", + RadrootsClientNotificationsPermission::Unavailable => "unavailable", + } + } + + pub fn parse(value: &str) -> Option<Self> { + match value { + "granted" => Some(RadrootsClientNotificationsPermission::Granted), + "denied" => Some(RadrootsClientNotificationsPermission::Denied), + "default" => Some(RadrootsClientNotificationsPermission::Default), + "unavailable" => Some(RadrootsClientNotificationsPermission::Unavailable), + _ => None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RadrootsClientNotificationsDialogConfirmConfig { + pub message: String, + pub title: Option<String>, + pub status: Option<RadrootsClientResolveStatus>, + pub cancel: Option<String>, + pub ok: Option<String>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum RadrootsClientNotificationsDialogConfirmOpts { + Message(String), + Config(RadrootsClientNotificationsDialogConfirmConfig), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RadrootsClientNotificationsSendOptions { + pub id: Option<String>, + pub channel_id: Option<String>, + pub title: Option<String>, + pub body: Option<String>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RadrootsClientNotificationsConfig { + pub app_name: String, +} + +#[async_trait(?Send)] +pub trait RadrootsClientNotifications { + async fn alert( + &self, + message: &str, + title: Option<&str>, + status: Option<RadrootsClientResolveStatus>, + ) -> bool; + async fn confirm( + &self, + opts: RadrootsClientNotificationsDialogConfirmOpts, + ) -> bool; + async fn notify_init( + &self, + ) -> RadrootsClientNotificationsResult<RadrootsClientNotificationsPermission>; + async fn notify_send( + &self, + opts: RadrootsClientNotificationsSendOptions, + ) -> RadrootsClientNotificationsResult<()>; + async fn open_photos( + &self, + ) -> RadrootsClientNotificationsResult<Option<Vec<String>>>; +} + +#[cfg(test)] +mod tests { + use super::{RadrootsClientNotificationsPermission, RadrootsClientResolveStatus}; + + #[test] + fn resolve_status_roundtrip() { + let status = RadrootsClientResolveStatus::Warning; + assert_eq!(status.as_str(), "warning"); + assert_eq!( + RadrootsClientResolveStatus::parse("warning"), + Some(status) + ); + assert_eq!(RadrootsClientResolveStatus::parse("other"), None); + } + + #[test] + fn notification_permission_roundtrip() { + let permission = RadrootsClientNotificationsPermission::Granted; + assert_eq!(permission.as_str(), "granted"); + assert_eq!( + RadrootsClientNotificationsPermission::parse("granted"), + Some(permission) + ); + assert_eq!(RadrootsClientNotificationsPermission::parse("other"), None); + } +}