prehnite_core/util/
file_dialog.rs1#![doc = "Prehniteブックを開く"]
2use crate::db::open_book_or_alert;
3use crate::i18n::i18n;
4use crate::opt_unwrap_or_return;
5use crate::settings::registry::SettingRegistry;
6use crate::settings::value::SettingValueType;
7use crate::settings::GlobalSettingKey;
8use crate::util::alert::alert_i18n_spawn;
9use iced::window::raw_window_handle::HasWindowHandle;
10use iced::{window, Task};
11use native_dialog::{FileDialogBuilder, MessageLevel};
12use std::path::PathBuf;
13use tracing::{debug, error, trace};
14use tracing_unwrap::ResultExt;
15
16fn prehnite_file_dialog_builder(
17 title_i18n_id: &str,
18 owner: &Option<&dyn HasWindowHandle>,
19) -> FileDialogBuilder {
20 let v = FileDialogBuilder::default()
21 .set_title(i18n(title_i18n_id))
22 .add_filter("prehnite book", ["prehnite"]);
23 match owner {
24 None => v,
25 Some(w) => v.set_owner(w),
26 }
27}
28
29fn unwrap_dialog_result(value: native_dialog::Result<Option<PathBuf>>) -> Option<PathBuf> {
30 match value.ok_or_log() {
31 Some(v) => {
32 if v.is_none() {
33 trace!("File select canceled.");
34 }
35 v
36 }
37 None => None,
38 }
39}
40
41fn dialog_new_prehnite_book(window_id: window::Id) -> Task<Option<PathBuf>> {
42 window::run(window_id, |w| {
43 prehnite_file_dialog_builder("new-file", &Some(w)).save_single_file()
44 })
45 .then(|v| Task::future(async { unwrap_dialog_result(v.spawn().await) }))
46}
47
48fn dialog_open_prehnite_book(window_id: window::Id) -> Task<Option<PathBuf>> {
49 window::run(window_id, |w| {
50 prehnite_file_dialog_builder("open-file", &Some(w)).open_single_file()
51 })
52 .then(|v| Task::future(async { unwrap_dialog_result(v.spawn().await) }))
53}
54
55#[derive(Clone, Debug)]
56pub enum FileOpe {
58 New,
59 Open,
60}
61
62#[derive(Clone, Debug, PartialEq, Eq)]
63pub enum OpenPrehniteBookStatus {
65 Success,
66 Failed,
67 NotSelected,
68}
69
70impl OpenPrehniteBookStatus {
71 pub fn is_success(&self) -> bool {
73 OpenPrehniteBookStatus::Success == *self
74 }
75}
76
77async fn prehnite_book_file_process(book_path: PathBuf, ope: FileOpe) -> OpenPrehniteBookStatus {
78 match ope {
79 FileOpe::New => match tokio::fs::remove_file(book_path.clone()).await {
80 Ok(_) => {}
81 Err(e) => {
82 if tokio::fs::try_exists(book_path.clone())
83 .await
84 .unwrap_or(true)
85 {
86 error!("Failed to remove file ({book_path:#?}): {e}");
87 alert_i18n_spawn(("error", "permission-denied"), MessageLevel::Error).await;
88 return OpenPrehniteBookStatus::Failed;
89 }
90 }
91 },
92 FileOpe::Open => {
93 if !tokio::fs::try_exists(book_path.clone())
94 .await
95 .unwrap_or(false)
96 {
97 error!("File does not exist ({book_path:#?})");
98 alert_i18n_spawn(("error", "file-notfound"), MessageLevel::Error).await;
99 SettingRegistry::immediate_apply(
100 GlobalSettingKey::LastOpened.into(),
101 SettingValueType::String(None),
102 )
103 .await
104 .ok_or_log();
105 return OpenPrehniteBookStatus::Failed;
106 }
107 }
108 }
109 if open_book_or_alert(book_path).await {
110 OpenPrehniteBookStatus::Success
111 } else {
112 OpenPrehniteBookStatus::Failed
113 }
114}
115
116#[tracing::instrument]
117pub fn select_and_open_prehnite_book_file(
119 window_id: window::Id,
120 ope: FileOpe,
121) -> Task<OpenPrehniteBookStatus> {
122 let file_dialog_result = match &ope {
123 FileOpe::New => dialog_new_prehnite_book(window_id),
124 FileOpe::Open => dialog_open_prehnite_book(window_id),
125 };
126 file_dialog_result.then(move |book_path| {
127 let book_path =
128 opt_unwrap_or_return!(book_path, Task::done(OpenPrehniteBookStatus::NotSelected));
129 debug!("Opening the book: {:#?}", book_path);
130 Task::future(prehnite_book_file_process(book_path, ope.clone()))
131 })
132}