From: Olaf Wintermann Date: Sun, 6 Sep 2026 10:35:27 +0000 (+0200) Subject: add save_as button to the attachment window X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=436d0b8ea55ba3d6db9a0b48ca0e97c8a3318803;p=note.git add save_as button to the attachment window --- diff --git a/application/backend/src/backend.rs b/application/backend/src/backend.rs index 9dd0eb2..a6e4141 100644 --- a/application/backend/src/backend.rs +++ b/application/backend/src/backend.rs @@ -963,6 +963,34 @@ impl BackendHandle { let _ = self.tx.send(cmd); } + pub fn save_attachment_file(&self, attachment_id: i32, path: &Path, callback: F) + where F: FnOnce(FileResult) + Send + 'static { + let backend = self.backend.clone(); + let pathbuf = path.to_path_buf(); + let cmd = Box::pin(async move { + let content = async { + attachmentcontent::Entity::find() + .filter(attachmentcontent::Column::AttachmentId.eq(attachment_id)) + .one(&backend.db) + .await? + .ok_or(DbErr::RecordNotFound(format!("attachment {} not found", attachment_id))) + }.await; + let result = match content { + Ok(content) => { + match write_file(pathbuf.as_path(), &content.content).await { + Ok(()) => FileResult::Ok, + Err(err) => FileResult::FileError(err), + } + }, + Err(e) => { + FileResult::DbErr(e) + } + }; + callback(result); + }); + let _ = self.tx.send(cmd); + } + pub fn open_extern(&self, note_id: i32, callback: F) where F: FnOnce(OpenExternResult) + Send + 'static { let backend = self.backend.clone(); @@ -1107,6 +1135,13 @@ pub enum SaveNoteResult { ValidationError(&'static str) } +#[derive(Debug)] +pub enum FileResult { + Ok, + DbErr(DbErr), + FileError(Error) +} + pub struct SaveNoteRet { pub model: entity::note::Model, pub content_id: i32, diff --git a/application/backend/src/storage.rs b/application/backend/src/storage.rs index a906874..858aab7 100644 --- a/application/backend/src/storage.rs +++ b/application/backend/src/storage.rs @@ -112,7 +112,7 @@ pub async fn get_last_modified(path: &Path) -> Option { return None } -pub async fn write_file(path: &Path, content: &str) -> std::io::Result<()> { +pub async fn write_file(path: &Path, content: &[u8]) -> std::io::Result<()> { let mut file = match File::create(path).await { Ok(f) => f, Err(err) if err.kind() == ErrorKind::NotFound => { @@ -124,7 +124,7 @@ pub async fn write_file(path: &Path, content: &str) -> std::io::Result<()> { Err(err) => return Err(err), }; - file.write_all(content.as_bytes()).await?; + file.write_all(content).await?; Ok(()) } diff --git a/application/note/src/attachments_window.rs b/application/note/src/attachments_window.rs index 6b38a29..58a1a44 100644 --- a/application/note/src/attachments_window.rs +++ b/application/note/src/attachments_window.rs @@ -25,6 +25,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +use std::path::Path; use backend::backend::BackendHandle; use ui_rs::ui::*; use ui_rs::{action, button, imageviewer, tabview, ui_actions, webview, UiModel}; @@ -40,6 +41,7 @@ pub fn attachments_window_create(backend: BackendHandle, note_id: i32, selected_ hb.start(|obj|{ button!(obj, icon = UiIconSet::GoBack.as_str(), action = "go_back"); button!(obj, icon = UiIconSet::GoForward.as_str(), action = "go_forward"); + button!(obj, icon = UiIconSet::SaveLocal.as_str(), action = "save_as"); }); }); @@ -224,4 +226,21 @@ impl AttachmentsWindow { self.update_selection(selected_index); } } + + #[action] + pub fn save_as(&mut self, _event: &ActionEvent) -> Option<()> { + let obj = self.obj.get_object()?; + let attachment = self.attachments.get(self.selected_index?)?; + let attachment_id = attachment.attachment.attachment_id; + obj.savefile_dialog(attachment.attachment.nodename.as_str(), move|event|{ + if let EventType::FileList(files) = event.event_type && let Some(path_str) = files.get(0) { + let path = Path::new(path_str); + event.data.backend.save_attachment_file(attachment_id, path, |result|{ + println!("save attachment file: {:?}", result); + }); + } + }); + + Some(()) + } }