184 lines
5.9 KiB
Rust
184 lines
5.9 KiB
Rust
|
use std::collections::{VecDeque};
|
||
|
use std::fs;
|
||
|
use std::time::SystemTime;
|
||
|
use directories::ProjectDirs;
|
||
|
use eframe::Frame;
|
||
|
use egui::{Context, RichText};
|
||
|
use log::info;
|
||
|
use simple_logger::SimpleLogger;
|
||
|
use crate::notes::{Note, NoteMetadata};
|
||
|
use crate::saving::Saving;
|
||
|
|
||
|
mod notes;
|
||
|
mod saving;
|
||
|
|
||
|
#[derive(PartialEq)]
|
||
|
enum CurrentMode {
|
||
|
View,
|
||
|
Compose,
|
||
|
PasswordInput,
|
||
|
}
|
||
|
|
||
|
struct App {
|
||
|
notes: Vec<Note>,
|
||
|
password: Option<String>,
|
||
|
tested_password: bool,
|
||
|
mode: CurrentMode,
|
||
|
saving: Saving,
|
||
|
|
||
|
password_buffer: String,
|
||
|
|
||
|
title_buffer: String,
|
||
|
text_buffer: String,
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
SimpleLogger::new().init().expect("failed to initialize logger");
|
||
|
|
||
|
info!("starting the UI");
|
||
|
|
||
|
let options = eframe::NativeOptions {
|
||
|
initial_window_size: Some(egui::vec2(640.0, 640.0)),
|
||
|
..Default::default()
|
||
|
};
|
||
|
|
||
|
let project_directories = ProjectDirs::from("com", "sofiaritz", "notes")
|
||
|
.unwrap();
|
||
|
|
||
|
let data_directory = project_directories
|
||
|
.data_dir();
|
||
|
info!("data directory: {:?}", data_directory);
|
||
|
|
||
|
fs::create_dir_all(data_directory).unwrap();
|
||
|
info!("created all intermediate directories");
|
||
|
|
||
|
let saving = Saving::new(data_directory);
|
||
|
let notes = saving.read_notes().unwrap();
|
||
|
info!("successfully read initial notes");
|
||
|
|
||
|
let app = App {
|
||
|
password: None,
|
||
|
tested_password: false,
|
||
|
notes,
|
||
|
mode: CurrentMode::PasswordInput,
|
||
|
saving,
|
||
|
|
||
|
password_buffer: String::new(),
|
||
|
|
||
|
title_buffer: String::new(),
|
||
|
text_buffer: String::new(),
|
||
|
};
|
||
|
|
||
|
eframe::run_native(
|
||
|
"notes",
|
||
|
options,
|
||
|
Box::new(move |_cc| Box::new(app))
|
||
|
).expect("failed to run native");
|
||
|
|
||
|
info!("shutdown");
|
||
|
}
|
||
|
|
||
|
impl eframe::App for App {
|
||
|
fn update(&mut self, ctx: &Context, _frame: &mut Frame) {
|
||
|
if self.password.is_none() {
|
||
|
self.mode = CurrentMode::PasswordInput;
|
||
|
}
|
||
|
|
||
|
if !self.tested_password && self.password.is_some() {
|
||
|
if let Some(note) = self.notes.get(0) {
|
||
|
note.decrypt(self.password.as_ref().unwrap()).unwrap();
|
||
|
self.tested_password = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
match self.mode {
|
||
|
CurrentMode::View => {
|
||
|
let password = self.password.as_ref().unwrap();
|
||
|
|
||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||
|
ui.heading("notes");
|
||
|
ui.horizontal(|ui| {
|
||
|
ui.label("the simple note taking app that uses encryption by default");
|
||
|
ui.add_space(7.5);
|
||
|
if ui.button("want to add one note?").clicked() {
|
||
|
self.mode = CurrentMode::Compose;
|
||
|
}
|
||
|
});
|
||
|
ui.separator();
|
||
|
|
||
|
for note in &mut self.notes {
|
||
|
if let Some(new_note) = note.render(ui, password) {
|
||
|
*note = new_note;
|
||
|
}
|
||
|
ui.add_space(10.0);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
CurrentMode::Compose => {
|
||
|
let password = self.password.as_ref().unwrap();
|
||
|
|
||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||
|
ui.heading("notes");
|
||
|
ui.horizontal(|ui| {
|
||
|
ui.label("the simple note taking app that uses encryption by default");
|
||
|
ui.add_space(7.5);
|
||
|
if ui.button("return to view mode?").clicked() {
|
||
|
self.title_buffer = String::new();
|
||
|
self.text_buffer = String::new();
|
||
|
self.mode = CurrentMode::View;
|
||
|
}
|
||
|
});
|
||
|
ui.separator();
|
||
|
|
||
|
ui.label("title:");
|
||
|
ui.text_edit_singleline(&mut self.title_buffer);
|
||
|
|
||
|
ui.label("text:");
|
||
|
ui.text_edit_multiline(&mut self.text_buffer);
|
||
|
|
||
|
ui.add_space(10.0);
|
||
|
if ui.button("add note").clicked() {
|
||
|
let note = Note::Decrypted {
|
||
|
title: self.title_buffer.clone(),
|
||
|
metadata: NoteMetadata {
|
||
|
date: SystemTime::now(),
|
||
|
arbitrary: None,
|
||
|
},
|
||
|
text: self.text_buffer.clone(),
|
||
|
};
|
||
|
|
||
|
self.saving.save_note(note.clone(), password.to_string()).unwrap();
|
||
|
|
||
|
let mut vec_deque = VecDeque::from(self.notes.clone());
|
||
|
vec_deque.push_front(note);
|
||
|
|
||
|
self.notes = Vec::from(vec_deque);
|
||
|
|
||
|
self.title_buffer = String::new();
|
||
|
self.text_buffer = String::new();
|
||
|
self.mode = CurrentMode::View;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
CurrentMode::PasswordInput => {
|
||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||
|
ui.heading("notes");
|
||
|
ui.label("the simple note taking app that uses encryption by default");
|
||
|
ui.separator();
|
||
|
|
||
|
ui.label("you need to put your password to access the notes");
|
||
|
ui.label(RichText::new("after starting the app, the password will be tested against the latest note").italics());
|
||
|
|
||
|
ui.add_space(10.0);
|
||
|
ui.text_edit_singleline(&mut self.password_buffer);
|
||
|
|
||
|
if ui.button("start app").clicked() {
|
||
|
self.password = Some(self.password_buffer.clone());
|
||
|
self.password_buffer = String::new();
|
||
|
self.mode = CurrentMode::View;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|