use std::sync::Arc; use bevy::prelude::Resource; use thiserror::Error; /// Abstracts platform-specific clipboard access for gameplay UI systems. pub trait ClipboardBackend: Send + Sync + 'static { /// Write plain text to the active OS clipboard. fn set_text(&self, text: &str) -> Result<(), ClipboardError>; } /// Bevy resource that exposes the active clipboard backend. #[derive(Resource, Clone)] pub struct ClipboardBackendResource(pub Arc); /// Errors surfaced by platform clipboard backends. #[derive(Debug, Error)] pub enum ClipboardError { #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] #[error(transparent)] Native(#[from] arboard::Error), #[cfg(target_os = "android")] #[error("android clipboard failed: {0}")] Android(String), #[cfg(all(target_arch = "wasm32", not(target_os = "android")))] #[error("clipboard backend unavailable on wasm32")] Unsupported, } /// Construct the default clipboard backend for the current platform. pub fn default_clipboard_backend() -> Result, ClipboardError> { #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] { Ok(Arc::new(NativeClipboardBackend)) } #[cfg(target_os = "android")] { Ok(Arc::new(AndroidClipboardBackend)) } #[cfg(all(target_arch = "wasm32", not(target_os = "android")))] { Err(ClipboardError::Unsupported) } } /// `arboard`-backed clipboard bridge for desktop targets. #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] #[derive(Debug, Default, Clone, Copy)] pub struct NativeClipboardBackend; #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] impl ClipboardBackend for NativeClipboardBackend { fn set_text(&self, text: &str) -> Result<(), ClipboardError> { let mut clipboard = arboard::Clipboard::new()?; clipboard.set_text(text.to_string())?; Ok(()) } } /// JNI-backed clipboard bridge for Android targets. #[cfg(target_os = "android")] #[derive(Debug, Default, Clone, Copy)] pub struct AndroidClipboardBackend; #[cfg(target_os = "android")] impl ClipboardBackend for AndroidClipboardBackend { fn set_text(&self, text: &str) -> Result<(), ClipboardError> { crate::android_clipboard::set_text(text).map_err(ClipboardError::Android) } }