Skip to content

Commit

Permalink
feat: New toast system to improve UI messages and notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
woelper committed Dec 9, 2023
1 parent 35b058c commit 9f8c688
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 81 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ trash = "3.1"
lutgen = {version ="0.9.0", features = ["lutgen-palettes"]}
libheif-rs = { version = "0.22.0", default-features = false, optional = true}
egui-phosphor = "=0.3.0"
egui-notify = "0.10.0"

[features]
heif = ["libheif-rs"]
Expand Down
15 changes: 9 additions & 6 deletions src/appstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
settings::PersistentSettings,
utils::{ExtendedImageInfo, Frame, Player},
};
use egui_notify::Toasts;
use image::RgbaImage;
use nalgebra::Vector2;
use notan::{egui::epaint::ahash::HashMap, prelude::Texture, AppState};
Expand Down Expand Up @@ -42,13 +43,12 @@ impl Message {
}

/// The state of the application
#[derive(Debug, AppState)]
#[derive(AppState)]
pub struct OculanteState {
pub image_geometry: ImageGeometry,
pub compare_list: HashMap<PathBuf, ImageGeometry>,
pub drag_enabled: bool,
pub reset_image: bool,
pub message: Option<Message>,
/// Is the image fully loaded?
pub is_loaded: bool,
pub window_size: Vector2<f32>,
Expand Down Expand Up @@ -80,24 +80,28 @@ pub struct OculanteState {
pub always_on_top: bool,
pub network_mode: bool,
/// how long the toast message appears
pub toast_cooldown: f32,
/// data to transform image once fullscreen is entered/left
pub fullscreen_offset: Option<(i32, i32)>,
/// List of images to cycle through. Usually the current dir or dropped files
pub scrubber: Scrubber,
pub checker_texture: Option<Texture>,
pub redraw: bool,
pub first_start: bool,
pub toasts: Toasts,
}

impl OculanteState {
pub fn send_message(&self, msg: &str) {
pub fn send_message_info(&self, msg: &str) {
_ = self.message_channel.0.send(Message::info(msg));
}

pub fn send_message_err(&self, msg: &str) {
_ = self.message_channel.0.send(Message::err(msg));
}

pub fn send_message_warn(&self, msg: &str) {
_ = self.message_channel.0.send(Message::warn(msg));
}
}

impl Default for OculanteState {
Expand All @@ -111,7 +115,6 @@ impl Default for OculanteState {
compare_list: Default::default(),
drag_enabled: Default::default(),
reset_image: Default::default(),
message: Default::default(),
is_loaded: Default::default(),
cursor: Default::default(),
cursor_relative: Default::default(),
Expand All @@ -138,12 +141,12 @@ impl Default for OculanteState {
always_on_top: Default::default(),
network_mode: Default::default(),
window_size: Default::default(),
toast_cooldown: Default::default(),
fullscreen_offset: Default::default(),
scrubber: Default::default(),
checker_texture: Default::default(),
redraw: Default::default(),
first_start: true,
toasts: Toasts::default(),
}
}
}
98 changes: 30 additions & 68 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,11 @@ fn init(gfx: &mut Graphics, plugins: &mut Plugins) -> OculanteState {
start_img_location = Some(location.clone());
} else {
// Unsupported extension
state.send_message(&format!("ERROR: Unsupported file: {} - Open Github issue if you think this should not happen.", location.display()));
state.send_message_err(&format!("ERROR: Unsupported file: {} - Open Github issue if you think this should not happen.", location.display()));
}
} else {
// Not a valid path, or user doesn't have permission to access?
state.send_message(&format!("ERROR: Can't open file: {}", location.display()));
state.send_message_err(&format!("ERROR: Can't open file: {}", location.display()));
}

// Assign image path if we have a valid one here
Expand All @@ -239,7 +239,7 @@ fn init(gfx: &mut Graphics, plugins: &mut Plugins) -> OculanteState {
if let Some(port) = matches.value_of("l") {
match port.parse::<i32>() {
Ok(p) => {
state.message = Some(Message::info(&format!("Listening on {p}")));
state.send_message_info(&format!("Listening on {p}"));
recv(p, state.texture_channel.0.clone());
state.current_path = Some(PathBuf::from(&format!("network port {p}")));
state.network_mode = true;
Expand Down Expand Up @@ -456,7 +456,7 @@ fn event(app: &mut App, state: &mut OculanteState, evt: Event) {
if key_pressed(app, state, DeleteFile) {
if let Some(p) = &state.current_path {
_ = trash::delete(p);
state.send_message("Deleted image");
state.send_message_info("Deleted image");
}
}
if key_pressed(app, state, ZoomIn) {
Expand Down Expand Up @@ -569,7 +569,7 @@ fn event(app: &mut App, state: &mut OculanteState, evt: Event) {
state.player.load(&p, state.message_channel.0.clone());
state.current_path = Some(p);
} else {
state.message = Some(Message::warn("Unsupported file!"));
state.send_message_warn("Unsupported file!");
}
}
}
Expand Down Expand Up @@ -674,25 +674,28 @@ fn update(app: &mut App, state: &mut OculanteState) {
app.window().request_frame();
}

// Only receive messages if current one is cleared
// debug!("cooldown {}", state.toast_cooldown);

if state.message.is_none() {
state.toast_cooldown = 0.;

// check if a new message has been sent
if let Ok(msg) = state.message_channel.1.try_recv() {
debug!("Received message: {:?}", msg);
match msg {
Message::LoadError(_) => {
state.current_image = None;
state.is_loaded = true;
state.current_texture = None;
}
_ => (),
// check if a new message has been sent
if let Ok(msg) = state.message_channel.1.try_recv() {
debug!("Received message: {:?}", msg);
match msg {
Message::LoadError(e) => {
state.toasts.error(e);
state.current_image = None;
state.is_loaded = true;
state.current_texture = None;
}
Message::Info(m) => {
state.toasts.info(m).set_duration(Some(Duration::from_secs(1)));
}
Message::Warning(m) => {
state.toasts.warning(m);
}
Message::Error(m) => {
state.toasts.error(m);
}
Message::Saved(_) => {
state.toasts.info("Saved");
}

state.message = Some(msg);
}
}
state.first_start = false;
Expand Down Expand Up @@ -767,7 +770,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O
if p.with_extension("oculante").is_file() {
if let Ok(f) = std::fs::File::open(p.with_extension("oculante")) {
if let Ok(edit_state) = serde_json::from_reader::<_, EditState>(f) {
state.send_message("Edits have been loaded for this image.");
state.send_message_info("Edits have been loaded for this image.");
state.edit_state = edit_state;
state.persistent_settings.edit_enabled = true;
state.reset_image = true;
Expand All @@ -780,7 +783,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O

if let Ok(f) = std::fs::File::open(parent.join(".oculante")) {
if let Ok(edit_state) = serde_json::from_reader::<_, EditState>(f) {
state.send_message(
state.send_message_info(
"Directory edits have been loaded for this image.",
);
state.edit_state = edit_state;
Expand Down Expand Up @@ -968,7 +971,8 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O

let egui_output = plugins.egui(|ctx| {
// the top menu bar
ctx.request_repaint_after(Duration::from_secs(1));
// ctx.request_repaint_after(Duration::from_secs(1));
state.toasts.show(ctx);

if !state.persistent_settings.zen_mode {
egui::TopBottomPanel::top("menu")
Expand All @@ -988,48 +992,6 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O
});
}

if let Some(message) = &state.message.clone() {
// debug!("Message is set, showing");
egui::TopBottomPanel::bottom("message").show_animated(
ctx,
state.message.is_some(),
|ui| {
ui.horizontal(|ui| {
match message {
Message::Info(txt) => {
ui.label(format!("💬 {txt}"));
}
Message::Warning(txt) => {
ui.colored_label(Color32::GOLD, format!("⚠ {txt}"));
}
Message::Error(txt) | Message::LoadError(txt) => {
ui.colored_label(Color32::RED, format!("🕱 {txt}"));
}
Message::Saved(path) => {
ui.colored_label(Color32::RED, format!("Saved!"));
state.current_path = Some(path.clone());
set_title(app, state);
}
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
if ui.small_button("🗙").clicked() {
state.message = None
}
});
});

ui.ctx().request_repaint();
},
);
let max_anim_len = 2.5;

state.toast_cooldown += app.timer.delta_f32();

if state.toast_cooldown > max_anim_len {
debug!("Setting message to none, timer reached.");
state.message = None;
}
}

if state.persistent_settings.info_enabled
&& !state.settings_enabled
Expand Down
18 changes: 11 additions & 7 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ pub fn settings_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx:

#[cfg(debug_assertions)]
if ui.button("send test msg").clicked() {
state.send_message("Test");
state.send_message_info("Test");
}

egui::ComboBox::from_label("Color theme")
Expand Down Expand Up @@ -572,7 +572,7 @@ pub fn settings_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx:

#[cfg(feature = "update")]
if ui.button("Check for updates").on_hover_text("Check and install update if available. You will need to restart the app to use the new version.").clicked() {
state.send_message("Checking for updates...");
state.send_message_info("Checking for updates...");
crate::update::update(Some(state.message_channel.0.clone()));
state.settings_enabled = false;
}
Expand Down Expand Up @@ -1232,8 +1232,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu
.save(p) {
Ok(_) => {
debug!("Saved to {}", p.display());

state.send_message("Saved");
state.send_message_info("Saved");
//Re-apply exif
if let Some(info) = &state.image_info {
// before doing anything, make sure we have raw exif data
Expand All @@ -1247,7 +1246,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu
}
}
Err(e) => {
state.send_message(&format!("Could not save: {e}"));
state.send_message_err(&format!("Could not save: {e}"));
}
}
}
Expand Down Expand Up @@ -1939,7 +1938,12 @@ pub fn main_menu(ui: &mut Ui, state: &mut OculanteState, app: &mut App, gfx: &mu
.clicked()
{
_ = trash::delete(p);
state.send_message("Deleted image");
state.send_message_info(&format!(
"Deleted {}",
p.file_name()
.map(|f| f.to_string_lossy().to_string())
.unwrap_or_default()
));
}
}

Expand Down Expand Up @@ -2007,7 +2011,7 @@ pub fn main_menu(ui: &mut Ui, state: &mut OculanteState, app: &mut App, gfx: &mu
.image_sender
.send(crate::utils::Frame::new_still(image));
// Since pasted data has no path, make sure it's not set
state.send_message("Image pasted");
state.send_message_info("Image pasted");
}
} else {
state.send_message_err("Clipboard did not contain image")
Expand Down

0 comments on commit 9f8c688

Please sign in to comment.