View

Now we need an ability to toggle the order of tasks in the view. So we will add two buttons one to sort ascending and other one to sort descending.

Let's start with imports. We need to add

use gtk::prelude::ButtonExt;
use relm4::send;
use store::OrderedStore;

use crate::store::OrderTasksBy; 

Since we need to sort tasks we need to add new messages to the MainWindowMsg.

pub enum MainWindowMsg {
    ASC,
    DESC,
}

Now we need to handle new messages in the update method of the MainWindowViewModel

impl AppUpdate for MainWindowViewModel {
    fn update(
        &mut self, 
        msg: Self::Msg , 
        _components: &Self::Components, 
        _sender: Sender<Self::Msg>
    ) -> bool {
        match msg  {
            MainWindowMsg::ASC => {
                self.tasks.set_order(
                    OrderTasksBy::Name{ascending: true}
                )
            },
            MainWindowMsg::DESC => {
                self.tasks.set_order(
                    OrderTasksBy::Name{ascending: false}
                )
            }
        }

        true
    }
}

SortedInMemoryStore implements OrderedStore which provides a method set_order which you can use to set order of elements in the store. Implementation of the set_order will take care of propagating the knowledge about the changes to the store view and in consequence render it on the screen.

Only thing left it to update our MainWindowWidgets so it can send the messages to sort our view.

#[widget(visibility=pub, relm4=relm4)]
impl Widgets<MainWindowViewModel, ()> for MainWindowWidgets {
    view!{
        root = gtk::ApplicationWindow {
            set_child: Some(components.tasks_list.root_widget()),
            set_titlebar= Some(&gtk::HeaderBar){
                set_title_widget = Some(&gtk::Label::new(Some("todo_3"))){},
                pack_end = &gtk::Button::from_icon_name("view-sort-ascending-symbolic") {
                    connect_clicked(sender) => move |_| {
                        send!(sender, MainWindowMsg::ASC)
                    },
                },
                pack_end = &gtk::Button::from_icon_name("view-sort-descending-symbolic") {
                    connect_clicked(sender) => move |_| {
                        send!(sender, MainWindowMsg::DESC)
                    },
                },
            },
            set_default_size: args!(350, 800),
        }
    }
}

To the titlebar of the main window we've added two buttons which will trigger sorting of the list. If you try adding new element to the list you will find that it's being inserted accordingly to the state of the data store.

As always full code can be found in examples as todo_3.