Try out different autosuggestion methods
This commit is contained in:
parent
e0feae0546
commit
c3e5db6889
32
src/ui/autosuggestion_element.rs
Normal file
32
src/ui/autosuggestion_element.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use gtk::prelude::*;
|
||||
use relm4::prelude::*;
|
||||
|
||||
pub struct AutosuggestionElementModel {
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
#[relm4::factory(pub)]
|
||||
impl FactoryComponent for AutosuggestionElementModel {
|
||||
type Init = String;
|
||||
type ParentWidget = gtk::ListBox;
|
||||
type CommandOutput = ();
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
#[root]
|
||||
gtk::ListBoxRow {
|
||||
gtk::Label {
|
||||
set_label: &self.label,
|
||||
set_halign: gtk::Align::Start,
|
||||
set_margin_all: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_model(label: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||
AutosuggestionElementModel { label }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Input, _sender: FactorySender<Self>) {}
|
||||
}
|
104
src/ui/autosuggestion_popover.rs
Normal file
104
src/ui/autosuggestion_popover.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use gtk::prelude::*;
|
||||
|
||||
use relm4::component::{AsyncComponent, AsyncComponentParts};
|
||||
use relm4::factory::FactoryVecDeque;
|
||||
use relm4::gtk;
|
||||
use relm4::{AsyncComponentSender, RelmListBoxExt};
|
||||
|
||||
use super::autosuggestion_element::AutosuggestionElementModel;
|
||||
|
||||
pub struct AutosuggestionPopoverModel {
|
||||
hidden: bool,
|
||||
suggestions: Vec<String>,
|
||||
suggestion_rows: FactoryVecDeque<AutosuggestionElementModel>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AutosuggestionPopoverInput {
|
||||
Show,
|
||||
Hide,
|
||||
SetSuggestions(Vec<String>),
|
||||
SuggestionIndexSelected(i32),
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AutosuggestionPopoverOutput {
|
||||
SuggestionSelected(String),
|
||||
}
|
||||
|
||||
#[relm4::component(pub, async)]
|
||||
impl AsyncComponent for AutosuggestionPopoverModel {
|
||||
type Init = ();
|
||||
type Input = AutosuggestionPopoverInput;
|
||||
type Output = AutosuggestionPopoverOutput;
|
||||
type CommandOutput = ();
|
||||
|
||||
view! {
|
||||
gtk::Popover {
|
||||
#[watch]
|
||||
set_visible: !model.hidden,
|
||||
set_has_arrow: false,
|
||||
model.suggestion_rows.widget() -> &relm4::gtk::ListBox {
|
||||
set_hexpand: true,
|
||||
// set_orientation: gtk::Orientation::Vertical,
|
||||
// set_spacing: 5,
|
||||
connect_row_activated[sender] => move |list_box, row| {
|
||||
let index = list_box.index_of_child(row).unwrap();
|
||||
sender.input(AutosuggestionPopoverInput::SuggestionIndexSelected(index));
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn init(
|
||||
_params: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: AsyncComponentSender<Self>,
|
||||
) -> AsyncComponentParts<Self> {
|
||||
let suggestion_rows = FactoryVecDeque::builder()
|
||||
.launch(gtk::ListBox::default())
|
||||
.forward(sender.input_sender(), |_| AutosuggestionPopoverInput::None);
|
||||
|
||||
let model = AutosuggestionPopoverModel {
|
||||
hidden: true,
|
||||
suggestions: Vec::new(),
|
||||
suggestion_rows,
|
||||
};
|
||||
let widgets = view_output!();
|
||||
|
||||
AsyncComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
// TODO: init_loading_widgets
|
||||
|
||||
async fn update(
|
||||
&mut self,
|
||||
msg: Self::Input,
|
||||
_sender: AsyncComponentSender<Self>,
|
||||
_root: &Self::Root,
|
||||
) {
|
||||
match msg {
|
||||
AutosuggestionPopoverInput::Show => self.hidden = false,
|
||||
AutosuggestionPopoverInput::Hide => self.hidden = true,
|
||||
AutosuggestionPopoverInput::SetSuggestions(suggestions) => {
|
||||
self.suggestion_rows.guard().clear();
|
||||
for suggestion in suggestions.iter() {
|
||||
self.suggestion_rows
|
||||
.guard()
|
||||
.push_back(suggestion.to_string());
|
||||
}
|
||||
self.suggestions = suggestions;
|
||||
}
|
||||
AutosuggestionPopoverInput::None => {}
|
||||
AutosuggestionPopoverInput::SuggestionIndexSelected(index) => {
|
||||
let suggestion = self.suggestions.get(index as usize).unwrap();
|
||||
_sender
|
||||
.output(AutosuggestionPopoverOutput::SuggestionSelected(
|
||||
suggestion.to_string(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
pub mod app;
|
||||
pub mod autosuggestion_element;
|
||||
pub mod autosuggestion_popover;
|
||||
pub mod mcdu;
|
||||
pub mod sheet_edit_dialog;
|
||||
pub mod sheet_listing;
|
||||
|
@ -3,7 +3,11 @@ use std::sync::Arc;
|
||||
|
||||
use relm4::{
|
||||
component::{AsyncComponent, AsyncComponentParts, Connector},
|
||||
gtk::EntryBuffer,
|
||||
gtk::{
|
||||
gio::ListStore,
|
||||
glib::{self, GString, Type, Value},
|
||||
EntryBuffer, EntryCompletion,
|
||||
},
|
||||
prelude::*,
|
||||
AsyncComponentSender,
|
||||
};
|
||||
@ -11,15 +15,19 @@ use relm4_components::alert::{Alert, AlertMsg, AlertSettings};
|
||||
|
||||
use crate::{database::Database, sheet::Sheet, sheet_dao};
|
||||
|
||||
use super::autosuggestion_popover::{AutosuggestionPopoverInput, AutosuggestionPopoverModel};
|
||||
|
||||
pub struct SheetEditDialogModel {
|
||||
database: Arc<Database>,
|
||||
hidden: bool,
|
||||
sheet: Option<Sheet>,
|
||||
name_entry_buffer: EntryBuffer,
|
||||
composer_entry_buffer: EntryBuffer,
|
||||
composer_entry_completion: EntryCompletion,
|
||||
is_book: bool,
|
||||
book_sheets: Vec<(String, String, i64)>,
|
||||
alert_empty_fields: Connector<Alert>,
|
||||
autosuggestion_popover: AsyncController<AutosuggestionPopoverModel>,
|
||||
}
|
||||
|
||||
pub struct SheetEditDialogInit {
|
||||
@ -31,6 +39,8 @@ pub struct SheetEditDialogInit {
|
||||
pub enum SheetEditDialogInput {
|
||||
Accept,
|
||||
Cancel,
|
||||
ComposerTextChanged(String),
|
||||
ComposerSuggestionSelected(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -74,7 +84,9 @@ impl AsyncComponent for SheetEditDialogModel {
|
||||
},
|
||||
gtk::Entry {
|
||||
set_buffer: &model.composer_entry_buffer,
|
||||
set_completion: Some(&model.composer_entry_completion),
|
||||
set_hexpand: true,
|
||||
connect_changed[sender] => move |entry| sender.input(SheetEditDialogInput::ComposerTextChanged(entry.text().to_string())),
|
||||
},
|
||||
},
|
||||
gtk::Box {
|
||||
@ -103,7 +115,8 @@ impl AsyncComponent for SheetEditDialogModel {
|
||||
set_label : "Confirm",
|
||||
connect_clicked[sender] => move |_| sender.input(SheetEditDialogInput::Accept)
|
||||
},
|
||||
}
|
||||
},
|
||||
// model.autosuggestion_popover.widget(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,12 +161,39 @@ impl AsyncComponent for SheetEditDialogModel {
|
||||
}
|
||||
};
|
||||
|
||||
let composer_entry_completion = EntryCompletion::new();
|
||||
let data = [
|
||||
"France".to_string(),
|
||||
"Italy".to_string(),
|
||||
"Sweden".to_string(),
|
||||
"Switzerland".to_string(),
|
||||
];
|
||||
let store = gtk::ListStore::new(&[glib::Type::STRING]);
|
||||
for d in data.iter() {
|
||||
store.set(&store.append(), &[(0, &d)]);
|
||||
}
|
||||
|
||||
composer_entry_completion.set_model(Some(&store));
|
||||
// Use the first (and only) column available to set the autocompletion text
|
||||
composer_entry_completion.set_text_column(0);
|
||||
// how many keystrokes to wait before attempting to autocomplete?
|
||||
composer_entry_completion.set_minimum_key_length(1);
|
||||
// whether the completions should be presented in a popup window
|
||||
composer_entry_completion.set_popup_completion(true);
|
||||
|
||||
let autosuggestion_popover = AutosuggestionPopoverModel::builder()
|
||||
.launch(())
|
||||
.forward(sender.input_sender(), |output| match output {
|
||||
crate::ui::autosuggestion_popover::AutosuggestionPopoverOutput::SuggestionSelected(suggestion) => SheetEditDialogInput::ComposerSuggestionSelected(suggestion),
|
||||
});
|
||||
|
||||
let model = SheetEditDialogModel {
|
||||
database: params.database,
|
||||
hidden: false,
|
||||
sheet: Some(sheet),
|
||||
name_entry_buffer: EntryBuffer::new(Some(sheet_name)),
|
||||
composer_entry_buffer: EntryBuffer::new(Some(sheet_composer)),
|
||||
composer_entry_completion,
|
||||
is_book,
|
||||
book_sheets: Vec::new(),
|
||||
alert_empty_fields: Alert::builder().transient_for(&root).launch(AlertSettings {
|
||||
@ -165,6 +205,7 @@ impl AsyncComponent for SheetEditDialogModel {
|
||||
cancel_label: None,
|
||||
option_label: None,
|
||||
}),
|
||||
autosuggestion_popover,
|
||||
};
|
||||
let widgets = view_output!();
|
||||
|
||||
@ -224,6 +265,32 @@ impl AsyncComponent for SheetEditDialogModel {
|
||||
self.hidden = true;
|
||||
self.sheet = None;
|
||||
}
|
||||
SheetEditDialogInput::ComposerTextChanged(composer_name) => {
|
||||
// let suggestions = vec![
|
||||
// "Hello".into(),
|
||||
// "World".into(),
|
||||
// "Seattle".into(),
|
||||
// "Salzburg".into(),
|
||||
// ];
|
||||
|
||||
// self.autosuggestion_popover
|
||||
// .emit(AutosuggestionPopoverInput::SetSuggestions(suggestions));
|
||||
// self.autosuggestion_popover
|
||||
// .emit(AutosuggestionPopoverInput::Show);
|
||||
// self.model.filtered_suggestions = self
|
||||
// .model
|
||||
// .suggestions
|
||||
// .iter()
|
||||
// .filter(|suggestion| suggestion.starts_with(&text))
|
||||
// .cloned()
|
||||
// .collect();
|
||||
// self.update_suggestions();
|
||||
}
|
||||
SheetEditDialogInput::ComposerSuggestionSelected(composer_name) => {
|
||||
self.composer_entry_buffer.set_text(composer_name);
|
||||
self.autosuggestion_popover
|
||||
.emit(AutosuggestionPopoverInput::Hide);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user