Skip to content

Commit

Permalink
Story add/delete enhancements
Browse files Browse the repository at this point in the history
Fix #11

Story titles couldn't be added. Now they can by clicking a second time on the active story.

Fix #10

Confirmation before delete. There is now a persistent app trash. Stories end up there before being permanantly removed. They can be restored or deleted individually.
  • Loading branch information
mdegans committed Jun 13, 2024
1 parent 85763fb commit b221f43
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 7 deletions.
Binary file added resources/add.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/check.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/delete.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/delete.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/delete_forever.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/delete_forever.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/restore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/restore.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
109 changes: 103 additions & 6 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod settings;
use {
self::settings::{BackendOptions, Settings},
crate::{
button,
node::{Action, Meta, Node},
story::{DrawMode, Story},
},
Expand All @@ -21,6 +22,9 @@ struct LeftSidebar {
pub title_buf: String,
pub page: SidebarPage,
pub visible: bool,
/// Whether the story title is being edited. If this is true, the story
/// title widget is a text edit widget. Otherwise, it is a label.
pub editing_active_title: bool,
}

#[derive(Default, PartialEq)]
Expand Down Expand Up @@ -91,6 +95,7 @@ impl From<String> for Error {
pub struct App {
active_story: Option<usize>,
stories: Vec<Story>,
trash: Vec<Story>,
settings: Settings,
left_sidebar: LeftSidebar,
right_sidebar: RightSidebar,
Expand Down Expand Up @@ -144,6 +149,31 @@ impl App {
})
.unwrap_or_default();

let trash = cc
.storage
.map(|storage| {
storage
.get_string("trash")
.and_then(|s| {
log::debug!("Loading trash: {}", s);
match serde_json::from_str(&s) {
Ok(trash) => Some(trash),
Err(e) => {
errors.push(
format!(
"Failed to load trash because: {}",
e
)
.into(),
);
None
}
}
})
.unwrap_or_default()
})
.unwrap_or_default();

let settings = cc
.storage
.map(|storage| {
Expand Down Expand Up @@ -174,6 +204,7 @@ impl App {
stories,
settings,
active_story: None,
trash,
..Default::default()
};

Expand Down Expand Up @@ -718,32 +749,95 @@ impl App {
ui.separator();
}
let mut delete = None;
for (i, story) in self.stories.iter().enumerate() {
for (i, story) in self.stories.iter_mut().enumerate() {
ui.horizontal(|ui| {
if ui.button("X").clicked() {
let active_story =
self.active_story.is_some_and(|idx| idx == i);
if button!(ui, "../resources/delete.png").clicked() {
delete = Some(i);
}
if ui.button(&story.title).clicked() {
self.active_story = Some(i);
if active_story {
if self.left_sidebar.editing_active_title {
ui.text_edit_singleline(&mut story.title);
if ui
.add(egui::Button::image(egui::include_image!(
"../resources/check.png"
)))
.clicked()
{
self.left_sidebar.editing_active_title = false;
}
} else if ui.button(&story.title).clicked() {
self.left_sidebar.editing_active_title = true;
}
} else {
if ui.button(&story.title).clicked() {
self.active_story = Some(i);
self.left_sidebar.editing_active_title = false;
}
}
});
}
if let Some(i) = delete {
self.stories.remove(i);
self.trash.push(self.stories.remove(i));
if self.active_story == Some(i) {
self.active_story = None;
}
}

ui.horizontal(|ui| {
if ui.button("New").clicked() {
if button!(ui, "../resources/add.png")
.on_hover_text_at_pointer("Add a story.")
.clicked()
{
let title = self.left_sidebar.title_buf.clone();
let author = self.settings.default_author.clone();
self.new_story(title, author);
self.left_sidebar.title_buf.clear();
}
ui.text_edit_singleline(&mut self.left_sidebar.title_buf);
});

let mut restore = None;
delete = None;
if !self.trash.is_empty() {
// FIXME: This should be bottom aligned. I tried a TopBottomPanel
// but it draws on *top* of the central panel which is not what we
// want. We want it to be below the stories list at the bottom of
// the sidebar.
ui.separator();
ui.horizontal(|ui| {
ui.label("Trash");
if button!(ui, "../resources/delete_forever.png")
.on_hover_text_at_pointer("Empty trash permanantly.")
.clicked()
{
self.trash.clear();
}
});
ui.separator();
for (i, story) in self.trash.iter().enumerate() {
ui.horizontal(|ui| {
if button!(ui, "../resources/restore.png")
.on_hover_text_at_pointer("Restore story.")
.clicked()
{
restore = Some(i);
}
if button!(ui, "../resources/delete_forever.png")
.on_hover_text_at_pointer("Delete story permanantly.")
.clicked()
{
delete = Some(i);
}
ui.label(&story.title);
});
}
}

if let Some(i) = restore {
self.stories.push(self.trash.remove(i));
}
}

/// Draw the central panel.
Expand Down Expand Up @@ -1259,12 +1353,15 @@ impl eframe::App for App {
let serialized_stories = serde_json::to_string(&self.stories).unwrap();
let serialized_settings =
serde_json::to_string(&self.settings).unwrap();
let serialized_trash = serde_json::to_string(&self.trash).unwrap();

log::debug!("Saving stories: {}", serialized_stories);
log::debug!("Saving settings: {}", serialized_settings);
log::debug!("Saving trash: {}", serialized_trash);

storage.set_string("stories", serialized_stories);
storage.set_string("settings", serialized_settings);
storage.set_string("trash", serialized_trash);
}

fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
Expand Down
10 changes: 9 additions & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ macro_rules! icon {
$ui.add(egui::Image::new(egui::include_image!($path)).max_height($size))
};
($ui:expr, $path:expr) => {
icon!($path, 12.0)
icon!($ui, $path, 12.0)
};
}

#[macro_export]
#[cfg(feature = "gui")]
macro_rules! button {
($ui:expr, $path:expr) => {
$ui.add(egui::Button::image(egui::include_image!($path)))
};
}

0 comments on commit b221f43

Please sign in to comment.