use std::sync::{Arc, Mutex};
use crate::img::{load_image_from_url, darken_image, create_egui_texture_from_image, ImageError};
use egui::{Context as EguiContext, TextureHandle};
use log::{info, warn};
#[derive(serde::Deserialize, serde::Serialize, Default)]
pub struct AppState {
pub counter: i32,
pub username: String,
pub email: String,
pub session_id: Option<String>, pub bio: String,
pub avatar_url: Option<String>,
pub label: String,
pub value: f32,
pub is_dark_mode: bool,
#[serde(skip)]
pub is_image_loaded: bool,
pub is_loading_image: Arc<Mutex<bool>>,
#[serde(skip)]
pub load_error: Arc<Mutex<Option<String>>>,
#[serde(skip)]
pub image_texture: Arc<Mutex<Option<egui::TextureHandle>>>,
}
impl AppState {
pub fn new() -> Self {
Self {
counter: 1,
username: String::new(),
email: String::new(),
session_id: None,
bio: String::new(),
avatar_url: None,
label: "Hello World!".to_owned(),
value: 2.7,
is_dark_mode: true, is_image_loaded: false,
is_loading_image: Arc::new(Mutex::new(false)),
load_error: Arc::new(Mutex::new(None)),
image_texture: Arc::new(Mutex::new(None)),
}
}
pub fn increment_counter(&mut self) {
self.counter += 1;
}
pub fn save(&self, storage: &mut dyn eframe::Storage) {
if let Ok(serialized) = serde_json::to_string(self) {
storage.set_string(eframe::APP_KEY, serialized);
}
}
pub fn load(storage: Option<&dyn eframe::Storage>) -> Option<Self> {
if let Some(storage) = storage {
if let Some(serialized) = storage.get_string(eframe::APP_KEY) {
return serde_json::from_str(&serialized).ok();
}
}
None
}
pub fn load_image(&mut self, ctx: &egui::Context, url: &str) {
let texture_handle = self.image_texture.clone();
let loading_flag = self.is_loading_image.clone();
let error_flag = self.load_error.clone();
*loading_flag.lock().unwrap() = true;
*error_flag.lock().unwrap() = None;
let ctx_clone = ctx.clone();
load_image_from_url(url, move |result| {
match result {
Ok(dynamic_image) => {
let rgba_image = dynamic_image.to_rgba8();
let texture = create_egui_texture_from_image(&ctx_clone, rgba_image);
*texture_handle.lock().unwrap() = Some(texture);
}
Err(error) => {
warn!("Error loading image: {:?}", error); *error_flag.lock().unwrap() = Some(match error {
ImageError::NetworkError(msg) if msg == "Empty response" =>
"Image not found or empty response".to_string(),
_ => format!("Failed to load image: {:?}", error),
});
}
}
*loading_flag.lock().unwrap() = false;
});
}
pub fn load_image_from_base64(&mut self, ctx: &egui::Context, base64_string: &str) {
let texture_handle = self.image_texture.clone();
let loading_flag = self.is_loading_image.clone();
let error_flag = self.load_error.clone();
*loading_flag.lock().unwrap() = true;
*error_flag.lock().unwrap() = None;
let ctx_clone = ctx.clone();
match base64::decode(base64_string) {
Ok(image_data) => {
match image::load_from_memory(&image_data) {
Ok(dynamic_image) => {
let rgba_image = dynamic_image.to_rgba8();
let texture = create_egui_texture_from_image(&ctx_clone, rgba_image);
*texture_handle.lock().unwrap() = Some(texture);
}
Err(error) => {
warn!("Error processing image: {:?}", error);
*error_flag.lock().unwrap() = Some(format!("Failed to process image: {:?}", error));
}
}
}
Err(error) => {
warn!("Error decoding Base64: {:?}", error);
*error_flag.lock().unwrap() = Some(format!("Failed to decode Base64: {:?}", error));
}
}
*loading_flag.lock().unwrap() = false;
}
}