Added TodoMVC example (Rust mock version) (#5396)

* Added TodoMVC example (Rust mock version)

* TodoMVC: use visible-width instead of width for selection items

and format

* TodoMVC: layout fix for qt checkbox

* TdodoMVC: fix license issues in the example

* Update examples/todo_mvc/ui/views/task_list_view.slint

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* TdodoMVC: fix license issues in the example

* TodoMVC: code review changes

* TodoMVC: code review changes

* Update .reuse/dep5

Co-authored-by: Simon Hausmann <simon.hausmann@slint.dev>

* Update examples/todo_mvc/rust/src/adapters/navigation_adapter.rs

Co-authored-by: Simon Hausmann <simon.hausmann@slint.dev>

* Update examples/todo_mvc/rust/src/adapters/navigation_adapter.rs

Co-authored-by: Simon Hausmann <simon.hausmann@slint.dev>

* TodoMVC: refactor task list model (code review feedback)

* TodoMVC: code review feedback

* Update examples/todo-mvc/rust/src/mvc/controllers/task_list_controller.rs

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* TodoMVC: add missing link in dep5

* dep5 fix

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Simon Hausmann <simon.hausmann@slint.dev>
This commit is contained in:
Florian Blasius 2024-06-13 11:05:44 +00:00 committed by GitHub
parent a2e10f8c78
commit 0870585c32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 1651 additions and 1 deletions

View file

@ -0,0 +1,108 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
use slint::*;
use crate::{
mvc::{
{CreateTaskController, TaskListController}, {DateModel, TimeModel},
},
ui,
};
// a helper function to make adapter and controller connection a little bit easier
fn connect_with_controller(
view_handle: &ui::MainWindow,
controller: &CreateTaskController,
connect_adapter_controller: impl FnOnce(ui::CreateTaskAdapter, CreateTaskController) + 'static,
) {
connect_adapter_controller(view_handle.global::<ui::CreateTaskAdapter>(), controller.clone());
}
// a helper function to make adapter and controller connection a little bit easier
fn connect_with_task_list_controller(
view_handle: &ui::MainWindow,
controller: &TaskListController,
connect_adapter_controller: impl FnOnce(ui::CreateTaskAdapter, TaskListController) + 'static,
) {
connect_adapter_controller(view_handle.global::<ui::CreateTaskAdapter>(), controller.clone());
}
// one place to implement connection between adapter (view) and controller
pub fn connect(view_handle: &ui::MainWindow, controller: CreateTaskController) {
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_back(move || {
controller.back();
})
}
});
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_current_date(move || map_date_model_to_date(controller.current_date()))
}
});
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_current_time(move || map_time_model_to_time(controller.current_time()))
}
});
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_date_string(move |date| {
controller.date_string(map_date_to_date_model(date)).into()
})
}
});
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_time_string(move |time| {
controller.time_string(map_time_to_time_model(time)).into()
})
}
});
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_time_stamp(move |date, time| {
controller
.time_stamp(map_date_to_date_model(date), map_time_to_time_model(time))
.into()
})
}
});
}
pub fn connect_task_list_controller(view_handle: &ui::MainWindow, controller: TaskListController) {
connect_with_task_list_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_create(move |title, time_stamp| {
controller.create_task(title.as_str(), time_stamp as i64)
})
}
});
}
fn map_time_model_to_time(time_model: TimeModel) -> ui::Time {
ui::Time {
hour: time_model.hour as i32,
minute: time_model.minute as i32,
second: time_model.second as i32,
}
}
fn map_time_to_time_model(time: ui::Time) -> TimeModel {
TimeModel { hour: time.hour as u32, minute: time.minute as u32, second: time.second as u32 }
}
fn map_date_model_to_date(date_model: DateModel) -> ui::Date {
ui::Date { year: date_model.year, month: date_model.month as i32, day: date_model.day as i32 }
}
fn map_date_to_date_model(date: ui::Date) -> DateModel {
DateModel { year: date.year, month: date.month as u32, day: date.day as u32 }
}

View file

@ -0,0 +1,34 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
use slint::*;
use crate::{
mvc::{CreateTaskController, TaskListController},
ui,
};
// one place to implement connection between adapter (view) and controller
pub fn connect_create_task_controller(
view_handle: &ui::MainWindow,
controller: CreateTaskController,
) {
controller.on_back({
let view_handle = view_handle.as_weak();
move || {
view_handle.unwrap().global::<ui::NavigationAdapter>().invoke_previous_page();
}
});
}
// one place to implement connection between adapter (view) and controller
pub fn connect_task_list_controller(view_handle: &ui::MainWindow, controller: TaskListController) {
controller.on_show_create_task({
let view_handle = view_handle.as_weak();
move || {
view_handle.unwrap().global::<ui::NavigationAdapter>().invoke_next_page();
}
});
}

View file

@ -0,0 +1,66 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
use chrono::DateTime;
use slint::*;
use std::rc::Rc;
use crate::{
mvc::{TaskListController, TaskModel},
ui,
};
// a helper function to make adapter and controller connection a little bit easier
pub fn connect_with_controller(
view_handle: &ui::MainWindow,
controller: &TaskListController,
connect_adapter_controller: impl FnOnce(ui::TaskListAdapter, TaskListController) + 'static,
) {
connect_adapter_controller(view_handle.global::<ui::TaskListAdapter>(), controller.clone());
}
// one place to implement connection between adapter (view) and controller
pub fn connect(view_handle: &ui::MainWindow, controller: TaskListController) {
// sets a mapped list of the task items to the ui
view_handle
.global::<ui::TaskListAdapter>()
.set_tasks(Rc::new(MapModel::new(controller.task_model(), map_task_to_item)).into());
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_toggle_task_checked(move |index| {
controller.toggle_done(index as usize);
})
}
});
connect_with_controller(view_handle, &controller, {
move |adapter, controller| {
adapter.on_remove_task(move |index| {
controller.remove_task(index as usize);
})
}
});
connect_with_controller(view_handle, &controller, {
move |adapter: ui::TaskListAdapter, controller| {
adapter.on_show_create_task(move || {
controller.show_create_task();
})
}
});
}
// maps a TaskModel (data) to a SelectionItem (ui)
fn map_task_to_item(task: TaskModel) -> ui::SelectionListViewItem {
ui::SelectionListViewItem {
text: task.title.into(),
checked: task.done,
description: DateTime::from_timestamp_millis(task.due_date)
.unwrap()
// example: Thu, Jun 6, 2024 16:29
.format("%a, %b %d, %Y %H:%M")
.to_string()
.into(),
}
}