Make relm4 app async and update last_opened in db

This commit is contained in:
2024-02-07 20:05:20 +01:00
parent 603864e7f6
commit bea97b55f3
6 changed files with 88 additions and 30 deletions

View File

@ -59,6 +59,15 @@ impl Database {
.await .await
.map(|_| ()) .map(|_| ())
} }
pub async fn update_sheet_last_opened(&self, sheet: &Sheet) -> sqlx::Result<()> {
sqlx::query("UPDATE sheets SET last_opened = $1 WHERE id = $2")
.bind(sheet.last_opened.timestamp())
.bind(sheet.id)
.execute(&self.connection)
.await
.map(|_| ())
// TODO: check for success
}
pub async fn fetch_all_sheets(&self) -> sqlx::Result<Vec<Sheet>> { pub async fn fetch_all_sheets(&self) -> sqlx::Result<Vec<Sheet>> {
sqlx::query_as::<_, Sheet>("SELECT * FROM sheets") sqlx::query_as::<_, Sheet>("SELECT * FROM sheets")
@ -82,15 +91,25 @@ impl Database {
.map(|result| result.last_insert_rowid()) .map(|result| result.last_insert_rowid())
} }
pub async fn update_orphan_file_path(&self, file: &OrphanFile) -> sqlx::Result<()> { pub async fn update_orphan_file_path(&self, orphan: &OrphanFile) -> sqlx::Result<()> {
sqlx::query("UPDATE orphan_files SET path = $1 WHERE id = $2") sqlx::query("UPDATE orphan_files SET path = $1 WHERE id = $2")
.bind(file.path.to_str().unwrap().to_string()) .bind(orphan.path.to_str().unwrap().to_string())
.bind(file.id) .bind(orphan.id)
.execute(&self.connection) .execute(&self.connection)
.await .await
.map(|_| ()) .map(|_| ())
} }
pub async fn update_orphan_last_opened(&self, orphan: &OrphanFile) -> sqlx::Result<()> {
sqlx::query("UPDATE orphan_files SET last_opened = $1 WHERE id = $2")
.bind(orphan.last_opened.timestamp())
.bind(orphan.id)
.execute(&self.connection)
.await
.map(|_| ())
// TODO: check for success
}
pub async fn fetch_all_orphan_files(&self) -> sqlx::Result<Vec<OrphanFile>> { pub async fn fetch_all_orphan_files(&self) -> sqlx::Result<Vec<OrphanFile>> {
sqlx::query_as::<_, OrphanFile>("SELECT * FROM orphan_files") sqlx::query_as::<_, OrphanFile>("SELECT * FROM orphan_files")
.fetch_all(&self.connection) .fetch_all(&self.connection)

View File

@ -59,17 +59,22 @@ async fn main() {
let mut sheets = validation_result.validated_sheets; let mut sheets = validation_result.validated_sheets;
sheets.append(&mut validation_result.updated_sheets); sheets.append(&mut validation_result.updated_sheets);
let sheets_and_orphans = SheetsAndOrphans { sheets, orphans }; let app_init_data = AppInitData {
sheets,
orphans,
database,
};
let app = RelmApp::new("de.frajul.sheet-organizer"); let app = RelmApp::new("de.frajul.sheet-organizer");
// Pass empty command line args to allow my own parsing // Pass empty command line args to allow my own parsing
app.with_args(Vec::new()) app.with_args(Vec::new())
.run::<AppModel>(sheets_and_orphans); .run_async::<AppModel>(app_init_data);
} }
pub struct SheetsAndOrphans { pub struct AppInitData {
sheets: Vec<Sheet>, sheets: Vec<Sheet>,
orphans: Vec<OrphanFile>, orphans: Vec<OrphanFile>,
database: Database,
} }
pub struct FileValidationResult { pub struct FileValidationResult {

View File

@ -1,9 +1,15 @@
use chrono::Utc;
use gtk::prelude::*; use gtk::prelude::*;
use relm4::prelude::*; use relm4::{
component::{AsyncComponent, AsyncComponentParts},
prelude::*,
AsyncComponentSender,
};
use crate::{ use crate::{
database::Database,
ui::{mcdu::McduOutput, sheet_model::SheetModelType}, ui::{mcdu::McduOutput, sheet_model::SheetModelType},
SheetsAndOrphans, AppInitData,
}; };
use super::{ use super::{
@ -12,6 +18,7 @@ use super::{
}; };
pub struct AppModel { pub struct AppModel {
database: Database,
mcdu: Controller<McduModel>, mcdu: Controller<McduModel>,
sheets_and_files_listing: Controller<SheetListingModel>, sheets_and_files_listing: Controller<SheetListingModel>,
new_files_listing: Controller<SheetListingModel>, new_files_listing: Controller<SheetListingModel>,
@ -24,11 +31,12 @@ pub enum AppInput {
SheetsAndFilesSheetPressed(SheetModelType), SheetsAndFilesSheetPressed(SheetModelType),
} }
#[relm4::component(pub)] #[relm4::component(pub, async)]
impl SimpleComponent for AppModel { impl AsyncComponent for AppModel {
type Input = AppInput; type Input = AppInput;
type Output = (); type Output = ();
type Init = SheetsAndOrphans; type Init = AppInitData;
type CommandOutput = ();
view! { view! {
#[root] #[root]
@ -66,11 +74,11 @@ impl SimpleComponent for AppModel {
} }
} }
fn init( async fn init(
sheets_and_orphans: Self::Init, init_data: Self::Init,
window: &Self::Root, window: Self::Root,
sender: ComponentSender<Self>, sender: AsyncComponentSender<Self>,
) -> relm4::ComponentParts<Self> { ) -> AsyncComponentParts<Self> {
relm4_icons::initialize_icons(); relm4_icons::initialize_icons();
let mcdu = McduModel::builder() let mcdu = McduModel::builder()
@ -79,7 +87,7 @@ impl SimpleComponent for AppModel {
McduOutput::SearchStarted(query) => AppInput::SearchStarted(query), McduOutput::SearchStarted(query) => AppInput::SearchStarted(query),
}); });
let new_files: Vec<SheetModelType> = sheets_and_orphans let new_files: Vec<SheetModelType> = init_data
.orphans .orphans
.iter() .iter()
.map(|orphan| SheetModelType::Orphan { .map(|orphan| SheetModelType::Orphan {
@ -87,12 +95,12 @@ impl SimpleComponent for AppModel {
}) })
.collect(); .collect();
let new_files_clone_iter = sheets_and_orphans let new_files_clone_iter = init_data
.orphans .orphans
.into_iter() .into_iter()
.map(|orphan| SheetModelType::Orphan { orphan }); .map(|orphan| SheetModelType::Orphan { orphan });
let sheets_and_files: Vec<SheetModelType> = sheets_and_orphans let sheets_and_files: Vec<SheetModelType> = init_data
.sheets .sheets
.into_iter() .into_iter()
.map(|sheet| SheetModelType::Sheet { sheet }) .map(|sheet| SheetModelType::Sheet { sheet })
@ -111,6 +119,7 @@ impl SimpleComponent for AppModel {
}); });
let model = AppModel { let model = AppModel {
database: init_data.database,
mcdu, mcdu,
sheets_and_files_listing, sheets_and_files_listing,
new_files_listing, new_files_listing,
@ -118,10 +127,15 @@ impl SimpleComponent for AppModel {
let widgets = view_output!(); let widgets = view_output!();
ComponentParts { model, widgets } AsyncComponentParts { model, widgets }
} }
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) { async fn update(
&mut self,
message: Self::Input,
sender: AsyncComponentSender<Self>,
_root: &Self::Root,
) {
// AppInput::SheetPressed(sheet) => opener::open(sheet).unwrap(), // AppInput::SheetPressed(sheet) => opener::open(sheet).unwrap(),
match message { match message {
AppInput::SearchStarted(query) => { AppInput::SearchStarted(query) => {
@ -133,7 +147,23 @@ impl SimpleComponent for AppModel {
// TODO // TODO
} }
AppInput::SheetsAndFilesSheetPressed(sheet_model_type) => { AppInput::SheetsAndFilesSheetPressed(sheet_model_type) => {
opener::open(sheet_model_type.get_path()).unwrap() opener::open(sheet_model_type.get_path()).unwrap();
match sheet_model_type {
SheetModelType::Orphan { mut orphan } => {
orphan.last_opened = Utc::now();
self.database
.update_orphan_last_opened(&orphan)
.await
.unwrap();
}
SheetModelType::Sheet { mut sheet } => {
sheet.last_opened = Utc::now();
self.database
.update_sheet_last_opened(&sheet)
.await
.unwrap();
}
};
} }
} }
} }

View File

@ -1,4 +1,5 @@
pub mod app; pub mod app;
pub mod database_worker;
pub mod mcdu; pub mod mcdu;
pub mod sheet_listing; pub mod sheet_listing;
pub mod sheet_model; pub mod sheet_model;

View File

@ -66,7 +66,6 @@ impl SimpleComponent for SheetListingModel {
} }
SheetListingInput::ListBoxRowClicked(index) => { SheetListingInput::ListBoxRowClicked(index) => {
let x = self.sheets.get(index as usize).unwrap(); let x = self.sheets.get(index as usize).unwrap();
debug!("clicked: {}!!!!!", x.label);
sender sender
.output(SheetModelSelected { .output(SheetModelSelected {
sheet_model_type: x.sheet_model_type.clone(), sheet_model_type: x.sheet_model_type.clone(),

View File

@ -64,13 +64,17 @@ impl FactoryComponent for SheetModel {
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self { fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
let label = match &value { let label = match &value {
SheetModelType::Sheet { sheet } => sheet.name.to_string(), SheetModelType::Sheet { sheet } => sheet.name.to_string(),
SheetModelType::Orphan { orphan } => orphan SheetModelType::Orphan { orphan } => {
.path orphan
.file_name() .path
.unwrap() .file_name()
.to_str() .unwrap()
.unwrap() .to_str()
.to_string(), .unwrap()
.to_string()
+ " "
+ &orphan.last_opened.to_string()
}
}; };
SheetModel { SheetModel {