Updating task list
All changes should happen in the view/task_list.rs
In relm4-store
components there is pagination component ready for you to use. Let's import it
use relm4::Components;
use relm4::RelmComponent;
use components::pagination::PaginationMsg;
use components::pagination::PaginationConfiguration;
use components::pagination::PaginationViewModel;
use store::StoreViewInnerComponent;
Now we need to add a component for the tasks list
pub struct TasksListComponents<Config>
where Config: TasksListConfiguration + 'static {
pagination: RelmComponent<PaginationViewModel<Self>, TasksListViewModel<Config>>
}
impl<Config> Components<TasksListViewModel<Config>> for TasksListComponents<Config>
where Config: TasksListConfiguration,
{
fn init_components(
parent_model: &TasksListViewModel<Config>,
parent_sender: Sender<<TasksListViewModel<Config> as ViewModel>::Msg>
) -> Self {
Self {
pagination: RelmComponent::new(parent_model, parent_sender.clone()),
}
}
fn connect_parent(&mut self, _parent_widgets: &TasksListViewWidgets) {}
}
impl<Config> PaginationConfiguration for TasksListComponents<Config>
where Config: TasksListConfiguration + 'static {
type StoreViewPrototype = TasksListViewModel<Config>;
fn get_view(parent_view_model: &<Self::StoreViewPrototype as StoreViewPrototype>::ViewModel) -> View<Self::StoreViewPrototype> {
parent_view_model.store_view.clone()
}
}
impl<Config> StoreViewInnerComponent<TasksListViewModel<Config>> for TasksListComponents<Config>
where Config: TasksListConfiguration + 'static {
fn on_store_update(&mut self) {
self.pagination.send(PaginationMsg::StoreUpdated).unwrap();
}
}
TaskListComponent and pagination are normal relm4 components. For TaskListComponent
we need to implement two extra traits. First is PaginationConfiguration
. As name implies it provides configuration for pagination component. Second one and more interesting is StoreViewInnerComponent
. This one provides a way to notify components when there is a change in the store. This allows to solve chicken and the egg problem of what's first store view or the pagination. Without view there is no point in pagination but pagination must own the view since it manages it.
Since we've created component for task list, now we need to add it to the relm4::Model
impl<Config> ViewModel for TasksListViewModel<Config>
where Config: TasksListConfiguration + 'static,
{
type Msg = TaskMsg;
type Widgets = TasksListViewWidgets;
type Components = TasksListComponents<Config>;
}
What's left is to add bunch of 'static
lifetimes for Config
generic attribute all around the file (compiler will tell you where). This is required because compiler can't infer the lifetime of some of the types.
Hopefully full list of the places to add 'static
lifetime:
- implementation of the
ViewModel for TaskListViewModel
- implementation of the
StoreViewPrototype for TaskListViewModel
- implementation of the
FactoryContainerWidget for TasksListViewWidgets
Now let's put a cherry on top and add the pagination to the TaskListViewWidgets
.
#[widget(visibility=pub, relm4=reexport::relm4)]
impl<Config: TasksListConfiguration> Widgets<TasksListViewModel<Config>, Config::ParentViewModel> for TasksListViewWidgets {
view!{
root = gtk::Box {
set_margin_all: 12,
set_orientation: gtk::Orientation::Vertical,
append = >k::Entry::with_buffer(&model.new_task_description) {
connect_activate(sender) => move |_| {
send!(sender, TaskMsg::New);
}
},
append = >k::ScrolledWindow {
set_hexpand: true,
set_vexpand: true,
set_child: container = Some(>k::Box) {
set_orientation: gtk::Orientation::Vertical,
factory!(model.store_view)
}
},
append: components.pagination.root_widget()
}
}
}
Last append
adds pagination to the view.
This ends the story of adding pagination to the task list. Source code can be found in todo_2
example