Skip to content

Commit

Permalink
feat: added action metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
lilopkins committed Oct 27, 2023
1 parent 2a06dd1 commit 3a2e0cd
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 17 deletions.
6 changes: 6 additions & 0 deletions testangel/locales/en/main.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ action-save-open-error-serializing-error = The action could not be saved due to
action-save-open-error-action-not-version-compatible = The action you tried to load is not compatible with this version of { app-name }.
action-save-open-error-missing-instruction = The instruction for step { $step } (with internal ID: { $error }) in this action is missing.
action-metadata-label = Action Metadata
action-metadata-name = Action Name
action-metadata-group = Action Group
action-metadata-author = Author
action-metadata-description = Description
action-metadata-visible = Visible in Flow Editor
action-step-label = Step { $step }: { $name }
# Execution
Expand Down
6 changes: 4 additions & 2 deletions testangel/src/next_ui/actions/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,10 @@ impl Component for ActionsHeader {
gtk::Button {
set_icon_name: relm4_icons::icon_name::PLAY,
set_tooltip: &lang::lookup("action-header-run"),
#[watch]
set_sensitive: model.action_open,
// TODO uncomment when execution dialog ready
//#[watch]
//set_sensitive: model.action_open,
set_sensitive: false,
connect_clicked[sender] => move |_| {
// unwrap rationale: receivers will never be dropped
sender.output(ActionsHeaderOutput::RunAction).unwrap();
Expand Down
1 change: 0 additions & 1 deletion testangel/src/next_ui/actions/instruction_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ impl FactoryComponent for InstructionComponent {

view! {
root = gtk::Box {
set_margin_all: 5,
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,

Expand Down
129 changes: 129 additions & 0 deletions testangel/src/next_ui/actions/metadata_component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use relm4::{adw, gtk, Component};
use adw::prelude::*;
use testangel::types::Action;

use crate::next_ui::lang;

#[derive(Debug)]
pub enum MetadataInput {
/// Inform the metadata component that the action has changed and as such
/// it should reload the metadata values
ChangeAction(Action),
}

#[derive(Clone, Debug, Default)]
pub struct MetadataOutput {
pub new_name: Option<String>,
pub new_group: Option<String>,
pub new_author: Option<String>,
pub new_description: Option<String>,
pub new_visible: Option<bool>,
}

#[derive(Debug)]
pub struct Metadata;

#[relm4::component(pub)]
impl Component for Metadata {
type Init = ();
type Input = MetadataInput;
type Output = MetadataOutput;
type CommandOutput = ();

view! {
adw::PreferencesGroup {
set_title: &lang::lookup("action-metadata-label"),

#[name = "name"]
adw::EntryRow {
set_title: &lang::lookup("action-metadata-name"),

connect_changed[sender] => move |entry| {
let _ = sender.output(MetadataOutput {
new_name: Some(entry.text().to_string()),
..Default::default()
});
},
},
#[name = "group"]
adw::EntryRow {
set_title: &lang::lookup("action-metadata-group"),

connect_changed[sender] => move |entry| {
let _ = sender.output(MetadataOutput {
new_group: Some(entry.text().to_string()),
..Default::default()
});
},
},
#[name = "author"]
adw::EntryRow {
set_title: &lang::lookup("action-metadata-author"),

connect_changed[sender] => move |entry| {
let _ = sender.output(MetadataOutput {
new_author: Some(entry.text().to_string()),
..Default::default()
});
},
},
#[name = "description"]
adw::EntryRow {
set_title: &lang::lookup("action-metadata-description"),

connect_changed[sender] => move |entry| {
let _ = sender.output(MetadataOutput {
new_description: Some(entry.text().to_string()),
..Default::default()
});
},
},
adw::ActionRow {
set_title: &lang::lookup("action-metadata-visible"),

#[name = "visible"]
add_suffix = &gtk::Switch {
connect_state_set[sender] => move |_switch, state| {
let _ = sender.output(MetadataOutput {
new_visible: Some(state),
..Default::default()
});
gtk::Inhibit(false)
},
},

}
},
}

fn init(
_init: Self::Init,
root: &Self::Root,
sender: relm4::ComponentSender<Self>,
) -> relm4::ComponentParts<Self> {
let model = Metadata;
let widgets = view_output!();

relm4::ComponentParts { model, widgets }
}

fn update_with_view(
&mut self,
widgets: &mut Self::Widgets,
message: Self::Input,
sender: relm4::ComponentSender<Self>,
_root: &Self::Root,
) {
match message {
MetadataInput::ChangeAction(action) => {
widgets.name.set_text(&action.friendly_name);
widgets.group.set_text(&action.group);
widgets.author.set_text(&action.author);
widgets.description.set_text(&action.description);
widgets.visible.set_active(action.visible);
}
}

self.update_view(widgets, sender)
}
}
63 changes: 49 additions & 14 deletions testangel/src/next_ui/actions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::{file_filters, lang};
mod instruction_component;
mod execution_dialog;
pub mod header;
mod metadata_component;

pub enum SaveOrOpenActionError {
IoError(std::io::Error),
Expand Down Expand Up @@ -110,6 +111,8 @@ pub enum ActionInputs {
/// The [`InstructionConfiguration`] has changed for the step indicated by the [`DynamicIndex`].
/// This does not refresh the UI.
ConfigUpdate(DynamicIndex, InstructionConfiguration),
/// The metadata has been updated and the action should be updated to reflect that
MetadataUpdated(metadata_component::MetadataOutput),
}
#[derive(Clone, Debug)]
pub enum ActionOutputs {
Expand All @@ -126,6 +129,7 @@ pub struct ActionsModel {
open_path: Option<PathBuf>,
needs_saving: bool,
header: Rc<Controller<header::ActionsHeader>>,
metadata: Controller<metadata_component::Metadata>,
live_instructions_list: FactoryVecDeque<instruction_component::InstructionComponent>,

execution_dialog: Option<Connector<execution_dialog::ExecutionDialog>>,
Expand Down Expand Up @@ -198,10 +202,12 @@ impl ActionsModel {
))
}
}
self.open_action = Some(action);

self.open_action = Some(action.clone());
self.header.emit(header::ActionsHeaderInput::ChangeActionOpen(
self.open_action.is_some(),
));
self.metadata.emit(metadata_component::MetadataInput::ChangeAction(action));
self.open_path = Some(file);
self.needs_saving = false;
log::debug!("New action open.");
Expand Down Expand Up @@ -314,25 +320,32 @@ impl Component for ActionsModel {
set_vexpand: true,
set_hscrollbar_policy: gtk::PolicyType::Never,

gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_margin_all: 5,

if model.open_action.is_none() {
adw::StatusPage {
set_title: &lang::lookup("nothing-open"),
set_description: Some(&lang::lookup("action-nothing-open-description")),
set_icon_name: Some(relm4_icons::icon_name::LIGHTBULB),
#[watch]
set_visible: model.open_action.is_none(),
set_vexpand: true,
},

#[local_ref]
live_instructions_list -> gtk::Box {
}
} else {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
},
},
set_margin_all: 10,
set_spacing: 10,

model.metadata.widget(),

gtk::Separator {
set_orientation: gtk::Orientation::Horizontal,
},

#[local_ref]
live_instructions_list -> gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
},
}
}
},
},
}
Expand Down Expand Up @@ -365,6 +378,7 @@ impl Component for ActionsModel {
execution_dialog: None,
header,
live_instructions_list: FactoryVecDeque::new(gtk::Box::default(), sender.input_sender()),
metadata: metadata_component::Metadata::builder().launch(()).forward(sender.input_sender(), |msg| ActionInputs::MetadataUpdated(msg)),
};

// Trigger update actions from model
Expand All @@ -385,6 +399,27 @@ impl Component for ActionsModel {
) {
match message {
ActionInputs::NoOp => (),

ActionInputs::MetadataUpdated(meta) => {
if let Some(action) = self.open_action.as_mut() {
if let Some(new_name) = meta.new_name {
action.friendly_name = new_name;
}
if let Some(new_group) = meta.new_group {
action.group = new_group;
}
if let Some(new_author) = meta.new_author {
action.author = new_author;
}
if let Some(new_description) = meta.new_description {
action.description = new_description;
}
if let Some(new_visible) = meta.new_visible {
action.visible = new_visible;
}
}
}

ActionInputs::ActionsMapChanged(new_map) => {
self.action_map = new_map.clone();
self.header.emit(header::ActionsHeaderInput::ActionsMapChanged(new_map));
Expand Down

0 comments on commit 3a2e0cd

Please sign in to comment.