Skip to content

Commit 54d451c

Browse files
committed
Add shortcuts and functionality to save the converted file
1 parent 9ec6fad commit 54d451c

4 files changed

Lines changed: 107 additions & 15 deletions

File tree

src/bridgex/src/app.rs

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,25 @@ use freya::{
33
prelude::*,
44
text_edit::Rope,
55
};
6+
use std::path::PathBuf;
67
use crate::theme::{ github_app_theme, github_editor_theme, GITHUB_COLORS };
7-
use crate::ui::{ about::AboutPopup, licenses::LicencesPopup, menu::MenuBarOwn };
8-
use crate::utils::files::FileOwn;
8+
use crate::ui::{ about::AboutPopup, licenses::LicencesPopup, menu::{ open_file, MenuBarOwn } };
9+
use crate::utils::files::{ FileOwn, Filter };
910

1011
pub fn app() -> impl IntoElement {
1112
use_init_theme(github_app_theme);
1213
let theme_colors = GITHUB_COLORS;
1314

1415
let mut open_file_state = use_state(|| Option::<FileOwn>::None);
16+
let mut save_requested = use_state(|| false);
17+
let mut exit_requested = use_state(|| false);
18+
let mut current_file_path = use_state(|| Option::<PathBuf>::None);
1519
let focus = use_focus();
1620

1721
let mut popup_licenses = LicencesPopup::new();
1822
let mut about_popup = AboutPopup::new(popup_licenses.show_popup.clone());
19-
let show_licenses = popup_licenses.show_popup.clone();
20-
let show_about = about_popup.show_popup.clone();
23+
let mut show_licenses = popup_licenses.show_popup.clone();
24+
let mut show_about = about_popup.show_popup.clone();
2125

2226
let mut editor = use_state(|| {
2327
let mut editor = CodeEditorData::new("".into(), LanguageId::Markdown);
@@ -30,6 +34,8 @@ pub fn app() -> impl IntoElement {
3034

3135
let menu_ctn = MenuBarOwn::new(
3236
open_file_state.clone(),
37+
save_requested.clone(),
38+
exit_requested.clone(),
3339
show_about.clone(),
3440
show_licenses.clone(),
3541
Some("#00000000".to_string())
@@ -42,11 +48,66 @@ pub fn app() -> impl IntoElement {
4248
let converted = crate::logic::converter::convert_from_path(file_path);
4349
editor.write().rope = Rope::from_str(converted.as_str());
4450
editor.write().parse();
51+
*current_file_path.write() = Some(file.path().clone());
4552
*open_file_state.write() = None;
4653
}
4754

55+
if *save_requested.read() {
56+
let default_name = current_file_path
57+
.read()
58+
.as_ref()
59+
.and_then(|path|
60+
path
61+
.file_name()
62+
.and_then(|name| name.to_str())
63+
.map(|s| s.to_string())
64+
)
65+
.unwrap_or_else(|| "document.md".to_string());
66+
67+
if
68+
let Some(save_path) = FileOwn::save_file_dialog(
69+
&default_name,
70+
vec![Filter::new("Markdown", &["md"])]
71+
)
72+
{
73+
if FileOwn::write_text_file(&save_path, &editor.read().rope.to_string()).is_ok() {
74+
*current_file_path.write() = Some(save_path);
75+
}
76+
}
77+
78+
*save_requested.write() = false;
79+
}
80+
81+
if *exit_requested.read() {
82+
std::process::exit(0);
83+
}
84+
4885
rect()
4986
.background(theme_colors.background)
87+
.on_global_key_down(move |event: Event<KeyboardEventData>| {
88+
if event.modifiers.ctrl() || event.modifiers.meta() {
89+
match event.code {
90+
Code::KeyO => {
91+
if let Some(file) = open_file() {
92+
*open_file_state.write() = Some(file);
93+
}
94+
}
95+
Code::KeyS => {
96+
*save_requested.write() = true;
97+
}
98+
Code::KeyQ => {
99+
*exit_requested.write() = true;
100+
}
101+
Code::KeyI => {
102+
show_about.toggle();
103+
}
104+
Code::KeyL => {
105+
show_licenses.toggle();
106+
}
107+
_ => {}
108+
}
109+
}
110+
})
50111
.child(menu)
51112
.child(build_popups(&mut popup_licenses, &mut about_popup))
52113
.child(

src/bridgex/src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ fn main() {
1414
LaunchConfig::new().with_window(
1515
WindowConfig::new(app)
1616
.with_title("Bridgex - Rust + Freya")
17+
.with_icon(
18+
LaunchConfig::window_icon(include_bytes!("assets/images/logo-bridgex-2.webp"))
19+
)
1720
.with_background(theme::GITHUB_COLORS.background)
1821
.with_min_size(900.0, 700.0)
1922
)

src/bridgex/src/ui/menu.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ pub struct MenuBarOwn {
99
menu_item_clicked: State<bool>,
1010
current_menu: State<String>,
1111
open_file_state: State<Option<FileOwn>>,
12+
save_requested: State<bool>,
13+
exit_requested: State<bool>,
1214
show_about: State<bool>,
1315
show_licenses: State<bool>,
1416
submenu_file_position: Position,
@@ -18,6 +20,8 @@ pub struct MenuBarOwn {
1820
impl MenuBarOwn {
1921
pub fn new(
2022
open_file_state: State<Option<FileOwn>>,
23+
save_requested: State<bool>,
24+
exit_requested: State<bool>,
2125
show_about: State<bool>,
2226
show_licenses: State<bool>,
2327
background: Option<String>
@@ -29,6 +33,8 @@ impl MenuBarOwn {
2933
menu_item_clicked: use_state(|| false),
3034
current_menu: use_state(|| String::new()),
3135
open_file_state,
36+
save_requested,
37+
exit_requested,
3238
show_about,
3339
show_licenses,
3440
submenu_file_position: Position::new_absolute()
@@ -105,6 +111,8 @@ impl MenuBarOwn {
105111

106112
fn submenu_file(&self, submenu_file_position: Position) -> impl IntoElement {
107113
let mut open_file_state = self.open_file_state.clone();
114+
let mut save_requested = self.save_requested.clone();
115+
let mut exit_requested = self.exit_requested.clone();
108116
let menu_item_clicked = self.menu_item_clicked.clone();
109117
let current_menu = self.current_menu.clone();
110118

@@ -114,14 +122,15 @@ impl MenuBarOwn {
114122
Menu::new()
115123
.child(
116124
MenuButton::new()
117-
.child("Save")
125+
.child("Save Ctrl+S")
118126
.on_press(move |_| {
127+
*save_requested.write() = true;
119128
close_menu(menu_item_clicked.clone(), current_menu.clone());
120129
})
121130
)
122131
.child(
123132
MenuButton::new()
124-
.child("Open")
133+
.child("Open Ctrl+O")
125134
.on_press(move |_| {
126135
if let Some(file) = open_file() {
127136
*open_file_state.write() = Some(file);
@@ -131,8 +140,9 @@ impl MenuBarOwn {
131140
)
132141
.child(
133142
MenuButton::new()
134-
.child("Exit")
143+
.child("Exit Ctrl+Q")
135144
.on_press(move |_| {
145+
*exit_requested.write() = true;
136146
close_menu(menu_item_clicked.clone(), current_menu.clone());
137147
})
138148
)
@@ -154,15 +164,15 @@ impl MenuBarOwn {
154164
Menu::new()
155165
.child(
156166
MenuButton::new()
157-
.child("About")
167+
.child("About Ctrl+I")
158168
.on_press(move |_| {
159169
show_about.toggle();
160170
close_menu(menu_item_clicked.clone(), current_menu.clone());
161171
})
162172
)
163173
.child(
164174
MenuButton::new()
165-
.child("Licenses")
175+
.child("Licenses Ctrl+L")
166176
.on_press(move |_| {
167177
show_licenses.toggle();
168178
close_menu(menu_item_clicked.clone(), current_menu.clone());
@@ -208,19 +218,16 @@ fn close_menu(mut menu_item_clicked: State<bool>, mut current_menu: State<String
208218
*current_menu.write() = String::new();
209219
}
210220

211-
fn open_file() -> Option<FileOwn> {
221+
pub(crate) fn open_file() -> Option<FileOwn> {
212222
let filters = vec![
213223
Filter::new("Excel", &["xlsx"]),
214224
Filter::new("Word", &["docx"]),
215225
Filter::new("PowerPoint", &["pptx"]),
216226
Filter::new("PDF", &["pdf"]),
217-
Filter::new("Images", &["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp"]),
218-
Filter::new("Audio", &["mp3", "wav", "flac", "ogg", "m4a", "aac"]),
219227
Filter::new("HTML", &["html", "htm"]),
220228
Filter::new("CSV (UTF-8)", &["csv"]),
221229
Filter::new("Text-based formats", &["xml", "rss", "atom", "txt"]),
222-
Filter::new("ZIP", &["zip"]),
223-
Filter::new("Markdown", &["md", "markdown"])
230+
Filter::new("ZIP", &["zip"])
224231
];
225232

226233
FileOwn::open_file_dialog(filters)

src/bridgex/src/utils/files.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{ path::PathBuf };
1+
use std::{ fs, path::{ Path, PathBuf } };
22
use rfd::FileDialog;
33
use crate::utils::constants::DOCUMENT_EXTENSIONS;
44

@@ -72,4 +72,25 @@ impl FileOwn {
7272
let path = dialog.pick_file()?;
7373
Some(Self::new(path))
7474
}
75+
76+
pub fn save_file_dialog(default_name: &str, mut filters: Vec<Filter>) -> Option<PathBuf> {
77+
if filters.is_empty() {
78+
filters.push(Filter::new("Markdown", &["md"]));
79+
}
80+
81+
let all_allowed_extensions: Vec<&'static str> = filters
82+
.iter()
83+
.flat_map(|filter| filter.extensions.iter().copied())
84+
.collect();
85+
86+
let dialog = FileDialog::new()
87+
.set_file_name(default_name)
88+
.add_filter("All allowed files", &all_allowed_extensions);
89+
let dialog = Self::set_filters(filters, dialog);
90+
dialog.save_file()
91+
}
92+
93+
pub fn write_text_file(path: impl AsRef<Path>, contents: &str) -> std::io::Result<()> {
94+
fs::write(path, contents)
95+
}
7596
}

0 commit comments

Comments
 (0)