diff --git a/external/mirai-core/include/mirai-core/MarkdownDataProvider.h b/external/mirai-core/include/mirai-core/MarkdownDataProvider.h index cf9d124..a88da83 100644 --- a/external/mirai-core/include/mirai-core/MarkdownDataProvider.h +++ b/external/mirai-core/include/mirai-core/MarkdownDataProvider.h @@ -36,6 +36,8 @@ class MarkdownDataProvider : public DataProvider std::string toMarkdown(); MarkdownData parseMarkdown(const std::string &content); + std::string path() const; + void save() override; void load() override; diff --git a/external/mirai-core/include/mirai-core/Source.h b/external/mirai-core/include/mirai-core/Source.h index 2917da2..a45ba95 100644 --- a/external/mirai-core/include/mirai-core/Source.h +++ b/external/mirai-core/include/mirai-core/Source.h @@ -53,6 +53,8 @@ class Source void load(); std::string name() const; + std::string type() const; + DataProvider *dataProvider(); void createTask(const createTaskParams &task); void removeTask(const Task &task); diff --git a/external/mirai-core/src/MarkdownDataProvider.cpp b/external/mirai-core/src/MarkdownDataProvider.cpp index 83440a6..d72c3cf 100644 --- a/external/mirai-core/src/MarkdownDataProvider.cpp +++ b/external/mirai-core/src/MarkdownDataProvider.cpp @@ -18,6 +18,11 @@ namespace mirai { +std::string MarkdownDataProvider::path() const +{ + return filePath_; +} + std::string MarkdownDataProvider::name() const { return data.name; diff --git a/external/mirai-core/src/Source.cpp b/external/mirai-core/src/Source.cpp index 75f48d2..67050a0 100644 --- a/external/mirai-core/src/Source.cpp +++ b/external/mirai-core/src/Source.cpp @@ -82,6 +82,8 @@ void Source::createEvent(const createEventParams &eventToCreate) .id = generateUniqueId(), .dayId = day.value().id, .title = eventToCreate.title, + .startsAt = eventToCreate.startsAt, + .endsAt = eventToCreate.endsAt, }); }; @@ -144,4 +146,15 @@ std::string Source::name() const { return data->name(); } + +std::string Source::type() const +{ + // There is only 1 type for now + return "MarkdownFile"; +} + +DataProvider *Source::dataProvider() +{ + return data; +} } // namespace mirai diff --git a/external/mirai-core/src/View.cpp b/external/mirai-core/src/View.cpp index c980d0a..cfe4aff 100644 --- a/external/mirai-core/src/View.cpp +++ b/external/mirai-core/src/View.cpp @@ -43,6 +43,9 @@ std::vector View::getTasksForDate(const Date &date) std::vector View::getEventsForDate(const Date &date) { + if (!dates.contains(date)) { + return {}; + } return dates.at(date).events; } diff --git a/external/selenite b/external/selenite index cbab9da..33d6a9d 160000 --- a/external/selenite +++ b/external/selenite @@ -1 +1 @@ -Subproject commit cbab9dabe784bd3c799d23ead5d2b4d942ec4081 +Subproject commit 33d6a9dee8437979b5a9bf5a716a4053f3ebf2fa diff --git a/src/AppWindowBackend.cpp b/src/AppWindowBackend.cpp index ee1cf05..47a370e 100644 --- a/src/AppWindowBackend.cpp +++ b/src/AppWindowBackend.cpp @@ -5,10 +5,13 @@ */ #include "AppWindowBackend.h" +#include "AppWindow.h" #include "SeleniteSetup.h" #include "Utils.h" -#include "appwindow.h" +#include "mirai-core/DataProvider.h" +#include "mirai-core/DateTime.h" #include "mirai-core/Day.h" +#include "mirai-core/MarkdownDataProvider.h" #include "mirai-core/Mirai.h" #include "slint.h" #include "slint_string.h" @@ -34,6 +37,7 @@ AppWindowBackend::AppWindowBackend(mirai::Mirai *miraiInstance) { sources_ = std::make_shared>(); days_ = std::make_shared>(); + calendar_ = std::make_shared>(); unscheduledTasks_ = std::make_shared>(); tags_ = std::make_shared>(); auto sourcesNames = std::make_shared>( @@ -43,14 +47,23 @@ AppWindowBackend::AppWindowBackend(mirai::Mirai *miraiInstance) } ); - const auto palette = - selenite::parseJson(std::string(getenv("HOME")) + "/.config/evalyte/theme.json"); + const auto palettePath = std::string(getenv("HOME")) + "/.config/evalyte/theme.json"; + const auto palette = selenite::parseJson(palettePath); if (palette.has_value()) { - std::cerr << "Warning, no evalyte/theme.json found" << std::endl; - setSelenitePalette(mainWindow_, palette.value()); + std::cerr << "Warning, no " << palettePath << " found" << std::endl; + setSelenitePalette(mainWindow_->global(), palette.value()); + setSelenitePalette(settingsWindow_->global(), palette.value()); } mainWindow_->global().set_sources(sourcesNames); + settingsWindow_->global().set_sources(sourcesNames); + + mainWindow_->global().set_sources_selected(sources_); + settingsWindow_->global().set_sources_selected(sources_); + + mainWindow_->global().set_tags(tags_); + mainWindow_->global().set_days(days_); + mainWindow_->global().set_calendar(calendar_); view_.setAllSources(); view_.update(); @@ -92,10 +105,17 @@ void AppWindowBackend::setupUtilsCallbacks() }; return std::format("{:%B %d}", chronoDate); }); + + mainWindow_->global().on_format_date_relative([&](const ui::Date &date) { + return formatDateRelative(date); + }); } void AppWindowBackend::setupCallbacks() { + mainWindow_->global().on_settings_clicked([&]() { + settingsWindow_->show(); + }); mainWindow_->global().on_task_clicked([&](int sourceId, int taskId) { auto source = miraiInstance_->getSourceById(sourceId); assert(source); @@ -142,10 +162,6 @@ void AppWindowBackend::setupCallbacks() reloadTasks(); }); - mainWindow_->global().set_sources_selected(sources_); - mainWindow_->global().set_tags(tags_); - mainWindow_->global().set_days(days_); - mainWindow_->global().on_save_task([&](ui::SaveTaskData newTaskData) { auto source = miraiInstance_->getSourceById(newTaskData.sourceId); assert(source); @@ -326,6 +342,42 @@ void AppWindowBackend::reloadTasks() }); } mainWindow_->global().set_unscheduled_tasks(unscheduledTasks_); + + calendar_->clear(); + for (int dayIndex = 0; dayIndex < 7; ++dayIndex) { + std::chrono::year_month_day nextDate = + std::chrono::floor(std::chrono::system_clock::now()) + + std::chrono::days{dayIndex}; + auto currentDate = mirai::Date{nextDate}; + auto events = view_.getEventsForDate(currentDate); + auto slintEvents = std::make_shared>(); + auto relativeDaysDiff = std::chrono::duration_cast( + std::chrono::sys_days(currentDate.toStdChrono()) - + std::chrono::sys_days(todayDate.toStdChrono()) + ) + .count(); + if (relativeDaysDiff < 0 || relativeDaysDiff >= 3) { + continue; + } + const std::vector eventsForDate = view_.getEventsForDate(currentDate); + for (int eventIndex = 0; eventIndex < eventsForDate.size(); ++eventIndex) { + auto ¤tEvent = eventsForDate.at(eventIndex); + slintEvents->push_back(ui::CalendarDayEvent{ + .title = slint::SharedString(currentEvent.title()), + .startsAt = MiraiTimeToSlintTime(currentEvent.startsAt()), + .endsAt = MiraiTimeToSlintTime(currentEvent.endsAt()), + }); + } + + auto calendarDay = ui::CalendarDay{ + .events = slintEvents, + .date = MiraiDateToSlintDate(currentDate), + .header = + slint::SharedString(capitalize(formatDateRelative(MiraiDateToSlintDate(currentDate)) + )) + }; + calendar_->push_back(calendarDay); + } } void AppWindowBackend::reloadSources() @@ -334,9 +386,12 @@ void AppWindowBackend::reloadSources() bool noSourceSelected = miraiInstance_->getSources().size() == view_.activeSourceCount(); for (const auto &source : miraiInstance_->getSources()) { bool isSourceSelected = view_.isSourceSelected(*source); + mirai::MarkdownDataProvider *sourceProvider = + dynamic_cast(source->dataProvider()); sources_->push_back( {.name = slint::SharedString(source->name()), - .selected = isSourceSelected && !noSourceSelected} + .selected = isSourceSelected && !noSourceSelected, + .path = slint::SharedString(sourceProvider->path())} ); } mainWindow_->global().set_no_source_selected(noSourceSelected); diff --git a/src/AppWindowBackend.h b/src/AppWindowBackend.h index b9c89bf..5c6379e 100644 --- a/src/AppWindowBackend.h +++ b/src/AppWindowBackend.h @@ -6,7 +6,7 @@ #pragma once -#include "appwindow.h" +#include "AppWindow.h" #include "mirai-core/Mirai.h" #include "mirai-core/View.h" #include "slint.h" @@ -29,9 +29,11 @@ class AppWindowBackend std::shared_ptr> sources_; std::shared_ptr> tags_; std::shared_ptr> days_; + std::shared_ptr> calendar_; std::shared_ptr> unscheduledTasks_; slint::ComponentHandle mainWindow_ = ui::AppWindow::create(); + slint::ComponentHandle settingsWindow_ = ui::SettingsWindow::create(); mirai::Mirai *miraiInstance_; mirai::View view_; diff --git a/src/SeleniteSetup.h b/src/SeleniteSetup.h index 4eade98..2b914b0 100644 --- a/src/SeleniteSetup.h +++ b/src/SeleniteSetup.h @@ -6,7 +6,7 @@ #pragma once -#include "appwindow.h" +#include "AppWindow.h" #include "selenite/palette.h" #include "slint_color.h" @@ -15,10 +15,8 @@ slint::Color seleniteColorToSlint(const selenite::Color &color) return slint::Color::from_rgb_uint8(color.r, color.g, color.b); } -void setSelenitePalette(slint::ComponentHandle ui, const selenite::Palette &palette) +void setSelenitePalette(const ui::Palette &uiPalette, const selenite::Palette &palette) { - auto &uiPalette = ui->global(); - uiPalette.set_background(seleniteColorToSlint(palette.background)); uiPalette.set_pane(seleniteColorToSlint(palette.pane)); uiPalette.set_foreground(seleniteColorToSlint(palette.foreground)); diff --git a/src/Utils.cpp b/src/Utils.cpp index 58b2e3e..169ed93 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -5,6 +5,9 @@ */ #include "Utils.h" +#include +#include +#include std::string formatZeroPadding(const int number) { @@ -14,6 +17,29 @@ std::string formatZeroPadding(const int number) return std::to_string(number); } +std::string formatDateRelative(const ui::Date &date) +{ + auto todayDate = mirai::Date(std::chrono::system_clock::now()); + auto relativeDaysDiff = std::chrono::duration_cast( + std::chrono::sys_days(SlintDateToMiraiDate(date).toStdChrono()) - + std::chrono::sys_days(todayDate.toStdChrono()) + ) + .count(); + + if (relativeDaysDiff == 0) { + return std::string("today"); + } else if (relativeDaysDiff == 1) { + return std::string("tomorrow"); + } + return std::format("in {} days", relativeDaysDiff); +}; + +std::string capitalize(std::string str) +{ + str[0] = static_cast(toupper(str[0])); + return str; +}; + std::string SlintDateToStdString(const ui::Date &date) { return std::to_string(date.year) + "-" + formatZeroPadding(date.month) + "-" + diff --git a/src/Utils.h b/src/Utils.h index 0595f2e..4af3230 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -6,11 +6,13 @@ #pragma once -#include "appwindow.h" +#include "AppWindow.h" #include "mirai-core/DateTime.h" #include std::string formatZeroPadding(const int number); +std::string formatDateRelative(const ui::Date &date); +std::string capitalize(std::string str); std::string SlintDateToStdString(const ui::Date &date); mirai::Date SlintDateToMiraiDate(const ui::Date &date); ui::Date MiraiDateToSlintDate(const mirai::Date &date); diff --git a/ui/AppWindow.slint b/ui/AppWindow.slint index 72de94d..ad33ee8 100644 --- a/ui/AppWindow.slint +++ b/ui/AppWindow.slint @@ -2,6 +2,7 @@ import { Backend } from "Backend.slint"; import { Button, VerticalBox, CheckBox } from "std-widgets.slint"; import { SideBar } from "./components/SideBar.slint"; import { MainView } from "MainView.slint"; +import { SettingsWindow } from "SettingsWindow.slint"; import { Palette } from "@selenite"; export component AppWindow inherits Window { @@ -11,8 +12,6 @@ export component AppWindow inherits Window { max-height: 4000px; // needed, otherwise the window wants to fit the content (on Swaywm) default-font-size: 16px; - in-out property test; - HorizontalLayout { SideBar {} MainView { @@ -22,4 +21,4 @@ export component AppWindow inherits Window { } -export { Backend, Palette } // Export to make it visible to the C++ backend +export { Backend, Palette, SettingsWindow } // Export to make it visible to the C++ backend diff --git a/ui/Backend.slint b/ui/Backend.slint index b727134..4cea021 100644 --- a/ui/Backend.slint +++ b/ui/Backend.slint @@ -1,4 +1,5 @@ import { Date, Time } from "std-widgets.slint"; +import { CalendarDay } from "components/Calendar.slint"; export struct NewTaskData { sourceId: int, @@ -35,7 +36,8 @@ export struct SaveEventParams { export struct Source { name: string, - selected: bool + selected: bool, + path: string } export struct TaskData { @@ -78,11 +80,13 @@ export global Backend { in-out property no-source-selected; in-out property<[string]> tags; in-out property<[Day]> days; + in-out property<[CalendarDay]> calendar; in-out property<[TaskData]> unscheduled-tasks; callback task-clicked(int, int); callback source-clicked(int); callback tag-clicked(int); + callback settings-clicked(); callback open-new-task-form(OpenNewTaskFormParams); callback open-edit-task-form(int, int); @@ -98,4 +102,6 @@ export global Backend { callback save-event(SaveEventParams); pure callback format-date(Date) -> string; + pure callback format-date-relative(Date) -> string; + pure callback capitalize-string(string) -> string; } diff --git a/ui/MainView.slint b/ui/MainView.slint index 5f725cb..0adffc9 100644 --- a/ui/MainView.slint +++ b/ui/MainView.slint @@ -2,6 +2,7 @@ import { Backend, TaskData } from "Backend.slint"; import { Button, VerticalBox, CheckBox, ScrollView, ComboBox } from "std-widgets.slint"; import { TaskLine } from "./components/TaskLine.slint"; import { EventGroup } from "./components/EventGroup.slint"; +import { Calendar } from "./components/Calendar.slint"; import { VPopupIconMenu, VDatePicker, VTimePicker, VCheckBox, VButton, VTag, VText, VTextInput, Svg, Palette } from "@selenite"; import { NewTaskData, SaveTaskData } from "Backend.slint"; import { CreateTaskOrEvent } from "components/CreateTaskOrEvent.slint"; @@ -13,111 +14,113 @@ export component MainView inherits Rectangle { private property icon-not-visible: Svg.not-visible; private property completed-tasks-visible: false; - VerticalLayout { - horizontal-stretch: 1; - padding: 16px; - spacing: 16px; - alignment: start; - HorizontalLayout { - horizontal-stretch: 1; - alignment: start; - spacing: 8px; - VButton { - text: "Show/Hide completed tasks"; - clicked => { - Backend.toggle-show-completed-tasks(); - completed-tasks-visible = !completed-tasks-visible; - } - icon-svg: completed-tasks-visible ? icon-visible : icon-not-visible; - icon-colorize: Palette.control-foreground; - } - } - Rectangle { - horizontal-stretch: 1; - background: Palette.background.brighter(0.2); - height: 1px; - } + HorizontalLayout { - CreateTaskOrEvent { - - } - - Flickable { + VerticalLayout { horizontal-stretch: 1; - VerticalLayout { + padding: 16px; + spacing: 16px; + HorizontalLayout { + horizontal-stretch: 1; alignment: start; - spacing: 16px; - if Backend.days.length == 0 && Backend.unscheduled-tasks.length == 0 : VText { - text: "There is no task to show"; - horizontal-alignment: center; - vertical-alignment: center; + spacing: 8px; + VButton { + text: "Show/Hide completed tasks"; + clicked => { + Backend.toggle-show-completed-tasks(); + completed-tasks-visible = !completed-tasks-visible; + } + icon-svg: completed-tasks-visible ? icon-visible : icon-not-visible; + icon-colorize: Palette.control-foreground; } - for day[dayIndex] in Backend.days: VerticalLayout { - Rectangle { - background: Palette.card-background; - border-radius: 8px; - VerticalLayout { - padding: 16px; - HorizontalLayout { - alignment: start; - VText { - text: Backend.format-date(day.date); - color: day.isLate ? Palette.orange : Palette.foreground; - font-size: 1.2rem; - } - VerticalLayout { - alignment: center; + } + Rectangle { + horizontal-stretch: 1; + background: Palette.background.brighter(0.2); + height: 1px; + } + + CreateTaskOrEvent { + + } + + Flickable { + horizontal-stretch: 1; + VerticalLayout { + alignment: start; + spacing: 16px; + if Backend.days.length == 0 && Backend.unscheduled-tasks.length == 0 : VText { + text: "There is no task to show"; + horizontal-alignment: center; + vertical-alignment: center; + } + for day[dayIndex] in Backend.days: VerticalLayout { + Rectangle { + background: Palette.card-background; + border-radius: 8px; + VerticalLayout { + padding: 16px; + HorizontalLayout { + alignment: start; VText { - text: day.relativeDaysDiff == 0 ? " - today" : - day.relativeDaysDiff == 1 ? " - tomorrow" : - day.relativeDaysDiff == -1 ? " - yesterday" : - day.relativeDaysDiff > 0 ? " - in \{day.relativeDaysDiff} days" : - " - \{-day.relativeDaysDiff} days ago"; - color: Palette.foreground-hint; - font-size: 1rem; + text: Backend.format-date(day.date); + color: day.isLate ? Palette.orange : Palette.foreground; + font-size: 1.2rem; + } + VerticalLayout { + alignment: center; + VText { + text: day.relativeDaysDiff == 0 ? " - today" : + day.relativeDaysDiff == 1 ? " - tomorrow" : + day.relativeDaysDiff == -1 ? " - yesterday" : + day.relativeDaysDiff > 0 ? " - in \{day.relativeDaysDiff} days" : + " - \{-day.relativeDaysDiff} days ago"; + color: Palette.foreground-hint; + font-size: 1rem; + } + } + } + for event[eventIndex] in day.events: VerticalLayout { + padding-top: 16px; + EventGroup { + event: event; + } + } + for task[taskIndex] in day.tasks: VerticalLayout { + padding-top: taskIndex == 0 ? 16px : 0px; + padding-bottom: 8px; + TaskLine { + task: task; + date: day.date; + source-index: task.sourceId; + task-index: task.id; } } } - for event[eventIndex] in day.events: VerticalLayout { - padding-top: 16px; - EventGroup { - event: event; - } - } - for task[taskIndex] in day.tasks: VerticalLayout { - padding-top: taskIndex == 0 ? 16px : 0px; - padding-bottom: 8px; - TaskLine { - task: task; - date: day.date; - source-index: task.sourceId; - task-index: task.id; - } - } } } - } - if Backend.unscheduled-tasks.length > 0 : VerticalLayout { - Rectangle { - background: Palette.card-background; - border-radius: 8px; - VerticalLayout { - padding: 16px; - HorizontalLayout { - alignment: start; - VText { - text: "Unscheduled"; - color: Palette.foreground; - font-size: 1.2rem; + if Backend.unscheduled-tasks.length > 0 : VerticalLayout { + Rectangle { + background: Palette.card-background; + border-radius: 8px; + VerticalLayout { + padding: 16px; + HorizontalLayout { + alignment: start; + VText { + text: "Unscheduled"; + color: Palette.foreground; + font-size: 1.2rem; + } } - } - for task[taskIndex] in Backend.unscheduled-tasks: VerticalLayout { - padding-top: taskIndex == 0 ? 16px : 0px; - padding-bottom: 8px; - TaskLine { - task: task; - source-index: task.sourceId; - task-index: task.id; + for task[taskIndex] in Backend.unscheduled-tasks: VerticalLayout { + padding-top: taskIndex == 0 ? 16px : 0px; + padding-bottom: 8px; + TaskLine { + task: task; + source-index: task.sourceId; + task-index: task.id; + } } } } @@ -125,5 +128,10 @@ export component MainView inherits Rectangle { } } } + Calendar { + init => { debug("cal len", Backend.calendar.length) } + days: Backend.calendar; + } } + } diff --git a/ui/SettingsWindow.slint b/ui/SettingsWindow.slint new file mode 100644 index 0000000..ec9da4f --- /dev/null +++ b/ui/SettingsWindow.slint @@ -0,0 +1,29 @@ +import { Backend } from "Backend.slint"; +import { Button, VerticalBox, CheckBox } from "std-widgets.slint"; +import { SideBar } from "./components/SideBar.slint"; +import { MainView } from "MainView.slint"; +import { VText, VTextInput, Palette } from "@selenite"; + +export component SettingsWindow inherits Window { + + title: "Mirai - Settings"; + min-height: 100px; + max-height: 4000px; // needed, otherwise the window wants to fit the content (on Swaywm) + default-font-size: 16px; + background: Palette.background; + + VerticalLayout { + padding: 16px; + spacing: 8px; + for source[source-index] in Backend.sources-selected: VerticalLayout { + VText { + text: source.name; + } + VTextInput { + text: source.path; + } + } + } +} + +export { Backend, Palette } // Export to make it visible to the C++ backend diff --git a/ui/components/Calendar.slint b/ui/components/Calendar.slint new file mode 100644 index 0000000..f5b523f --- /dev/null +++ b/ui/components/Calendar.slint @@ -0,0 +1,112 @@ +import { ScrollView, Date, Time } from "std-widgets.slint"; +import { VCheckBox, VButton, VActionButton, Svg, VTag, VPopupIconMenu, VText, Palette } from "@selenite"; +import { Utils } from "../Utils.slint"; + +export struct CalendarDayEvent { + title: string, + startsAt: Time, + endsAt: Time +} + +export struct CalendarDay { + events: [CalendarDayEvent], + date: Date, + header: string, +} + +export enum CalendarDateDisplayFormat { + Relative, + Normal +} + +export component Calendar inherits Rectangle { + in property<[CalendarDay]> days; + in property format; + private property header-height: 64px; + private property available-day-space: self.height - header-height; + private property day-start-y: header-height; + private property hour-spacing: available-day-space / 24; + background: Palette.pane; + + HorizontalLayout { + Rectangle { + //background: red; + width: 48px; + VerticalLayout { + y: 0; + height: header-height; + padding-right: 8px; + VText { + vertical-alignment: center; + horizontal-alignment: right; + text: ""; + } + } + + for index in 24: VerticalLayout { + y: day-start-y + index * hour-spacing - (hour-spacing / 2); + height: hour-spacing; + padding-right: 8px; + VText { + vertical-alignment: center; + horizontal-alignment: right; + text: "\{index}h"; + } + } + + } + Rectangle { + //background: green; + HorizontalLayout { + for day[day-index] in root.days: Rectangle { + if day-index > 0 : Rectangle { + x: 0; + y: header-height - 32px; + width: 1px; + height: parent.height; + background: Palette.card-background.transparentize(0.5); + } + VerticalLayout { + y: 0; + height: header-height; + padding-right: 8px; + VText { + vertical-alignment: center; + horizontal-alignment: center; + text: day.header; + } + } + for hour[hour-index] in 24 : Rectangle { + background: Palette.card-background.transparentize(0.5); + x: 0px; + width: parent.width; + y: day-start-y + hour-spacing * hour-index; + height: 1px; + } + for event[event-index] in day.events : Rectangle { + background: Palette.card-background; + border-radius: 4px; + x: 8px; + width: parent.width - 16px; + y: day-start-y + hour-spacing * event.startsAt.hour; + height: hour-spacing * (event.endsAt.hour - event.startsAt.hour) - 2px; + clip: true; + HorizontalLayout { + Rectangle { + width: 4px; + background: Palette.accent; + } + VerticalLayout { + padding: 16px; + VText { + text: event.title; + wrap: TextWrap.word-wrap; + } + } + } + } + } + } + } + } +} diff --git a/ui/components/EventGroup.slint b/ui/components/EventGroup.slint index 40c4a8e..f868781 100644 --- a/ui/components/EventGroup.slint +++ b/ui/components/EventGroup.slint @@ -62,7 +62,7 @@ export component EventGroup { VText { text: Utils.time-to-string(event.endsAt); color: Palette.accent; - font-size: 0.8rem; + font-size: 0.9rem; horizontal-alignment: center; } } diff --git a/ui/components/SideBar.slint b/ui/components/SideBar.slint index 12acd97..26d3841 100644 --- a/ui/components/SideBar.slint +++ b/ui/components/SideBar.slint @@ -1,11 +1,11 @@ import { Backend } from "../Backend.slint"; -import { ToggleButton, VText, Palette } from "@selenite"; +import { VButton, ToggleButton, VText, Svg, Palette } from "@selenite"; export component SideBar inherits Rectangle { background: Palette.pane; VerticalLayout { - alignment: start; + height: parent.height; padding: 16px; spacing: 16px; VText { @@ -13,19 +13,33 @@ export component SideBar inherits Rectangle { font-size: 1.5rem; } VerticalLayout { - spacing: 4px; - ToggleButton { - text: "All"; - text-alignment: left; - active: Backend.no-source-selected; - clicked => { Backend.source-clicked(-1) } - } - for item[index] in Backend.sources-selected: ToggleButton { - text: item.name; - text-alignment: left; - active: item.selected; - clicked => { Backend.source-clicked(index) } + alignment: space-between; + vertical-stretch: 1; + VerticalLayout { + vertical-stretch: 1; + spacing: 4px; + ToggleButton { + text: "All"; + text-alignment: left; + active: Backend.no-source-selected; + clicked => { Backend.source-clicked(-1) } + } + for item[index] in Backend.sources-selected: ToggleButton { + text: item.name; + text-alignment: left; + active: item.selected; + clicked => { Backend.source-clicked(index) } + } } + /*VerticalLayout { + spacing: 4px; + VButton { + icon-svg: Svg.cog; + text: "Settings"; + background: transparent; + clicked => { Backend.settings-clicked() } + } + }*/ } } }