Implement working search bar

This commit is contained in:
Julian Mutter 2024-01-22 21:11:51 +01:00
parent e47c9afe33
commit e4543ac66e
3 changed files with 100 additions and 30 deletions

View File

@ -6,17 +6,16 @@ use std::{env, path::PathBuf, process};
use gtk::prelude::*; use gtk::prelude::*;
use mcdu::McduModel; use mcdu::McduModel;
use relm4::prelude::*; use relm4::prelude::*;
use sheet_listing::SheetListingModel; use sheet_listing::{SheetListingInput, SheetListingModel};
struct AppModel { struct AppModel {
text: String,
mcdu: Controller<McduModel>, mcdu: Controller<McduModel>,
sheet_listing: Controller<SheetListingModel>, sheet_listing: Controller<SheetListingModel>,
} }
#[derive(Debug)] #[derive(Debug)]
enum AppInput { enum AppInput {
McduInput(char), SearchStarted(String),
SheetPressed(PathBuf), SheetPressed(PathBuf),
} }
@ -44,17 +43,7 @@ impl SimpleComponent for AppModel {
// set_hscrollbar_policy: PolicyType::Never, // set_hscrollbar_policy: PolicyType::Never,
}, },
}, },
gtk::Box { model.mcdu.widget(),
set_orientation: gtk::Orientation::Vertical,
set_valign: gtk::Align::Center,
model.mcdu.widget(),
#[name = "label"]
gtk::Label {
#[watch]
set_label: &model.text,
set_margin_all: 5,
}
},
} }
} }
} }
@ -69,7 +58,7 @@ impl SimpleComponent for AppModel {
let mcdu = McduModel::builder() let mcdu = McduModel::builder()
.launch(()) .launch(())
.forward(sender.input_sender(), |response| match response { .forward(sender.input_sender(), |response| match response {
mcdu::McduOutput::ButtonPress(c) => AppInput::McduInput(c), mcdu::McduOutput::SearchStarted(query) => AppInput::SearchStarted(query),
}); });
let sheet_listing = let sheet_listing =
@ -82,7 +71,6 @@ impl SimpleComponent for AppModel {
}); });
let model = AppModel { let model = AppModel {
text: String::from("Text: "),
mcdu, mcdu,
sheet_listing, sheet_listing,
}; };
@ -94,8 +82,8 @@ impl SimpleComponent for AppModel {
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) { fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
match message { match message {
AppInput::McduInput(c) => self.text.push(c),
AppInput::SheetPressed(sheet) => opener::open(sheet).unwrap(), AppInput::SheetPressed(sheet) => opener::open(sheet).unwrap(),
AppInput::SearchStarted(query) => self.sheet_listing.emit(SheetListingInput { query }),
} }
} }
} }

View File

@ -1,24 +1,57 @@
use relm4::gtk::{glib, prelude::*}; use relm4::gtk::{glib, prelude::*};
use relm4::{gtk, ComponentParts, ComponentSender, SimpleComponent}; use relm4::{gtk, ComponentParts, ComponentSender, SimpleComponent};
pub struct McduModel; pub struct McduModel {
query: String,
query_changed_by_mcdu_keys: bool,
}
impl McduModel {
fn new() -> Self {
McduModel {
query: String::new(),
query_changed_by_mcdu_keys: false,
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum McduOutput { pub enum McduOutput {
SearchStarted(String),
}
#[derive(Debug)]
pub enum KeyboardEvent {
ButtonPress(char), ButtonPress(char),
SearchStarted(String),
QueryChanged(String),
} }
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for McduModel { impl SimpleComponent for McduModel {
type Init = (); type Init = ();
type Input = (); type Input = KeyboardEvent;
type Output = McduOutput; type Output = McduOutput;
view! { view! {
#[root] #[root]
gtk::Grid { gtk::Box {
set_column_spacing: 5, set_orientation: gtk::Orientation::Vertical,
set_row_spacing: 5, set_valign: gtk::Align::Center,
gtk::SearchEntry {
set_margin_bottom: 10,
#[block_signal(change_handler, search_handler)]
#[track = "model.query_changed_by_mcdu_keys"]
set_text: &model.query,
connect_changed[sender] => move |search_entry| sender.input(KeyboardEvent::QueryChanged(search_entry.text().to_string())) @change_handler,
connect_search_changed[sender] => move |search_entry| sender.input(KeyboardEvent::SearchStarted(search_entry.text().to_string())) @search_handler,
},
#[name = "keyboard"]
gtk::Grid {
set_column_spacing: 5,
set_row_spacing: 5,
}
} }
} }
@ -27,6 +60,9 @@ impl SimpleComponent for McduModel {
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let model = McduModel::new();
let widgets = view_output!();
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let mcdu_width = 6; let mcdu_width = 6;
@ -34,17 +70,33 @@ impl SimpleComponent for McduModel {
let button = gtk::Button::default(); let button = gtk::Button::default();
button.set_label(&c.to_string()); button.set_label(&c.to_string());
button.connect_clicked(glib::clone!(@strong sender => move |_| { button.connect_clicked(glib::clone!(@strong sender => move |_| {
sender.output(McduOutput::ButtonPress(c)).unwrap(); sender.input(KeyboardEvent::ButtonPress(c));
})); }));
let column = i % mcdu_width; let column = i % mcdu_width;
let row = (i - column) / mcdu_width; let row = (i - column) / mcdu_width;
root.attach(&button, column as i32, row as i32, 1, 1); widgets
.keyboard
.attach(&button, column as i32, row as i32, 1, 1);
} }
let model = McduModel;
let widgets = view_output!();
ComponentParts { model, widgets } ComponentParts { model, widgets }
} }
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
self.query_changed_by_mcdu_keys = false;
match message {
KeyboardEvent::ButtonPress(c) => {
// println!("Button press: {}", c);
self.query_changed_by_mcdu_keys = true;
self.query.push(c);
}
KeyboardEvent::SearchStarted(s) => {
// println!("Started search: {}", s);
sender.output(McduOutput::SearchStarted(s)).unwrap();
}
KeyboardEvent::QueryChanged(query) => self.query = query,
}
}
} }

View File

@ -9,11 +9,13 @@ use walkdir::WalkDir;
pub struct SheetModel { pub struct SheetModel {
path: PathBuf, path: PathBuf,
visible: bool,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum SheetModelInput { pub enum SheetModelInput {
OnClicked, OnClicked,
SearchChanged(String),
} }
#[derive(Debug)] #[derive(Debug)]
@ -30,6 +32,8 @@ impl SimpleComponent for SheetModel {
view! { view! {
#[root] #[root]
gtk::Box { gtk::Box {
#[watch]
set_visible: model.visible,
set_orientation: gtk::Orientation::Vertical, set_orientation: gtk::Orientation::Vertical,
append = &gtk::Button { append = &gtk::Button {
set_label: &format!("{}", model.path.file_name().unwrap().to_string_lossy()), set_label: &format!("{}", model.path.file_name().unwrap().to_string_lossy()),
@ -45,7 +49,10 @@ impl SimpleComponent for SheetModel {
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let model = SheetModel { path }; let model = SheetModel {
path,
visible: true,
};
let widgets = view_output!(); let widgets = view_output!();
ComponentParts { model, widgets } ComponentParts { model, widgets }
} }
@ -55,18 +62,33 @@ impl SimpleComponent for SheetModel {
SheetModelInput::OnClicked => sender SheetModelInput::OnClicked => sender
.output(SheetPressedMessage::SheetPressed(self.path.clone())) .output(SheetPressedMessage::SheetPressed(self.path.clone()))
.unwrap(), .unwrap(),
SheetModelInput::SearchChanged(query) => {
self.visible = self
.path
.file_name()
.unwrap()
.to_string_lossy()
.to_lowercase()
.contains(&query.to_lowercase());
}
} }
} }
} }
pub struct SheetListingModel { pub struct SheetListingModel {
_sheet_models: Vec<Controller<SheetModel>>, query: String,
sheet_models: Vec<Controller<SheetModel>>,
}
#[derive(Debug)]
pub struct SheetListingInput {
pub query: String,
} }
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for SheetListingModel { impl SimpleComponent for SheetListingModel {
type Init = PathBuf; type Init = PathBuf;
type Input = (); type Input = SheetListingInput;
type Output = SheetPressedMessage; type Output = SheetPressedMessage;
view! { view! {
@ -102,9 +124,17 @@ impl SimpleComponent for SheetListingModel {
} }
let model = SheetListingModel { let model = SheetListingModel {
_sheet_models: sheet_models, query: String::new(),
sheet_models: sheet_models,
}; };
let widgets = view_output!(); let widgets = view_output!();
ComponentParts { model, widgets } ComponentParts { model, widgets }
} }
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
self.query = message.query;
for model in self.sheet_models.iter() {
model.emit(SheetModelInput::SearchChanged(self.query.clone()));
}
}
} }