feat(wallpaper): extend commands with gallery, delete image, and crop
The plugin now exposes gallery retrieval, image deletion and image crop across Android, desktop and mobile. The Rust core and Android bridge are wired to handle these commands, updating state as needed. - Add gallery, delete_image, and set_image_crop commands - across Android, desktop and mobile. - Update permissions, defaults, and schema to enable new commands.
This commit is contained in:
+54
-5
@@ -1,10 +1,59 @@
|
||||
use tauri::{AppHandle, command, Runtime};
|
||||
use tauri::{command, AppHandle, Runtime};
|
||||
|
||||
use crate::models::*;
|
||||
use crate::Result;
|
||||
use crate::WallpaperExt;
|
||||
|
||||
#[command] pub(crate) async fn get_state<R: Runtime>(app: AppHandle<R>) -> Result<WallpaperState> { app.wallpaper().get_state() }
|
||||
#[command] pub(crate) async fn select_images<R: Runtime>(app: AppHandle<R>) -> Result<WallpaperState> { app.wallpaper().select_images() }
|
||||
#[command] pub(crate) async fn set_setting<R: Runtime>(app: AppHandle<R>, name: String, value: bool) -> Result<WallpaperState> { app.wallpaper().set_setting(SettingRequest { name, value }) }
|
||||
#[command] pub(crate) async fn next_wallpaper<R: Runtime>(app: AppHandle<R>) -> Result<WallpaperState> { app.wallpaper().next_wallpaper() }
|
||||
#[command]
|
||||
pub(crate) async fn get_state<R: Runtime>(app: AppHandle<R>) -> Result<WallpaperState> {
|
||||
app.wallpaper().get_state()
|
||||
}
|
||||
#[command]
|
||||
pub(crate) async fn get_gallery<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
offset: usize,
|
||||
limit: usize,
|
||||
) -> Result<GalleryPage> {
|
||||
app.wallpaper()
|
||||
.get_gallery(GalleryRequest { offset, limit })
|
||||
}
|
||||
#[command]
|
||||
pub(crate) async fn select_images<R: Runtime>(app: AppHandle<R>) -> Result<WallpaperState> {
|
||||
app.wallpaper().select_images()
|
||||
}
|
||||
#[command]
|
||||
pub(crate) async fn delete_image<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
id: String,
|
||||
) -> Result<WallpaperState> {
|
||||
app.wallpaper().delete_image(DeleteImageRequest { id })
|
||||
}
|
||||
#[command]
|
||||
pub(crate) async fn set_image_crop<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
id: String,
|
||||
mode: String,
|
||||
zoom: f64,
|
||||
position_x: f64,
|
||||
position_y: f64,
|
||||
) -> Result<GalleryImage> {
|
||||
app.wallpaper().set_image_crop(ImageCropRequest {
|
||||
id,
|
||||
mode,
|
||||
zoom,
|
||||
position_x,
|
||||
position_y,
|
||||
})
|
||||
}
|
||||
#[command]
|
||||
pub(crate) async fn set_setting<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
name: String,
|
||||
value: bool,
|
||||
) -> Result<WallpaperState> {
|
||||
app.wallpaper().set_setting(SettingRequest { name, value })
|
||||
}
|
||||
#[command]
|
||||
pub(crate) async fn next_wallpaper<R: Runtime>(app: AppHandle<R>) -> Result<WallpaperState> {
|
||||
app.wallpaper().next_wallpaper()
|
||||
}
|
||||
|
||||
+76
-8
@@ -4,19 +4,87 @@ use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
||||
use crate::models::*;
|
||||
|
||||
pub fn init<R: Runtime, C: DeserializeOwned>(
|
||||
app: &AppHandle<R>,
|
||||
_api: PluginApi<R, C>,
|
||||
app: &AppHandle<R>,
|
||||
_api: PluginApi<R, C>,
|
||||
) -> crate::Result<Wallpaper<R>> {
|
||||
Ok(Wallpaper(app.clone()))
|
||||
Ok(Wallpaper(app.clone()))
|
||||
}
|
||||
|
||||
/// Access to the wallpaper APIs.
|
||||
pub struct Wallpaper<R: Runtime>(AppHandle<R>);
|
||||
|
||||
impl<R: Runtime> Wallpaper<R> {
|
||||
fn demo() -> WallpaperState { WallpaperState { image_count: 3, enabled: true, shuffle: true, lock_screen_only: true, current_index: 0, image_urls: vec!["/wallpapers/alpine.png".into(), "/wallpapers/waterfall.png".into(), "/wallpapers/coast.png".into()] } }
|
||||
pub fn get_state(&self) -> crate::Result<WallpaperState> { Ok(Self::demo()) }
|
||||
pub fn select_images(&self) -> crate::Result<WallpaperState> { Ok(Self::demo()) }
|
||||
pub fn set_setting(&self, payload: SettingRequest) -> crate::Result<WallpaperState> { let mut state = Self::demo(); match payload.name.as_str() { "enabled" => state.enabled = payload.value, "shuffle" => state.shuffle = payload.value, "lockScreenOnly" => state.lock_screen_only = payload.value, _ => {} }; Ok(state) }
|
||||
pub fn next_wallpaper(&self) -> crate::Result<WallpaperState> { let mut state = Self::demo(); state.current_index = 1; Ok(state) }
|
||||
fn demo() -> WallpaperState {
|
||||
WallpaperState {
|
||||
image_count: 3,
|
||||
enabled: true,
|
||||
shuffle: true,
|
||||
lock_screen_only: true,
|
||||
current_index: 0,
|
||||
image_urls: vec![
|
||||
"/wallpapers/alpine.png".into(),
|
||||
"/wallpapers/waterfall.png".into(),
|
||||
"/wallpapers/coast.png".into(),
|
||||
],
|
||||
}
|
||||
}
|
||||
pub fn get_state(&self) -> crate::Result<WallpaperState> {
|
||||
Ok(Self::demo())
|
||||
}
|
||||
pub fn get_gallery(&self, payload: GalleryRequest) -> crate::Result<GalleryPage> {
|
||||
let urls = Self::demo().image_urls;
|
||||
let items = urls
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.skip(payload.offset)
|
||||
.take(payload.limit)
|
||||
.map(|(index, url)| GalleryImage {
|
||||
id: format!("demo-{index}"),
|
||||
url,
|
||||
selected: index == 0,
|
||||
crop_mode: "cover".into(),
|
||||
crop_zoom: 1.0,
|
||||
crop_position_x: 0.5,
|
||||
crop_position_y: 0.5,
|
||||
})
|
||||
.collect();
|
||||
Ok(GalleryPage { total: 3, items })
|
||||
}
|
||||
pub fn select_images(&self) -> crate::Result<WallpaperState> {
|
||||
Ok(Self::demo())
|
||||
}
|
||||
pub fn delete_image(&self, _payload: DeleteImageRequest) -> crate::Result<WallpaperState> {
|
||||
Ok(Self::demo())
|
||||
}
|
||||
pub fn set_image_crop(&self, payload: ImageCropRequest) -> crate::Result<GalleryImage> {
|
||||
let url = Self::demo()
|
||||
.image_urls
|
||||
.into_iter()
|
||||
.nth(payload.id.trim_start_matches("demo-").parse().unwrap_or(0))
|
||||
.unwrap_or_default();
|
||||
Ok(GalleryImage {
|
||||
id: payload.id,
|
||||
url,
|
||||
selected: false,
|
||||
crop_mode: payload.mode,
|
||||
crop_zoom: payload.zoom,
|
||||
crop_position_x: payload.position_x,
|
||||
crop_position_y: payload.position_y,
|
||||
})
|
||||
}
|
||||
pub fn set_setting(&self, payload: SettingRequest) -> crate::Result<WallpaperState> {
|
||||
let mut state = Self::demo();
|
||||
match payload.name.as_str() {
|
||||
"enabled" => state.enabled = payload.value,
|
||||
"shuffle" => state.shuffle = payload.value,
|
||||
"lockScreenOnly" => state.lock_screen_only = payload.value,
|
||||
_ => {}
|
||||
};
|
||||
Ok(state)
|
||||
}
|
||||
pub fn next_wallpaper(&self) -> crate::Result<WallpaperState> {
|
||||
let mut state = Self::demo();
|
||||
state.current_index = 1;
|
||||
Ok(state)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -4,18 +4,18 @@ pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
#[cfg(mobile)]
|
||||
#[error(transparent)]
|
||||
PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
#[cfg(mobile)]
|
||||
#[error(transparent)]
|
||||
PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
|
||||
}
|
||||
|
||||
impl Serialize for Error {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.to_string().as_ref())
|
||||
}
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.to_string().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
+25
-17
@@ -1,6 +1,6 @@
|
||||
use tauri::{
|
||||
plugin::{Builder, TauriPlugin},
|
||||
Manager, Runtime,
|
||||
plugin::{Builder, TauriPlugin},
|
||||
Manager, Runtime,
|
||||
};
|
||||
|
||||
pub use models::*;
|
||||
@@ -23,26 +23,34 @@ use mobile::Wallpaper;
|
||||
|
||||
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the wallpaper APIs.
|
||||
pub trait WallpaperExt<R: Runtime> {
|
||||
fn wallpaper(&self) -> &Wallpaper<R>;
|
||||
fn wallpaper(&self) -> &Wallpaper<R>;
|
||||
}
|
||||
|
||||
impl<R: Runtime, T: Manager<R>> crate::WallpaperExt<R> for T {
|
||||
fn wallpaper(&self) -> &Wallpaper<R> {
|
||||
self.state::<Wallpaper<R>>().inner()
|
||||
}
|
||||
fn wallpaper(&self) -> &Wallpaper<R> {
|
||||
self.state::<Wallpaper<R>>().inner()
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the plugin.
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("wallpaper")
|
||||
.invoke_handler(tauri::generate_handler![commands::get_state, commands::select_images, commands::set_setting, commands::next_wallpaper])
|
||||
.setup(|app, api| {
|
||||
#[cfg(mobile)]
|
||||
let wallpaper = mobile::init(app, api)?;
|
||||
#[cfg(desktop)]
|
||||
let wallpaper = desktop::init(app, api)?;
|
||||
app.manage(wallpaper);
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
Builder::new("wallpaper")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::get_state,
|
||||
commands::get_gallery,
|
||||
commands::select_images,
|
||||
commands::delete_image,
|
||||
commands::set_image_crop,
|
||||
commands::set_setting,
|
||||
commands::next_wallpaper
|
||||
])
|
||||
.setup(|app, api| {
|
||||
#[cfg(mobile)]
|
||||
let wallpaper = mobile::init(app, api)?;
|
||||
#[cfg(desktop)]
|
||||
let wallpaper = desktop::init(app, api)?;
|
||||
app.manage(wallpaper);
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
+42
-13
@@ -1,7 +1,7 @@
|
||||
use serde::de::DeserializeOwned;
|
||||
use tauri::{
|
||||
plugin::{PluginApi, PluginHandle},
|
||||
AppHandle, Runtime,
|
||||
plugin::{PluginApi, PluginHandle},
|
||||
AppHandle, Runtime,
|
||||
};
|
||||
|
||||
use crate::models::*;
|
||||
@@ -11,22 +11,51 @@ tauri::ios_plugin_binding!(init_plugin_wallpaper);
|
||||
|
||||
// initializes the Kotlin or Swift plugin classes
|
||||
pub fn init<R: Runtime, C: DeserializeOwned>(
|
||||
_app: &AppHandle<R>,
|
||||
api: PluginApi<R, C>,
|
||||
_app: &AppHandle<R>,
|
||||
api: PluginApi<R, C>,
|
||||
) -> crate::Result<Wallpaper<R>> {
|
||||
#[cfg(target_os = "android")]
|
||||
let handle = api.register_android_plugin("de.wechselbild.wallpaper", "WallpaperPlugin")?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let handle = api.register_ios_plugin(init_plugin_wallpaper)?;
|
||||
Ok(Wallpaper(handle))
|
||||
#[cfg(target_os = "android")]
|
||||
let handle = api.register_android_plugin("de.wechselbild.wallpaper", "WallpaperPlugin")?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let handle = api.register_ios_plugin(init_plugin_wallpaper)?;
|
||||
Ok(Wallpaper(handle))
|
||||
}
|
||||
|
||||
/// Access to the wallpaper APIs.
|
||||
pub struct Wallpaper<R: Runtime>(PluginHandle<R>);
|
||||
|
||||
impl<R: Runtime> Wallpaper<R> {
|
||||
pub fn get_state(&self) -> crate::Result<WallpaperState> { self.0.run_mobile_plugin("getState", ()).map_err(Into::into) }
|
||||
pub fn select_images(&self) -> crate::Result<WallpaperState> { self.0.run_mobile_plugin("selectImages", ()).map_err(Into::into) }
|
||||
pub fn set_setting(&self, payload: SettingRequest) -> crate::Result<WallpaperState> { self.0.run_mobile_plugin("setSetting", payload).map_err(Into::into) }
|
||||
pub fn next_wallpaper(&self) -> crate::Result<WallpaperState> { self.0.run_mobile_plugin("nextWallpaper", ()).map_err(Into::into) }
|
||||
pub fn get_state(&self) -> crate::Result<WallpaperState> {
|
||||
self.0.run_mobile_plugin("getState", ()).map_err(Into::into)
|
||||
}
|
||||
pub fn get_gallery(&self, payload: GalleryRequest) -> crate::Result<GalleryPage> {
|
||||
self.0
|
||||
.run_mobile_plugin("getGallery", payload)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
pub fn select_images(&self) -> crate::Result<WallpaperState> {
|
||||
self.0
|
||||
.run_mobile_plugin("selectImages", ())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
pub fn delete_image(&self, payload: DeleteImageRequest) -> crate::Result<WallpaperState> {
|
||||
self.0
|
||||
.run_mobile_plugin("deleteImage", payload)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
pub fn set_image_crop(&self, payload: ImageCropRequest) -> crate::Result<GalleryImage> {
|
||||
self.0
|
||||
.run_mobile_plugin("setImageCrop", payload)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
pub fn set_setting(&self, payload: SettingRequest) -> crate::Result<WallpaperState> {
|
||||
self.0
|
||||
.run_mobile_plugin("setSetting", payload)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
pub fn next_wallpaper(&self) -> crate::Result<WallpaperState> {
|
||||
self.0
|
||||
.run_mobile_plugin("nextWallpaper", ())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
+52
-7
@@ -3,14 +3,59 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WallpaperState {
|
||||
pub image_count: usize,
|
||||
pub enabled: bool,
|
||||
pub shuffle: bool,
|
||||
pub lock_screen_only: bool,
|
||||
pub current_index: usize,
|
||||
pub image_urls: Vec<String>,
|
||||
pub image_count: usize,
|
||||
pub enabled: bool,
|
||||
pub shuffle: bool,
|
||||
pub lock_screen_only: bool,
|
||||
pub current_index: usize,
|
||||
pub image_urls: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SettingRequest { pub name: String, pub value: bool }
|
||||
pub struct SettingRequest {
|
||||
pub name: String,
|
||||
pub value: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GalleryRequest {
|
||||
pub offset: usize,
|
||||
pub limit: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeleteImageRequest {
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ImageCropRequest {
|
||||
pub id: String,
|
||||
pub mode: String,
|
||||
pub zoom: f64,
|
||||
pub position_x: f64,
|
||||
pub position_y: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GalleryImage {
|
||||
pub id: String,
|
||||
pub url: String,
|
||||
pub selected: bool,
|
||||
pub crop_mode: String,
|
||||
pub crop_zoom: f64,
|
||||
pub crop_position_x: f64,
|
||||
pub crop_position_y: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GalleryPage {
|
||||
pub total: usize,
|
||||
pub items: Vec<GalleryImage>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user