cleanup code and simplify application to be ready for restructuring and refactoring

This commit is contained in:
2023-07-15 12:52:01 +02:00
parent 33107d295c
commit 132860c33f
26 changed files with 332 additions and 771 deletions

View File

@@ -2,11 +2,11 @@ use std::collections::VecDeque;
use relm4::gtk::{Application, ApplicationWindow};
use relm4::{factory::FactoryVecDeque, RelmApp};
use toolbx::ToolbxContainer;
use ui::app::model::AppModel;
use util::toolbx::ToolbxContainer;
mod toolbx;
mod ui;
mod util;
fn main() {
let toolbx_list = VecDeque::from(ToolbxContainer::get_toolboxes());

View File

@@ -1,12 +1,10 @@
use relm4::factory::DynamicIndex;
use crate::toolbx::ToolbxContainer;
use crate::util::toolbx::ToolbxContainer;
use super::model::ToolbxEntry;
pub enum AppMsg {
ShowToolboxSettingsRequest(DynamicIndex),
ShowToolboxAppsRequest,
ToolbxListUpdate(Vec<ToolbxContainer>),
ToolbxContainerToggleStartStop(DynamicIndex),
OpenToolbxTerminal(DynamicIndex),

View File

@@ -1,6 +1,6 @@
use relm4::{factory::FactoryVecDeque, Model};
use crate::{toolbx::ToolbxContainer, ui::components::AppComponents};
use crate::{ui::components::AppComponents, util::toolbx::ToolbxContainer};
use super::{messages::AppMsg, widgets::AppWidgets};

View File

@@ -9,11 +9,11 @@ use relm4::{
};
use crate::{
toolbx::ToolbxStatus,
ui::ui_strings::{
APP_ICON, APP_TOOLTIP, SETTINGS_ICON, SETTINGS_TOOLTIP, SHUTDOWN_ICON, SHUTDOWN_TOOLTIP,
START_ICON, START_TOOLTIP, TERMINAL_ICON, TERMINAL_TOOLTIP, UPDATE_ICON, UPDATE_TOOLTIP,
},
util::toolbx::ToolbxStatus,
};
use super::{messages::AppMsg, model::ToolbxEntry};
@@ -38,20 +38,6 @@ impl FactoryPrototype for ToolbxEntry {
view! {
suffix_box = &gtk::Box{
/* application menu
append = &gtk::AspectFrame{
set_ratio: 1.0,
set_child = Some(&gtk::Button::from_icon_name(APP_ICON)) {
set_margin_start: 10,
set_margin_top: 10,
set_margin_bottom: 10,
set_tooltip_text: Some(APP_TOOLTIP),
set_css_classes: &["flat"],
connect_clicked(sender) => move |btn| {
send!(sender, AppMsg::ShowToolboxAppsRequest);
},
}
},*/
append = &gtk::AspectFrame{
set_ratio: 1.0,
set_child = Some(&gtk::Button::from_icon_name(TERMINAL_ICON)) {
@@ -65,40 +51,8 @@ impl FactoryPrototype for ToolbxEntry {
},
}
},
append = &gtk::AspectFrame{
set_ratio: 1.0,
set_child = Some(&gtk::Button::from_icon_name(SETTINGS_ICON)) {
set_margin_start: 10,set_margin_start: 10,
set_margin_top: 10,
set_margin_bottom: 10,
set_tooltip_text: Some(SETTINGS_TOOLTIP),
set_css_classes: &["circular"],
connect_clicked(sender) => move |btn| {
send!(sender, AppMsg::ShowToolboxSettingsRequest(index_settings.clone()));
},
},
}
}
};
/*
if self.update_available {
view! {
update_button = &gtk::AspectFrame{
set_ratio: 1.0,
set_child = Some(&gtk::Button::from_icon_name(UPDATE_ICON)) {
set_margin_top: 10,
set_margin_bottom: 10,
set_margin_end: 10,
set_tooltip_text: Some(UPDATE_TOOLTIP),
set_css_classes: &["suggested-action"],
}
}
};
suffix_box.prepend(&update_button);
}
*/
let mut status_button_tooltip = START_TOOLTIP;
let mut status_button_icon = START_ICON;

View File

@@ -2,35 +2,13 @@ use std::process::Command;
use relm4::{AppUpdate, Sender};
use crate::{
toolbx::ToolbxStatus,
ui::components::{
toolbox_apps::messages::ToolboxAppDialogMsg,
toolbox_settings::messages::ToolboxSettingsDialogMsg, AppComponents,
},
};
use crate::{ui::components::AppComponents, util::toolbx::ToolbxStatus};
use super::{messages::AppMsg, model::AppModel, workers::AsyncHandlerMsg};
impl AppUpdate for AppModel {
fn update(&mut self, msg: AppMsg, components: &AppComponents, _sender: Sender<AppMsg>) -> bool {
match msg {
AppMsg::ShowToolboxSettingsRequest(index) => {
if let Some(toolbx_entry) = self.toolboxes.get(index.current_index()) {
components
.toolbox_settings_dialog
.send(ToolboxSettingsDialogMsg::Show(
toolbx_entry.toolbx_container.clone(),
))
.unwrap();
}
}
AppMsg::ShowToolboxAppsRequest => {
components
.toolbox_apps_dialog
.send(ToolboxAppDialogMsg::Show)
.unwrap();
}
AppMsg::ToolbxContainerToggleStartStop(index) => {
if let Some(toolbx_container) = self.toolboxes.get_mut(index.current_index()) {
match toolbx_container.toolbx_container.status {

View File

@@ -5,7 +5,7 @@ use relm4::{send, MessageHandler, Sender};
use tokio::runtime::{Builder, Runtime};
use tokio::sync::mpsc::{channel, Sender as TokioSender};
use crate::toolbx::ToolbxContainer;
use crate::util::toolbx::ToolbxContainer;
use super::{
messages::AppMsg,

11
src/ui/components.rs Normal file
View File

@@ -0,0 +1,11 @@
use relm4::RelmComponent;
use relm4::RelmMsgHandler;
use relm4::Sender;
use super::app::model::AppModel;
use super::app::workers::AsyncHandler;
#[derive(relm4::Components)]
pub struct AppComponents {
pub async_handler: RelmMsgHandler<AsyncHandler, AppModel>,
}

View File

@@ -1,20 +0,0 @@
use relm4::RelmComponent;
use relm4::RelmMsgHandler;
use relm4::Sender;
use self::{
toolbox_apps::model::ToolboxAppDialogModel, toolbox_settings::model::ToolboxSettingsDialogModel,
};
use super::app::model::AppModel;
use super::app::workers::AsyncHandler;
pub mod toolbox_apps;
pub mod toolbox_settings;
#[derive(relm4::Components)]
pub struct AppComponents {
pub toolbox_settings_dialog: RelmComponent<ToolboxSettingsDialogModel, AppModel>,
pub toolbox_apps_dialog: RelmComponent<ToolboxAppDialogModel, AppModel>,
pub async_handler: RelmMsgHandler<AsyncHandler, AppModel>,
}

View File

@@ -1,82 +0,0 @@
use relm4::{
adw::prelude::{BoxExt, OrientableExt, WidgetExt},
factory::{FactoryPrototype, FactoryVec},
gtk::{self, Orientation},
view, Sender, WidgetPlus,
};
use super::{
messages::ToolboxAppDialogMsg, model::DotDesktopApplication, widgets::AppFactoryWidgets,
};
impl FactoryPrototype for DotDesktopApplication {
type Factory = FactoryVec<Self>;
type Widgets = AppFactoryWidgets;
type Root = gtk::Box;
type View = gtk::FlowBox;
type Msg = ToolboxAppDialogMsg;
fn init_view(
&self,
key: &<Self::Factory as relm4::factory::Factory<Self, Self::View>>::Key,
sender: Sender<Self::Msg>,
) -> Self::Widgets {
view! {
app_box = &gtk::Box {
set_css_classes: &[&"card"],
set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center,
set_orientation: Orientation::Vertical,
set_hexpand: false,
set_vexpand: false,
set_width_request: 100,
set_height_request: 100,
append = &gtk::Switch {
set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center,
set_hexpand: false,
set_vexpand: false,
set_margin_all: 10,
set_active: self.selected,
},
append = &gtk::Image::from_file(&self.icon_path) {
set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center,
set_width_request: 64,
set_height_request: 64,
set_margin_start: 36,
set_margin_end: 36,
set_hexpand: false,
set_vexpand: false,
},
append = &gtk::Label {
set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center,
set_text: &self.name,
set_margin_all: 5,
set_hexpand: false,
set_vexpand: false,
}
}
}
AppFactoryWidgets { app_box }
}
fn position(
&self,
key: &<Self::Factory as relm4::factory::Factory<Self, Self::View>>::Key,
) -> <Self::View as relm4::factory::FactoryView<Self::Root>>::Position {
}
fn view(
&self,
key: &<Self::Factory as relm4::factory::Factory<Self, Self::View>>::Key,
widgets: &Self::Widgets,
) {
}
fn root_widget(widgets: &Self::Widgets) -> &Self::Root {
&widgets.app_box
}
}

View File

@@ -1,4 +0,0 @@
pub enum ToolboxAppDialogMsg {
Show,
Close,
}

View File

@@ -1,5 +0,0 @@
pub mod factory;
pub mod messages;
pub mod model;
pub mod update;
pub mod widgets;

View File

@@ -1,20 +0,0 @@
use relm4::{factory::FactoryVec, Model};
use super::{messages::ToolboxAppDialogMsg, widgets::ToolboxAppDialogWidgets};
#[derive(Default)]
pub struct DotDesktopApplication {
pub name: String,
pub selected: bool,
pub icon_path: String,
}
pub struct ToolboxAppDialogModel {
pub hidden: bool,
pub apps: FactoryVec<DotDesktopApplication>,
}
impl Model for ToolboxAppDialogModel {
type Msg = ToolboxAppDialogMsg;
type Widgets = ToolboxAppDialogWidgets;
type Components = ();
}

View File

@@ -1,51 +0,0 @@
use relm4::{factory::FactoryVec, ComponentUpdate, Sender};
use crate::ui::app::{messages::AppMsg, model::AppModel};
use super::{
messages::ToolboxAppDialogMsg,
model::{DotDesktopApplication, ToolboxAppDialogModel},
};
impl ComponentUpdate<AppModel> for ToolboxAppDialogModel {
fn init_model(_parent_model: &AppModel) -> Self {
let mut factory_vec = FactoryVec::new();
factory_vec.push(DotDesktopApplication {
name: "Firefox".to_string(),
selected: true,
icon_path: "".to_string(),
});
factory_vec.push(DotDesktopApplication {
name: "Firefox".to_string(),
selected: false,
icon_path: "".to_string(),
});
factory_vec.push(DotDesktopApplication {
name: "Firefox".to_string(),
selected: true,
icon_path: "".to_string(),
});
factory_vec.push(DotDesktopApplication {
name: "Firefox".to_string(),
selected: false,
icon_path: "".to_string(),
});
ToolboxAppDialogModel {
hidden: true,
apps: factory_vec,
}
}
fn update(
&mut self,
msg: ToolboxAppDialogMsg,
_components: &(),
_sender: Sender<ToolboxAppDialogMsg>,
parent_sender: Sender<AppMsg>,
) {
match msg {
ToolboxAppDialogMsg::Show => self.hidden = false,
ToolboxAppDialogMsg::Close => self.hidden = true,
}
}
}

View File

@@ -1,63 +0,0 @@
use gtk::Orientation;
use gtk::PolicyType;
use relm4::adw;
use relm4::adw::prelude::GtkWindowExt;
use relm4::adw::prelude::WidgetExt;
use relm4::adw::traits::PreferencesGroupExt;
use relm4::adw::traits::PreferencesPageExt;
use relm4::adw::traits::PreferencesWindowExt;
use relm4::gtk;
use relm4::send;
use relm4::WidgetPlus;
use relm4::Widgets;
use gtk::prelude::*;
use crate::ui::app::model::AppModel;
use crate::ui::components::toolbox_apps::messages::ToolboxAppDialogMsg;
use super::model::ToolboxAppDialogModel;
#[derive(Debug)]
pub struct AppFactoryWidgets {
pub app_box: gtk::Box,
}
#[relm4::widget(pub)]
impl Widgets<ToolboxAppDialogModel, AppModel> for ToolboxAppDialogWidgets {
view! {
adw::PreferencesWindow {
set_title: Some("Applications: <Toolbox_name>"),
set_transient_for: parent!{Some(&parent_widgets.main_window)},
set_modal: true,
set_search_enabled: false,
set_visible: watch!(!model.hidden),
connect_close_request(sender) => move |_| {
send!(sender, ToolboxAppDialogMsg::Close);
gtk::Inhibit(true)
},
add = &adw::PreferencesPage {
set_hexpand: true,
set_vexpand: false,
add = &adw::PreferencesGroup {
add = &gtk::ScrolledWindow {
set_hscrollbar_policy: PolicyType::Never,
set_hexpand: false,
set_vexpand: true,
set_child = Some(&gtk::FlowBox) {
set_halign: gtk::Align::Fill,
set_valign: gtk::Align::Start,
set_selection_mode: gtk::SelectionMode::None,
set_margin_all: 5,
set_column_spacing: 5,
set_row_spacing: 5,
set_orientation: Orientation::Horizontal,
factory!(model.apps),
}
}
}
}
}
}
}

View File

@@ -1,11 +0,0 @@
use relm4::RelmComponent;
use relm4::RelmMsgHandler;
use relm4::Sender;
use super::model::ToolboxSettingsDialogModel;
use crate::ui::components::toolbox_settings::workers::AsyncSettingsHandler;
#[derive(relm4::Components)]
pub struct SettingsComponents {
pub async_handler: RelmMsgHandler<AsyncSettingsHandler, ToolboxSettingsDialogModel>,
}

View File

@@ -1,9 +0,0 @@
use crate::toolbx::ToolbxContainer;
use super::model::ToolboxPreferences;
pub enum ToolboxSettingsDialogMsg {
Show(ToolbxContainer),
ReplyToolbxSettings(ToolboxPreferences),
Close,
}

View File

@@ -1,6 +0,0 @@
pub mod components;
pub mod messages;
pub mod model;
pub mod update;
pub mod widgets;
pub mod workers;

View File

@@ -1,23 +0,0 @@
use relm4::Model;
use super::{
components::SettingsComponents, messages::ToolboxSettingsDialogMsg,
widgets::ToolboxSettingsDialogWidgets,
};
use crate::toolbx::ToolbxContainer;
pub struct ToolboxSettingsDialogModel {
pub hidden: bool,
pub window_title: Option<String>,
pub current_toolbox_container: Option<ToolbxContainer>,
pub current_toolbx_settings: Option<ToolboxPreferences>,
}
impl Model for ToolboxSettingsDialogModel {
type Msg = ToolboxSettingsDialogMsg;
type Widgets = ToolboxSettingsDialogWidgets;
type Components = SettingsComponents;
}
#[derive(Debug, Clone)]
pub struct ToolboxPreferences {}

View File

@@ -1,67 +0,0 @@
use relm4::{ComponentUpdate, Sender};
use crate::ui::app::{messages::AppMsg, model::AppModel};
use super::{
components::SettingsComponents, messages::ToolboxSettingsDialogMsg,
model::ToolboxSettingsDialogModel, workers::AsyncSettingsHandlerMsg,
};
impl ComponentUpdate<AppModel> for ToolboxSettingsDialogModel {
fn init_model(_parent_model: &AppModel) -> Self {
ToolboxSettingsDialogModel {
hidden: true,
window_title: None,
current_toolbox_container: None,
current_toolbx_settings: None,
}
}
fn update(
&mut self,
msg: ToolboxSettingsDialogMsg,
components: &SettingsComponents,
_sender: Sender<ToolboxSettingsDialogMsg>,
parent_sender: Sender<AppMsg>,
) {
match msg {
ToolboxSettingsDialogMsg::ReplyToolbxSettings(settings) => {
self.current_toolbx_settings = Some(settings);
println!("Received Toolbox Settings");
}
ToolboxSettingsDialogMsg::Show(toolbx_container) => {
self.hidden = false;
self.window_title = Some(format!(
"Toolbx Preferences: {}",
toolbx_container.name.clone()
));
// TODO: create settings handling for each toolbox
// probably settings for a toolbox should be stored in a HashMap and loaded based on that
components
.async_handler
.sender()
.blocking_send(AsyncSettingsHandlerMsg::RequestToolbxSettings(
toolbx_container.clone(),
))
.expect("Receiver dropped");
self.current_toolbox_container = Some(toolbx_container);
}
ToolboxSettingsDialogMsg::Close => {
self.current_toolbx_settings.as_ref().map(|settings| {
components
.async_handler
.sender()
.blocking_send(AsyncSettingsHandlerMsg::SaveToolboxSettings(
settings.clone(),
))
.expect("Receiver dropped");
});
self.hidden = true;
self.window_title = None;
self.current_toolbox_container = None;
self.current_toolbx_settings = None;
}
}
}
}

View File

@@ -1,89 +0,0 @@
use relm4::adw;
use relm4::adw::prelude::BoxExt;
use relm4::adw::prelude::GtkWindowExt;
use relm4::adw::prelude::ListBoxRowExt;
use relm4::adw::prelude::WidgetExt;
use relm4::adw::traits::ActionRowExt;
use relm4::adw::traits::PreferencesGroupExt;
use relm4::adw::traits::PreferencesPageExt;
use relm4::adw::traits::PreferencesRowExt;
use relm4::adw::traits::PreferencesWindowExt;
use relm4::gtk;
use relm4::send;
use relm4::WidgetPlus;
use relm4::Widgets;
use crate::ui::app::model::AppModel;
use crate::ui::components::toolbox_settings::messages::ToolboxSettingsDialogMsg;
use crate::ui::ui_strings::FOLDER_PICKER_ICON;
use crate::ui::ui_strings::FOLDER_PICKER_TOOLTIP;
use super::model::ToolboxSettingsDialogModel;
#[relm4::widget(pub)]
impl Widgets<ToolboxSettingsDialogModel, AppModel> for ToolboxSettingsDialogWidgets {
view! {
adw::PreferencesWindow {
set_title: watch!{ model.window_title.as_ref().map( |x| x.as_str() ) },
set_transient_for: parent!{Some(&parent_widgets.main_window)},
set_modal: true,
set_visible: watch!(!model.hidden),
connect_close_request(sender) => move |_| {
send!(sender, ToolboxSettingsDialogMsg::Close);
gtk::Inhibit(true)
},
add = &adw::PreferencesPage {
add = &adw::PreferencesGroup {
set_title: "Updates",
add = &adw::PreferencesRow {
set_title: "Update Policy",
set_child = Some(&adw::ActionRow) {
set_title: "Update Policy",
add_suffix = &gtk::Box {
append = &gtk::DropDown::from_strings(&[
"Update automatically",
"Notify about updates",
"Do nothing"
]) {
set_margin_all: 15,
},
}
},
},
},
add = &adw::PreferencesGroup {
set_title: "Home Folder",
add = &adw::PreferencesRow {
set_title: "Separate Home Folder",
set_child = Some(&adw::ActionRow) {
set_title: "Use separate home folder",
add_suffix = &gtk::Box {
append = &gtk::Switch {
set_margin_all: 15,
set_tooltip_text: Some("Use separate home folder"),
},
}
},
},
add = &adw::PreferencesRow {
set_title: "Home Folder Path",
set_child = Some(&adw::ActionRow) {
set_title: "Home folder path",
add_suffix = &gtk::Box {
set_margin_all: 15,
add_css_class: "linked",
append = &gtk::Entry {
set_hexpand: true,
},
append = &gtk::Button::from_icon_name(FOLDER_PICKER_ICON) {
set_tooltip_text: Some(FOLDER_PICKER_TOOLTIP),
}
}
},
},
}
}
}
}
}

View File

@@ -1,76 +0,0 @@
use std::time::Duration;
use crate::toolbx::ToolbxContainer;
use relm4::factory::DynamicIndex;
use relm4::{send, MessageHandler, Sender};
use tokio::runtime::{Builder, Runtime};
use tokio::sync::mpsc::{channel, Sender as TokioSender};
use crate::ui::app::{messages::AppMsg, model::AppModel};
use super::model::ToolboxPreferences;
use crate::ui::components::toolbox_settings::messages::ToolboxSettingsDialogMsg;
use crate::ui::components::ToolboxSettingsDialogModel;
// Code adapted from https://relm4.org/book/stable/message_handler.html
pub struct AsyncSettingsHandler {
_rt: Runtime,
sender: TokioSender<AsyncSettingsHandlerMsg>,
}
#[derive(Debug)]
pub enum AsyncSettingsHandlerMsg {
RequestToolbxSettings(ToolbxContainer),
SaveToolboxSettings(ToolboxPreferences),
}
impl MessageHandler<ToolboxSettingsDialogModel> for AsyncSettingsHandler {
type Msg = AsyncSettingsHandlerMsg;
type Sender = TokioSender<AsyncSettingsHandlerMsg>;
fn init(
_parent_model: &ToolboxSettingsDialogModel,
parent_sender: Sender<ToolboxSettingsDialogMsg>,
) -> Self {
let (sender, mut rx) = channel::<AsyncSettingsHandlerMsg>(10);
let rt = Builder::new_multi_thread()
.worker_threads(1)
.enable_time()
.build()
.unwrap();
rt.spawn(async move {
while let Some(msg) = rx.recv().await {
let parent_sender = parent_sender.clone();
tokio::spawn(async move {
match msg {
AsyncSettingsHandlerMsg::SaveToolboxSettings(tbx_settings) => {
// TODO: actually save settings
println!("Received Toolbx Settings save request");
}
AsyncSettingsHandlerMsg::RequestToolbxSettings(tbx) => {
println!("Received ToolbxSettings Request");
parent_sender
.send(ToolboxSettingsDialogMsg::ReplyToolbxSettings(
ToolboxPreferences {},
))
.unwrap();
}
}
});
}
});
AsyncSettingsHandler { _rt: rt, sender }
}
fn send(&self, msg: Self::Msg) {
self.sender.blocking_send(msg).unwrap();
}
fn sender(&self) -> Self::Sender {
self.sender.clone()
}
}

1
src/util.rs Normal file
View File

@@ -0,0 +1 @@
pub mod toolbx;