View
We need to add a button with a trash to the right of our task description. When user presses the button we will remove the task from the store.
So in the view/task_list.rs
we need to add imports
use gtk::Button;
use gtk::prelude::ButtonExt;
Then we need to update the TaskWidgets
so they will hold reference to the delete button
#[derive(Debug)]
#[allow(dead_code)]
pub struct TaskWidgets {
checkbox: CheckButton,
label: Label,
delete_button: Button,
root: Box,
We need to add Delete
event to the TaskMsg
so we can track which record should be deleted.
pub enum TaskMsg {
Toggle{
complete: bool,
id: Id<Task>,
},
Delete(Id<Task>),
New,
}
Now we need to update the init_view
method in the implementation of the StoreViewPrototype
for TaskListViewModel
impl<Config> StoreViewPrototype for TasksListViewModel<Config>
where Config: TasksListConfiguration + 'static,
{
...
fn init_view(
record: &Task,
_position: Position,
sender: Sender<TaskMsg>,
) -> Self::RecordWidgets {
let root = Box::builder()
.orientation(Orientation::Horizontal)
.build();
let checkbox = CheckButton::builder()
.margin_top(12)
.margin_start(12)
.margin_end(12)
.margin_bottom(12)
.active(record.completed)
.build();
{
let sender = sender.clone();
let id = record.get_id();
checkbox.connect_toggled(move |btn| {
send!(sender, TaskMsg::Toggle{
id,
complete: btn.is_active()
});
});
}
let label = Label::builder()
.margin_top(12)
.margin_start(12)
.margin_end(12)
.margin_bottom(12)
.label(&record.description)
.hexpand(true)
.xalign(0.0)
.build();
let delete_button = Button::builder()
.margin_top(12)
.margin_start(12)
.margin_end(12)
.margin_bottom(12)
.icon_name("user-trash-symbolic")
.build();
delete_button.add_css_class("flat");
{
let sender = sender.clone();
let id = record.get_id();
delete_button.connect_clicked(move |_| {
send!(sender, TaskMsg::Delete(id));
});
}
root.append(&checkbox);
root.append(&label);
root.append(&delete_button);
TaskWidgets {
checkbox,
label,
delete_button,
root,
}
}
...
}
The most important part is that we've built delete_button
and added it to the root
widget. When delete_button
is clicked
it will send TaskMsg::Delete
. To make ui nice we in the label
we've added to extra settings
.hexpand(true)
.xalign(0.0)
This will expand horizontally and text will be left aligned.
Last thing left to do is to handle the changes in the view
method in the implementation of StoreViewPrototype
for TaskListViewModel
.
Compiler will tell you exactly where.
impl<Config> StoreViewPrototype for TasksListViewModel<Config>
where Config: TasksListConfiguration + 'static,
{
...
fn update(
view_model: &mut Self::ViewModel,
msg: <Self as ViewModel>::Msg,
_sender: Sender<<Self as ViewModel>::Msg>
) {
match msg {
TaskMsg::New => {
let description = view_model.new_task_description.text();
let task = Task::new(description, false);
view_model.new_task_description.set_text("");
view_model.tasks.send(StoreMsg::Commit(task));
},
TaskMsg::Toggle{ complete, id } => {
let tasks = &view_model.tasks;
if let Some(record) = tasks.get(&id) {
let mut updated = record.clone();
updated.completed = complete;
tasks.send(StoreMsg::Commit(updated));
}
},
TaskMsg::Delete(id) => {
let tasks = &view_model.tasks;
tasks.send(StoreMsg::Delete(id));
}
}
}
...
}
Sending StorMsg::Delete
to the task with record id will remove it from the data store.
After this chapter you know how to create
, update
and delete
the records from the store. Full source code can be found in the examples todo_4
.