diff --git a/Cargo.lock b/Cargo.lock index 42b35fc..1d6442d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "cairo-rs" version = "0.17.10" @@ -164,7 +170,27 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-targets 0.52.0", +] + +[[package]] +name = "const-random" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", ] [[package]] @@ -182,6 +208,42 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -797,6 +859,17 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] + [[package]] name = "libssh2-sys" version = "0.3.0" @@ -872,6 +945,17 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + [[package]] name = "nanorand" version = "0.7.0" @@ -933,6 +1017,22 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-multimap" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4d6a8c22fc714f0c2373e6091bf6f5e9b37b1bc0b1184874b7e0a4e303d318f" +dependencies = [ + "dlv-list", + "hashbrown", +] + [[package]] name = "pango" version = "0.17.10" @@ -959,6 +1059,29 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1065,6 +1188,26 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.3" @@ -1138,18 +1281,35 @@ name = "rsproject" version = "0.1.0" dependencies = [ "chrono", + "dirs", "git2", "glib-build-tools", "gtk4", "lazy_static", "libadwaita", + "once_cell", "regex", "relm4", "relm4-icons", + "rust-ini", + "serde", + "thiserror", + "tokio", + "toml", "tracker", "validator", ] +[[package]] +name = "rust-ini" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1238,6 +1398,15 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -1253,6 +1422,16 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "spin" version = "0.9.8" @@ -1329,6 +1508,15 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1351,8 +1539,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", + "bytes", + "libc", + "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -1650,7 +1857,31 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1659,51 +1890,93 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index cc23d53..79edfde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,13 @@ git2 = "0.18.2" validator = { version = "0.16.1",features=['derive'] } lazy_static = "1.4.0" regex = "1.10.3" +toml = "0.8.10" +dirs = "5.0.1" +serde = { version = "1.0.197",features = ["derive"] } +thiserror = "1.0.57" +once_cell = "1.19.0" +tokio = { version = "1.36.0",features = ["full"] } +rust-ini = "*" [build-dependencies] glib-build-tools = "0.17.0" \ No newline at end of file diff --git a/src/components/alg_page.rs b/src/components/alg_page.rs new file mode 100644 index 0000000..a2f22ce --- /dev/null +++ b/src/components/alg_page.rs @@ -0,0 +1,160 @@ +use adw::prelude::*; +use gtk::prelude::*; +use relm4::{component, component::Component, ComponentParts, ComponentSender}; +use relm4::{ + factory::FactoryView, + prelude::{DynamicIndex, FactoryComponent}, + typed_list_view::{LabelColumn, RelmColumn, TypedColumnView}, + view, FactorySender, RelmObjectExt, +}; +use std::collections::HashMap; +use ini::Ini; +use crate::utils::ini_to_table; + +#[derive(Debug)] +pub struct AlgPage { + alg_list: TypedColumnView, +} + +#[derive(Debug)] +pub enum AlgPageMsg { + New(Ini) +} + +#[component(pub)] +impl Component for AlgPage { + type Output = (); + type Init = (); + type Input = AlgPageMsg; + type CommandOutput = (); + + view! { + #[root] + gtk::Box{ + gtk::ScrolledWindow{ + #[local_ref] + #[wrap(Some)] + set_child=list_view -> gtk::ColumnView{ + set_hexpand:true, + set_vexpand:true, + set_show_column_separators: true, + set_show_row_separators: true, + set_enable_rubberband:true, + } + } + } + } + + fn init( + init: Self::Init, + root: &Self::Root, + sender: ComponentSender, + ) -> ComponentParts { + let mut alg_list = TypedColumnView::new(); + alg_list.append_column::(); + alg_list.append_column::(); + alg_list.append_column::(); + alg_list.append_column::(); + + let model = AlgPage { alg_list }; + let list_view = &model.alg_list.view; + let widgets = view_output!(); + ComponentParts { model, widgets } + } + + fn update(&mut self, message: Self::Input, sender: ComponentSender, root: &Self::Root) { + match message { + AlgPageMsg::New(ini) => { + let lists = ini_to_table(&ini); + for list in lists { + let item = AlgListItem::new(list.0,list.1,"".to_string(),"".to_string()); + self.alg_list.append(item); + } + } + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub(super) struct AlgListItem { + name: String, + description: String, + version: String, + tag: String, +} + +impl AlgListItem { + pub fn new(name: String, version: String, description: String, tag: String) -> Self { + Self { + name, + version, + description, + tag, + } + } +} + +pub(super) struct NameColumn; +pub(super) struct VersionColumn; +pub(super) struct DescriptionColumn; +pub(super) struct TagColumn; + +impl LabelColumn for TagColumn { + type Item = AlgListItem; + type Value = String; + const COLUMN_NAME: &'static str = "Tag"; + const ENABLE_SORT: bool = true; + + fn get_cell_value(item: &Self::Item) -> Self::Value { + item.tag.clone() + } + + fn format_cell_value(value: &Self::Value) -> String { + format!("{}", value) + } +} + +impl LabelColumn for NameColumn { + type Item = AlgListItem; + type Value = String; + const COLUMN_NAME: &'static str = "Name"; + const ENABLE_SORT: bool = true; + + fn get_cell_value(item: &Self::Item) -> Self::Value { + item.name.clone() + } + + fn format_cell_value(value: &Self::Value) -> String { + format!("{}", value) + } +} + +impl LabelColumn for VersionColumn { + type Item = AlgListItem; + type Value = String; + const COLUMN_NAME: &'static str = "Version"; + const ENABLE_SORT: bool = true; + + fn get_cell_value(item: &Self::Item) -> Self::Value { + item.version.clone() + } + + fn format_cell_value(value: &Self::Value) -> String { + format!("{}", value) + } +} + +impl LabelColumn for DescriptionColumn { + type Item = AlgListItem; + type Value = String; + const COLUMN_NAME: &'static str = "Description"; + const ENABLE_SORT: bool = true; + + fn get_cell_value(item: &Self::Item) -> Self::Value { + item.description.clone() + } + + fn format_cell_value(value: &Self::Value) -> String { + format!("{}", value) + } +} diff --git a/src/components/app.rs b/src/components/app.rs index 81c7593..169936d 100644 --- a/src/components/app.rs +++ b/src/components/app.rs @@ -2,8 +2,7 @@ use crate::components::new_project::NewPageModel; use adw::prelude::*; use gtk::prelude::*; use gtk::Widget; -use relm4::actions::RelmActionGroup; -use relm4::{actions::*, prelude::*, Component, ComponentParts, ComponentSender}; +use relm4::{actions::RelmActionGroup, component::{AsyncComponentController, AsyncController}, Component, ComponentParts, ComponentSender}; use std::{ any::Any, borrow::{Borrow, BorrowMut}, @@ -13,6 +12,7 @@ use std::{ rc::Rc, sync::{Arc, Mutex}, }; +use crate::components::alg_page::AlgPage; relm4::new_action_group!(FileActionGroup, "file"); relm4::new_stateless_action!(OpenAction, FileActionGroup, "open"); @@ -23,7 +23,7 @@ pub enum AppMsg { NewProject, } pub struct AppModel { - new_page_model: Controller, + new_page_model: AsyncController, tracker: usize, } @@ -139,9 +139,12 @@ impl Component for AppModel { relm4_icons::initialize_icons(); let app = relm4::main_application(); + use relm4::component::AsyncComponent; let new_page_model = NewPageModel::builder() .launch(()) .forward(sender.input_sender(), |a| AppMsg::NewProject); + + let model = AppModel { new_page_model, tracker: 0, diff --git a/src/components/history_list.rs b/src/components/history_list.rs index e69de29..8b13789 100644 --- a/src/components/history_list.rs +++ b/src/components/history_list.rs @@ -0,0 +1 @@ + diff --git a/src/components/mod.rs b/src/components/mod.rs index 1e596fd..b879e40 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,7 +1,8 @@ +mod alg_page; mod app; mod history_list; mod new_project; mod setting_item; pub use app::*; pub use new_project::*; -pub use setting_item::*; \ No newline at end of file +pub use setting_item::*; diff --git a/src/components/new_project.rs b/src/components/new_project.rs index b3e6d69..59b46ce 100644 --- a/src/components/new_project.rs +++ b/src/components/new_project.rs @@ -1,6 +1,8 @@ use crate::components::setting_item::{SettingItem, SettingType}; use crate::components::NewPageMsg::RadarEdit; use crate::config::{CommonConfig, RadarConfig}; +use crate::utils::get_alg_lists; +use gtk::prelude::*; use adw::prelude::*; use adw::{glib, PreferencesPage}; use gtk::ffi::gtk_content_fit_get_type; @@ -8,12 +10,17 @@ use gtk::glib::clone; use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt, ToggleButtonExt}; use gtk::ResponseType::No; use gtk::Widget; +use relm4::component::{AsyncComponent, AsyncComponentParts, AsyncComponentSender}; use relm4::factory::FactoryVecDeque; +use relm4::loading_widgets::LoadingWidgets; use relm4::{prelude::*, view}; use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; +use ini::Ini; use validator::Validate; +use crate::components::alg_page::{AlgPage, AlgPageMsg}; +use crate::components::AppMsg; #[tracker::track] #[derive(Debug)] @@ -22,20 +29,26 @@ pub struct NewPageModel { radar_num: usize, current_idx: usize, radar_configs: Vec>>, + #[do_not_track] + alg_page_model: Controller, + #[do_not_track] + alg_lists: Vec } #[derive(Debug)] pub enum NewPageMsg { ChangeName(String), ChangeRadarNum(usize), + ChangeAlgList(usize), CheckRadarConfig, SwitchToRadar(usize), SwitchToAlgorithm, RadarEdit(usize), + None, } -#[relm4::component(pub)] -impl Component for NewPageModel { +#[relm4::component(async, pub)] +impl AsyncComponent for NewPageModel { type Init = (); type Output = (); type Input = NewPageMsg; @@ -98,6 +111,14 @@ impl Component for NewPageModel { set_value: model.radar_num as f64, set_numeric: true, }, + #[name = "alg_list_selection"] + add=&adw::ComboRow{ + set_title: "Algorithm List", + connect_selected_notify[sender] => move |s| { + let s = s.selected(); + sender.input(NewPageMsg::ChangeAlgList(s as usize)); + } + } }, add=&adw::PreferencesGroup{ add=>k::Grid{ @@ -118,9 +139,6 @@ impl Component for NewPageModel { }, } } - }, - algorithm_setting = gtk::Box{ - }, radar_setting=gtk::Box{ set_orientation: gtk::Orientation::Vertical, @@ -131,34 +149,49 @@ impl Component for NewPageModel { }, stack.add_titled(&common_setting, Some("Common"), "Common"), stack.add_titled(&radar_setting, Some("Radar"), "Radar"), - alg_page = stack.add_titled(&algorithm_setting, Some("Algorithm"), "Algorithm") -> gtk::StackPage{ + alg_page = stack.add_titled(alg, Some("Algorithm"), "Algorithm") -> gtk::StackPage{ set_visible: false }, } - fn init( + async fn init( init: Self::Init, - root: &Self::Root, - sender: relm4::ComponentSender, - ) -> relm4::ComponentParts { + root: Self::Root, + sender: AsyncComponentSender, + ) -> AsyncComponentParts { let config = CommonConfig::default(); + let alg_page_model = AlgPage::builder().launch(()).forward(sender.input_sender(), |a| NewPageMsg::None); let mut model = NewPageModel { + alg_page_model, project_name: format!("Project {}", 0), radar_num: 1, + alg_lists: Vec::new(), radar_configs: Vec::new(), current_idx: 0, - // common_setting: config, tracker: 0, }; + let alg = model.alg_page_model.widget(); let widgets = view_output!(); - ComponentParts { model, widgets } + let alg_lts_list = get_alg_lists().await.unwrap(); + model.alg_lists = alg_lts_list; + let names = model.alg_lists + .iter() + .map(|p| { + let name = p.file_name().unwrap(); + name.to_str().unwrap() + }) + .collect::>(); + widgets + .alg_list_selection + .set_model(Some(>k::StringList::new(names.as_slice()))); + AsyncComponentParts { model, widgets } } - fn update_with_view( + async fn update_with_view( &mut self, widgets: &mut Self::Widgets, msg: Self::Input, - sender: ComponentSender, + sender: AsyncComponentSender, root: &Self::Root, ) { self.reset(); @@ -269,9 +302,17 @@ impl Component for NewPageModel { } else { widgets.alg_page.set_visible(false); let idx = un.first().unwrap(); - widgets.radar_stack.set_visible_child_name(format!("{}", idx).as_str()); + widgets + .radar_stack + .set_visible_child_name(format!("{}", idx).as_str()); } + }, + NewPageMsg::ChangeAlgList(idx) => { + let path = self.alg_lists.get(idx).unwrap(); + let ini = Ini::load_from_file(path).unwrap(); + self.alg_page_model.emit(AlgPageMsg::New(ini)); } + _ => {} } self.update_view(widgets, sender); diff --git a/src/components/setting_item/mod.rs b/src/components/setting_item/mod.rs index 3d9f487..94e0e4a 100644 --- a/src/components/setting_item/mod.rs +++ b/src/components/setting_item/mod.rs @@ -1,11 +1,11 @@ +use adw::glib::gobject_ffi::GValue; +use adw::glib::GString; use adw::prelude::*; use gtk::prelude::*; use gtk::{StringList, Widget}; use relm4::{factory::FactoryView, gtk, prelude::*, FactorySender, RelmObjectExt}; use std::cell::{Cell, RefCell}; use std::rc::Rc; -use adw::glib::gobject_ffi::GValue; -use adw::glib::GString; #[derive(Debug)] pub enum Msg {} @@ -69,7 +69,7 @@ impl SettingItem { s.remove_css_class("error"); } - if let Some(buffer) = buffer.as_ref(){ + if let Some(buffer) = buffer.as_ref() { buffer(text.as_str()); } }); diff --git a/src/config.rs b/src/config.rs index 8796866..372a868 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,7 +12,6 @@ lazy_static! { r"^\s*(0|[1-9]\d*)(\.\d+)?\s*,\s*(0|[1-9]\d*)(\.\d+)?\s*,\s*(0|[1-9]\d*)(\.\d+)?\s*$" ) .unwrap(); - static ref RADAR_TYPES: Vec<&'static str> = vec!["X", "S", "C"]; } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..8773085 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,21 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum SettingError { + #[error("IO Error: {0}")] + IOErr(#[from] std::io::Error), + #[error("Config Format is wrong;")] + FormatError(#[from] toml::de::Error), + #[error("Can't locate default config;")] + CantLocateDefaultConfig, +} + +#[derive(Debug, Error)] +pub enum SourceError { + #[error("IO Error: {0}")] + IOErr(#[from] std::io::Error), + #[error("can't sync cause of {0}")] + SyncError(#[from] git2::Error), + #[error("can't sync cause of {0}")] + TokioError(#[from] tokio::task::JoinError), +} diff --git a/src/main.rs b/src/main.rs index 8d80e04..0fc909d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,23 @@ #![allow(unused)] #![allow(dead_code)] use gtk::{ - gio::{self, Settings}, + gio::{self}, prelude::SettingsExt, }; -use std::{ptr, sync::Mutex}; + mod components; mod config; +mod error; +mod setting; +mod utils; mod widgets; +use crate::setting::Config; use components::AppModel; +use once_cell::{sync::Lazy as SafeLazy, unsync::Lazy as UnsafeLazy}; +use std::sync::Mutex; + +static CONFIG: SafeLazy> = SafeLazy::new(|| Mutex::new(Config::from_env().unwrap())); const APP_ID: &str = "org.tsuki.rsproject"; fn main() { diff --git a/src/setting.rs b/src/setting.rs new file mode 100644 index 0000000..d16d009 --- /dev/null +++ b/src/setting.rs @@ -0,0 +1,67 @@ +use crate::error::SettingError; +use dirs::home_dir; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::env; +use std::io::Write; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Config { + pub alg_list_repo: String, + pub source_list_loc: PathBuf, +} + +impl Default for Config { + fn default() -> Self { + let default_source_list_loc = home_dir().unwrap().join(".cache/rsp/lts"); + Self { + alg_list_repo: "http://192.168.1.70:6020/awesomeradaralgorithms/lts.git".to_string(), + source_list_loc: default_source_list_loc, + } + } +} +impl Config { + fn from_file(path: impl AsRef) -> Result { + let file = std::fs::read_to_string(path)?; + let config = toml::from_str(&file)?; + Ok(config) + } + + pub fn from_env() -> Result { + if let Some(dir_path) = env::var("RADARG_CONFIG") + .ok() + .map(|x| PathBuf::from(x)) + .or(dirs::config_dir()) + { + let path = dir_path.join("rsp.toml"); + if path.exists() { + return Ok(Self::from_file(path)?); + } else { + let default_config = Config::default(); + let mut file = std::fs::File::create(path)?; + let ser_config = toml::to_string_pretty(&default_config).unwrap(); + file.write_all(ser_config.as_bytes()); + return Ok(default_config); + } + } + + Err(SettingError::CantLocateDefaultConfig) + } + + pub fn save(&self) -> Result<(), SettingError> { + if let Some(dir_path) = env::var("RADARG_CONFIG") + .ok() + .map(|x| PathBuf::from(x)) + .or(dirs::config_dir()) + { + let path = dir_path.join("rsp.toml"); + let mut file = std::fs::File::create(path)?; + let ser_config = toml::to_string_pretty(&self).unwrap(); + file.write_all(ser_config.as_bytes()); + Ok(()) + } else { + Err(SettingError::CantLocateDefaultConfig) + } + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..fc8f27c --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,78 @@ +use crate::error::SourceError; +use crate::CONFIG; +use git2::{Cred, FetchOptions, RemoteCallbacks, Repository}; +use std::path::PathBuf; +use ini::Ini; +use tokio::task; + +pub async fn get_alg_lists() -> Result, SourceError> { + let (repo, loc) = { + let config = CONFIG.lock().unwrap(); + (config.alg_list_repo.clone(), config.source_list_loc.clone()) + }; + + let loc_cp = loc.clone(); + let handler = task::spawn_blocking(move || { + if loc.exists() && loc.is_dir() { + let repo = Repository::open(loc); + { + if let Ok(repo) = repo.as_ref() { + let mut fetch_options = FetchOptions::new(); + let mut callbacks = RemoteCallbacks::new(); + callbacks.credentials(|_url, username_from_url, _allowed_types| { + Cred::ssh_key( + username_from_url.unwrap(), + None, + std::path::Path::new(&format!( + "{}/.ssh/id_rsa", + std::env::var("HOME").unwrap() + )), + None, + ) + }); + fetch_options.remote_callbacks(callbacks); + let mut remote = repo.find_remote("origin").unwrap(); + remote + .fetch( + &["refs/heads/*:refs/heads/*"], + Some(&mut fetch_options), + None, + ) + .unwrap(); + } + } + repo + } else { + Repository::clone(&repo, loc) + } + }); + let repo = handler.await??; + let mut list = Vec::new(); + for entry in std::fs::read_dir(&loc_cp)? { + let entry = entry?; + let path = entry.path(); + if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("ini") { + list.push(path); + } + } + Ok(list) +} + +pub fn ini_to_table(ini: &Ini) -> Vec<(String,String)> { + let mut result = Vec::new(); + let lib_sec = ini.section(Some("lib")); + let alg_sec = ini.section(Some("algorithms")); + + if let Some(lib) = lib_sec{ + for (key,value) in lib.iter(){ + result.push((key.to_string(), value.to_string())); + } + } + + if let Some(alg) = alg_sec{ + for (key,value) in alg.iter(){ + result.push((key.to_string(), value.to_string())); + } + } + result +}