mirror of
https://codeberg.org/vyn/mirai.git
synced 2025-07-02 01:13:19 +00:00
Add new 'Add task/event' bar directly in the main view
This commit is contained in:
parent
534da46a26
commit
2aa039e5fc
18 changed files with 399 additions and 51 deletions
|
@ -44,6 +44,7 @@ class TasksView
|
|||
void removeFilters();
|
||||
const Tags &getActiveTagsFilter();
|
||||
const std::vector<std::string> &getActiveFilesFilter();
|
||||
bool isSourceFilterActive(const std::string &sourceName);
|
||||
|
||||
void hideCompletedTasks(bool hide);
|
||||
bool shouldHideCompletedTasks() const;
|
||||
|
|
10
external/mirai-core/src/TasksView.cpp
vendored
10
external/mirai-core/src/TasksView.cpp
vendored
|
@ -177,6 +177,7 @@ void TasksView::removeSourceFilter(const std::string &fileName)
|
|||
void TasksView::removeFilters()
|
||||
{
|
||||
tagsFilter.clear();
|
||||
resourcesFilter.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -190,6 +191,15 @@ const std::vector<std::string> &TasksView::getActiveFilesFilter()
|
|||
return resourcesFilter;
|
||||
}
|
||||
|
||||
bool TasksView::isSourceFilterActive(const std::string &sourceName)
|
||||
{
|
||||
if (std::ranges::find(getActiveFilesFilter(), sourceName) == getActiveFilesFilter().end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TasksView::hideCompletedTasks(bool hide)
|
||||
{
|
||||
shouldHideCompletedTasks_ = hide;
|
||||
|
|
49
external/slint-vynui/ActionButton.slint
vendored
Normal file
49
external/slint-vynui/ActionButton.slint
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { Palette } from "Palette.slint";
|
||||
import { VText } from "Text.slint";
|
||||
|
||||
export component VActionButton inherits Rectangle {
|
||||
|
||||
in property<image> icon-source;
|
||||
in property<brush> icon-colorize: Palette.foreground;
|
||||
in property<length> icon-size: 1rem;
|
||||
in property<string> icon-svg;
|
||||
in property enabled <=> ta.enabled;
|
||||
callback clicked;
|
||||
|
||||
private property<bool> active: false;
|
||||
|
||||
background: enabled ? Palette.control-background : Palette.control-background.darker(0.2);
|
||||
border-radius: 4px;
|
||||
|
||||
ta := TouchArea {
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
active = !active;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: center;
|
||||
spacing: 8px;
|
||||
padding: 8px;
|
||||
if root.icon-svg != "" : VerticalLayout {
|
||||
alignment: center;
|
||||
Path {
|
||||
padding: 8px;
|
||||
commands: root.icon-svg;
|
||||
stroke: icon-colorize;
|
||||
stroke-width: 2px;
|
||||
width: icon-size;
|
||||
height: icon-size;
|
||||
fill: icon-colorize;
|
||||
}
|
||||
}
|
||||
if root.icon-source.width != 0 : Image {
|
||||
padding: 8px;
|
||||
source: icon-source;
|
||||
colorize: icon-colorize;
|
||||
width: icon-size;
|
||||
}
|
||||
}
|
||||
}
|
9
external/slint-vynui/BurgerIcon.slint
vendored
Normal file
9
external/slint-vynui/BurgerIcon.slint
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { Palette } from "./Palette.slint";
|
||||
|
||||
export component BurgerIcon inherits Path {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
commands: "M3 6h18M3 12h18M3 18h18";
|
||||
stroke: Palette.foreground;
|
||||
stroke-width: 2px;
|
||||
}
|
18
external/slint-vynui/Button.slint
vendored
18
external/slint-vynui/Button.slint
vendored
|
@ -5,9 +5,11 @@ export component VButton inherits Rectangle {
|
|||
|
||||
in property<string> text;
|
||||
in property<brush> text-color: Palette.foreground;
|
||||
in property<length> text-size: 1rem;
|
||||
in property<image> icon-source;
|
||||
in property<brush> icon-colorize;
|
||||
in property<brush> icon-colorize: Palette.foreground;
|
||||
in property<length> icon-size: 1rem;
|
||||
in property <string> icon-svg;
|
||||
in property enabled <=> ta.enabled;
|
||||
callback clicked;
|
||||
|
||||
|
@ -27,9 +29,20 @@ export component VButton inherits Rectangle {
|
|||
HorizontalLayout {
|
||||
alignment: center;
|
||||
spacing: 8px;
|
||||
padding: 8px;
|
||||
padding: 16px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
if root.icon-svg != "" : VerticalLayout {
|
||||
alignment: center;
|
||||
Path {
|
||||
padding: 8px;
|
||||
commands: root.icon-svg;
|
||||
stroke: icon-colorize;
|
||||
stroke-width: 2px;
|
||||
width: icon-size;
|
||||
height: icon-size;
|
||||
}
|
||||
}
|
||||
if root.icon-source.width != 0 : Image {
|
||||
padding: 8px;
|
||||
source: icon-source;
|
||||
|
@ -39,6 +52,7 @@ export component VButton inherits Rectangle {
|
|||
if root.text != "" : VerticalLayout {
|
||||
VText {
|
||||
text: root.text;
|
||||
font-size: root.text-size;
|
||||
color: root.text-color;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
|
|
48
external/slint-vynui/LabeledComponent.slint
vendored
48
external/slint-vynui/LabeledComponent.slint
vendored
|
@ -2,21 +2,59 @@ import { Palette } from "Palette.slint";
|
|||
import { VText } from "Text.slint";
|
||||
|
||||
export component VLabeledComponent {
|
||||
in property<string> label <=> labelComponent.text;
|
||||
in property<string> label;
|
||||
in property<length> label-size: 1rem;
|
||||
in property <TextHorizontalAlignment> label-alignment: TextHorizontalAlignment.left;
|
||||
in property<bool> enabled: true;
|
||||
in property<bool> no-background: false;
|
||||
|
||||
function calc-background() -> brush {
|
||||
if (no-background == true) {
|
||||
return Palette.control-background.transparentize(1);
|
||||
}
|
||||
if (enabled == false) {
|
||||
return Palette.control-background.darker(0.2);
|
||||
}
|
||||
return Palette.control-background;
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
labelComponent := VText {
|
||||
|
||||
if root.label != "" : VerticalLayout {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
VText {
|
||||
text: root.label;
|
||||
font-size: label-size;
|
||||
horizontal-alignment: root.label-alignment;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
background: enabled ? Palette.control-background : Palette.control-background.darker(0.2);
|
||||
background: calc-background();
|
||||
border-radius: 4px;
|
||||
VerticalLayout {
|
||||
padding: 4px;
|
||||
@children
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export component CommonComponentBackground {
|
||||
in property<bool> enabled: true;
|
||||
in property<bool> no-background: false;
|
||||
|
||||
function calc-background() -> brush {
|
||||
if (no-background == true) {
|
||||
return Palette.control-background.transparentize(1);
|
||||
}
|
||||
if (enabled == false) {
|
||||
return Palette.control-background.darker(0.2);
|
||||
}
|
||||
return Palette.control-background;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
background: calc-background();
|
||||
@children
|
||||
}
|
||||
}
|
||||
|
|
34
external/slint-vynui/Slider.slint
vendored
Normal file
34
external/slint-vynui/Slider.slint
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { VLabeledComponent } from "LabeledComponent.slint";
|
||||
import { Palette } from "Palette.slint";
|
||||
import { Slider } from "std-widgets.slint";
|
||||
import { VText } from "Text.slint";
|
||||
|
||||
export component VSlider inherits VLabeledComponent {
|
||||
in property <bool> show-value;
|
||||
in-out property <float> value;
|
||||
|
||||
init => {
|
||||
sliderComponent.value = root.value;
|
||||
}
|
||||
|
||||
pure callback format-value(float) -> string;
|
||||
format-value(value) => {
|
||||
return "\{value}";
|
||||
}
|
||||
|
||||
callback released <=> sliderComponent.released;
|
||||
in property minimum <=> sliderComponent.minimum;
|
||||
in property maximum <=> sliderComponent.maximum;
|
||||
|
||||
VerticalLayout {
|
||||
spacing: 8px;
|
||||
VText {
|
||||
horizontal-alignment: center;
|
||||
text: format-value(sliderComponent.value);
|
||||
color: Palette.foreground-hint;
|
||||
}
|
||||
sliderComponent := Slider {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
18
external/slint-vynui/TextInput.slint
vendored
18
external/slint-vynui/TextInput.slint
vendored
|
@ -1,13 +1,31 @@
|
|||
import { VLabeledComponent } from "LabeledComponent.slint";
|
||||
import { Palette } from "Palette.slint";
|
||||
import { VText } from "Text.slint";
|
||||
|
||||
export component VTextInput inherits VLabeledComponent {
|
||||
in-out property text <=> textInputComponent.text;
|
||||
out property has-focus <=> textInputComponent.has-focus;
|
||||
in-out property placeholder <=> textInputComponent.accessible-placeholder-text;
|
||||
in-out property wrap <=> textInputComponent.wrap;
|
||||
callback accepted();
|
||||
|
||||
VerticalLayout {
|
||||
padding: 4px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
textInputComponent := TextInput {
|
||||
color: Palette.foreground;
|
||||
accepted => { root.accepted() }
|
||||
HorizontalLayout {
|
||||
alignment: start;
|
||||
VText {
|
||||
visible: textInputComponent.text == "";
|
||||
color: Palette.foreground-hint;
|
||||
text: root.placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
3
external/slint-vynui/ToggleButton.slint
vendored
3
external/slint-vynui/ToggleButton.slint
vendored
|
@ -6,9 +6,9 @@ export component ToggleButton inherits Rectangle {
|
|||
in property text <=> text-component.text;
|
||||
in property text-color <=> text-component.color;
|
||||
in property text-alignment <=> text-component.horizontal-alignment;
|
||||
in property<bool> active: false;
|
||||
callback clicked;
|
||||
|
||||
private property<bool> active: false;
|
||||
|
||||
background: root.active ? Palette.control-background
|
||||
: ta.has-hover ? Palette.control-background.transparentize(0.5)
|
||||
|
@ -18,7 +18,6 @@ export component ToggleButton inherits Rectangle {
|
|||
ta := TouchArea {
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
active = !active;
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
|
|
6
external/slint-vynui/index.slint
vendored
6
external/slint-vynui/index.slint
vendored
|
@ -1,11 +1,15 @@
|
|||
export { Palette } from "Palette.slint";
|
||||
export { VButton } from "Button.slint";
|
||||
export { VActionButton } from "ActionButton.slint";
|
||||
export { VText } from "Text.slint";
|
||||
export { VCheckBox } from "CheckBox.slint";
|
||||
export { VDatePicker } from "DatePicker.slint";
|
||||
export { VTimePicker } from "TimePicker.slint";
|
||||
export { VLabeledComponent } from "LabeledComponent.slint";
|
||||
export { VLabeledComponent, CommonComponentBackground } from "LabeledComponent.slint";
|
||||
export { VPopupIconMenu } from "PopupIconMenu.slint";
|
||||
export { VTag } from "Tag.slint";
|
||||
export { VTextInput } from "TextInput.slint";
|
||||
export { VSlider } from "Slider.slint";
|
||||
export { ToggleButton } from "ToggleButton.slint";
|
||||
|
||||
export { BurgerIcon } from "BurgerIcon.slint";
|
||||
|
|
|
@ -34,14 +34,22 @@
|
|||
|
||||
UiState::UiState(mirai::Mirai *miraiInstance) : miraiInstance_(miraiInstance), view_(miraiInstance)
|
||||
{
|
||||
sources_ = std::make_shared<slint::VectorModel<slint::SharedString>>();
|
||||
sources_ = std::make_shared<slint::VectorModel<Source>>();
|
||||
days_ = std::make_shared<slint::VectorModel<Day>>();
|
||||
unscheduledTasks_ = std::make_shared<slint::VectorModel<TaskData>>();
|
||||
tags_ = std::make_shared<slint::VectorModel<slint::SharedString>>();
|
||||
auto sourcesNames = std::make_shared<slint::MapModel<Source, slint::SharedString>>(
|
||||
sources_,
|
||||
[&](const Source &a) {
|
||||
return a.name;
|
||||
}
|
||||
);
|
||||
|
||||
taskWindow_->global<Backend>().set_sources(sources_);
|
||||
mainWindow_->global<Backend>().set_sources(sourcesNames);
|
||||
taskWindow_->global<Backend>().set_sources_selected(sources_);
|
||||
taskWindow_->global<Backend>().set_sources(sourcesNames);
|
||||
taskWindow_->global<Backend>().set_tags(tags_);
|
||||
eventWindow_->global<Backend>().set_sources(sources_);
|
||||
eventWindow_->global<Backend>().set_sources_selected(sources_);
|
||||
eventWindow_->global<Backend>().set_tags(tags_);
|
||||
|
||||
view_.update();
|
||||
|
@ -76,7 +84,7 @@ std::optional<Date> stringToDate(const std::string &dateStr)
|
|||
|
||||
void UiState::setupTaskWindowCallbacks()
|
||||
{
|
||||
taskWindow_->on_save([&](SaveTaskData newTaskData) {
|
||||
mainWindow_->global<Backend>().on_saveTask([&](SaveTaskData newTaskData) {
|
||||
auto source = miraiInstance_->getSourceById(newTaskData.sourceId);
|
||||
assert(source);
|
||||
auto task = source->getTaskById(newTaskData.id);
|
||||
|
@ -103,7 +111,7 @@ void UiState::setupTaskWindowCallbacks()
|
|||
taskWindow_->hide();
|
||||
});
|
||||
|
||||
taskWindow_->on_create([&](NewTaskData newTaskData) {
|
||||
mainWindow_->global<Backend>().on_createTask([&](NewTaskData newTaskData) {
|
||||
const Date &date = newTaskData.date;
|
||||
const std::string dateStr = SlintDateToStdString(date);
|
||||
auto source = miraiInstance_->getSourceById(newTaskData.sourceId);
|
||||
|
@ -152,7 +160,7 @@ void UiState::setupEventWindowCallbacks()
|
|||
assert(source);
|
||||
auto event = source->getEventById(eventId);
|
||||
assert(event);
|
||||
eventWindow_->global<Backend>().set_sources(sources_);
|
||||
eventWindow_->global<Backend>().set_sources_selected(sources_);
|
||||
eventWindow_->global<Backend>().set_tags(tags_);
|
||||
|
||||
eventWindow_->set_sourceId(sourceId);
|
||||
|
@ -177,7 +185,7 @@ void UiState::setupEventWindowCallbacks()
|
|||
reloadTasks();
|
||||
});
|
||||
|
||||
eventWindow_->on_create([&](NewEventParams newEventParams) {
|
||||
mainWindow_->global<Backend>().on_createEvent([&](NewEventParams newEventParams) {
|
||||
const Date &date = newEventParams.date;
|
||||
const std::string dateStr = SlintDateToStdString(date);
|
||||
auto source = miraiInstance_->getSourceById(newEventParams.sourceId);
|
||||
|
@ -195,7 +203,7 @@ void UiState::setupEventWindowCallbacks()
|
|||
eventWindow_->hide();
|
||||
});
|
||||
|
||||
eventWindow_->on_save([&](SaveEventParams newEventParams) {
|
||||
mainWindow_->global<Backend>().on_saveEvent([&](SaveEventParams newEventParams) {
|
||||
const Date &date = newEventParams.date;
|
||||
const std::string dateStr = SlintDateToStdString(date);
|
||||
auto source = miraiInstance_->getSourceById(newEventParams.sourceId);
|
||||
|
@ -239,6 +247,16 @@ void UiState::setupCallbacks()
|
|||
});
|
||||
|
||||
mainWindow_->global<Backend>().on_source_clicked([&](int index) {
|
||||
// index with value -1 is equal to no selection, aka "All"
|
||||
if (index == -1) {
|
||||
view_.removeFilters();
|
||||
} else {
|
||||
view_.removeFilters();
|
||||
const auto &source = miraiInstance_->getSourceById(index);
|
||||
const auto &sourceName = source->getName();
|
||||
view_.addSourceFilter(sourceName);
|
||||
/*
|
||||
// Old behavior, I keep it here for now
|
||||
const auto &source = miraiInstance_->getSourceById(index);
|
||||
const auto &sourceName = source->getName();
|
||||
if (std::ranges::find(view_.getActiveFilesFilter(), sourceName) ==
|
||||
|
@ -247,7 +265,10 @@ void UiState::setupCallbacks()
|
|||
} else {
|
||||
view_.removeSourceFilter(sourceName);
|
||||
}
|
||||
*/
|
||||
}
|
||||
view_.update();
|
||||
reloadSources();
|
||||
reloadTasks();
|
||||
});
|
||||
|
||||
|
@ -294,7 +315,7 @@ void UiState::setupCallbacks()
|
|||
});
|
||||
|
||||
mainWindow_->global<Backend>().on_open_new_task_form([&](OpenNewTaskFormParams params) {
|
||||
taskWindow_->global<Backend>().set_sources(sources_);
|
||||
taskWindow_->global<Backend>().set_sources_selected(sources_);
|
||||
taskWindow_->global<Backend>().set_tags(tags_);
|
||||
|
||||
auto todayDate = std::chrono::year_month_day{
|
||||
|
@ -329,7 +350,7 @@ void UiState::setupCallbacks()
|
|||
reloadTasks();
|
||||
});
|
||||
|
||||
mainWindow_->global<Backend>().set_sources(sources_);
|
||||
mainWindow_->global<Backend>().set_sources_selected(sources_);
|
||||
mainWindow_->global<Backend>().set_tags(tags_);
|
||||
mainWindow_->global<Backend>().set_visible_tasks(days_);
|
||||
|
||||
|
@ -450,9 +471,17 @@ void UiState::reloadTasks()
|
|||
void UiState::reloadSources()
|
||||
{
|
||||
sources_->clear();
|
||||
bool noSourceSelected = true;
|
||||
for (const auto &source : miraiInstance_->getSources()) {
|
||||
sources_->push_back(slint::SharedString(source->getName()));
|
||||
bool isSourceSelected = view_.isSourceFilterActive(source->getName());
|
||||
sources_->push_back(
|
||||
{.name = slint::SharedString(source->getName()), .selected = isSourceSelected}
|
||||
);
|
||||
if (isSourceSelected) {
|
||||
noSourceSelected = false;
|
||||
}
|
||||
}
|
||||
mainWindow_->global<Backend>().set_no_source_selected(noSourceSelected);
|
||||
}
|
||||
|
||||
void UiState::reloadTags()
|
||||
|
|
|
@ -29,7 +29,7 @@ class UiState
|
|||
void setupEventWindowCallbacks();
|
||||
void setupUtilsCallbacks();
|
||||
|
||||
std::shared_ptr<slint::VectorModel<slint::SharedString>> sources_;
|
||||
std::shared_ptr<slint::VectorModel<Source>> sources_;
|
||||
std::shared_ptr<slint::VectorModel<slint::SharedString>> tags_;
|
||||
std::shared_ptr<slint::VectorModel<Day>> days_;
|
||||
std::shared_ptr<slint::VectorModel<TaskData>> unscheduledTasks_;
|
||||
|
|
|
@ -1,6 +1,42 @@
|
|||
import { Date, Time } from "std-widgets.slint";
|
||||
|
||||
export struct NewTaskData {
|
||||
sourceId: int,
|
||||
eventId: int,
|
||||
title: string,
|
||||
scheduled: bool,
|
||||
date: Date
|
||||
}
|
||||
|
||||
export struct SaveTaskData {
|
||||
sourceId: int,
|
||||
id: int,
|
||||
title: string,
|
||||
scheduled: bool,
|
||||
date: Date,
|
||||
}
|
||||
|
||||
export struct NewEventParams {
|
||||
sourceId: int,
|
||||
title: string,
|
||||
date: Date,
|
||||
startsAt: Time,
|
||||
endsAt: Time
|
||||
}
|
||||
|
||||
export struct SaveEventParams {
|
||||
sourceId: int,
|
||||
id: int,
|
||||
title: string,
|
||||
date: Date,
|
||||
startsAt: Time,
|
||||
endsAt: Time
|
||||
}
|
||||
|
||||
export struct Source {
|
||||
name: string,
|
||||
selected: bool
|
||||
}
|
||||
|
||||
export struct TaskData {
|
||||
sourceId: int,
|
||||
|
@ -36,7 +72,9 @@ struct OpenNewTaskFormParams {
|
|||
}
|
||||
|
||||
export global Backend {
|
||||
in-out property<[Source]> sources-selected;
|
||||
in-out property<[string]> sources;
|
||||
in-out property<bool> no-source-selected;
|
||||
in-out property<[string]> tags;
|
||||
in-out property<[Day]> visible_tasks;
|
||||
in-out property<[TaskData]> unscheduled-tasks;
|
||||
|
@ -53,5 +91,10 @@ export global Backend {
|
|||
callback delete_task_clicked(int, int);
|
||||
callback delete_event_clicked(int, int);
|
||||
|
||||
callback createTask(NewTaskData);
|
||||
callback saveTask(SaveTaskData);
|
||||
callback createEvent(NewEventParams);
|
||||
callback saveEvent(SaveEventParams);
|
||||
|
||||
pure callback formatDate(Date) -> string;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,8 @@ export component EventGroup {
|
|||
VText {
|
||||
text: Utils.timeToString(event.endsAt);
|
||||
color: Palette.accent;
|
||||
font-size: 0.8rem;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Backend, TaskData } from "Backend.slint";
|
||||
import { Button, VerticalBox, CheckBox, ScrollView } from "std-widgets.slint";
|
||||
import { Button, VerticalBox, CheckBox, ScrollView, ComboBox } from "std-widgets.slint";
|
||||
import { SideBar } from "SideBar.slint";
|
||||
import { TaskLine } from "TaskLine.slint";
|
||||
import { EventGroup } from "EventGroup.slint";
|
||||
import { VPopupIconMenu, VCheckBox, VButton, VTag, VText, Palette } from "@vynui";
|
||||
import { VPopupIconMenu, VDatePicker, VTimePicker, VCheckBox, VButton, VTag, VText, VTextInput, Palette } from "@vynui";
|
||||
import { NewTaskData, SaveTaskData } from "Backend.slint";
|
||||
|
||||
export component MainView inherits Rectangle {
|
||||
|
||||
|
@ -37,6 +38,7 @@ export component MainView inherits Rectangle {
|
|||
icon-source: @image-url("./images/add.png");
|
||||
icon-colorize: Colors.greenyellow;
|
||||
}
|
||||
|
||||
VButton {
|
||||
text: "New event";
|
||||
clicked => { Backend.open_new_event_form() }
|
||||
|
@ -58,6 +60,95 @@ export component MainView inherits Rectangle {
|
|||
background: Palette.background.brighter(0.2);
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
border-color: newTaskTitleInput.text != "" ? Palette.card-background : transparent;
|
||||
border-width: newTaskTitleInput.text != "" ? 4px : 0px;
|
||||
border-radius: newTaskTitleInput.text != "" ? 8px : 0px;
|
||||
animate border-color, border-width {
|
||||
duration: 500ms;
|
||||
}
|
||||
VerticalLayout {
|
||||
in-out property <int> task-or-event: 1;
|
||||
spacing: 8px;
|
||||
padding: newTaskTitleInput.text != "" ? 16px : 0px;
|
||||
animate padding {
|
||||
duration: 250ms;
|
||||
}
|
||||
Rectangle {
|
||||
min-height: 0px;
|
||||
max-height: newTaskTitleInput.text != "" ? 512px : 0px;
|
||||
opacity: newTaskTitleInput.text != "" ? 1 : 0;
|
||||
clip: true;
|
||||
animate max-height, opacity {
|
||||
duration: 500ms;
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: start;
|
||||
spacing: 8px;
|
||||
VerticalLayout {
|
||||
alignment: end;
|
||||
VButton {
|
||||
text: task-or-event == 1 ? "Task" : "Event";
|
||||
clicked => { task-or-event = task-or-event == 1 ? 0 : 1 }
|
||||
}
|
||||
}
|
||||
VText { text: "for"; vertical-alignment: bottom;}
|
||||
VerticalLayout {
|
||||
alignment: end;
|
||||
sourceInput := ComboBox {
|
||||
model: Backend.sources;
|
||||
}
|
||||
}
|
||||
VText { text: "on"; vertical-alignment: bottom;}
|
||||
taskDateInput := VDatePicker {
|
||||
label: "Date";
|
||||
enabled: true;
|
||||
}
|
||||
HorizontalLayout {
|
||||
visible: task-or-event == 0;
|
||||
HorizontalLayout {
|
||||
spacing: 4px;
|
||||
VText { text: "between"; vertical-alignment: bottom; }
|
||||
eventStartTimeInput := VTimePicker {
|
||||
label: "Starts at";
|
||||
}
|
||||
VText { text: "and"; vertical-alignment: bottom; }
|
||||
eventEndTimeInput := VTimePicker {
|
||||
label: "Ends at";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
newTaskTitleInput := VTextInput {
|
||||
placeholder: "Add task";
|
||||
accepted => {
|
||||
if (task-or-event == 1) {
|
||||
Backend.createTask({
|
||||
sourceId: sourceInput.current-index,
|
||||
eventId: -1,
|
||||
title: newTaskTitleInput.text,
|
||||
scheduled: taskDateInput.date.year != 0,
|
||||
date: taskDateInput.date
|
||||
})
|
||||
} else {
|
||||
Backend.createEvent({
|
||||
sourceId: sourceInput.current-index,
|
||||
title: newTaskTitleInput.text,
|
||||
date: taskDateInput.date,
|
||||
startsAt: eventStartTimeInput.time,
|
||||
endsAt: eventEndTimeInput.time,
|
||||
});
|
||||
}
|
||||
newTaskTitleInput.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
horizontal-stretch: 1;
|
||||
VerticalLayout {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { ToggleButton, VText, Palette } from "@vynui";
|
|||
|
||||
export component SideBar inherits Rectangle {
|
||||
background: Palette.pane;
|
||||
|
||||
VerticalLayout {
|
||||
alignment: start;
|
||||
padding: 16px;
|
||||
|
@ -13,9 +14,16 @@ export component SideBar inherits Rectangle {
|
|||
}
|
||||
VerticalLayout {
|
||||
spacing: 4px;
|
||||
for item[index] in Backend.sources: ToggleButton {
|
||||
text: item;
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Date, Time, ComboBox } from "std-widgets.slint";
|
|||
import { VTimePicker, VDatePicker, VButton, VTextInput, VText, Palette } from "@vynui";
|
||||
import { Backend } from "../Backend.slint";
|
||||
|
||||
export struct NewEventParams {
|
||||
struct NewEventParams {
|
||||
sourceId: int,
|
||||
title: string,
|
||||
date: Date,
|
||||
|
@ -10,7 +10,7 @@ export struct NewEventParams {
|
|||
endsAt: Time
|
||||
}
|
||||
|
||||
export struct SaveEventParams {
|
||||
struct SaveEventParams {
|
||||
sourceId: int,
|
||||
id: int,
|
||||
title: string,
|
||||
|
@ -51,15 +51,15 @@ export component EventWindow inherits Window {
|
|||
enabled: eventId == -1;
|
||||
}
|
||||
|
||||
taskDateInput := VDatePicker {
|
||||
label: "Date";
|
||||
}
|
||||
|
||||
taskTitleInput := VTextInput {
|
||||
label: "Title";
|
||||
wrap: word-wrap;
|
||||
}
|
||||
|
||||
taskDateInput := VDatePicker {
|
||||
label: "Date";
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: 4px;
|
||||
eventStartTimeInput := VTimePicker {
|
||||
|
@ -71,7 +71,6 @@ export component EventWindow inherits Window {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
VButton {
|
||||
text: eventId == -1 ? "Create" : "Save";
|
||||
clicked => {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Date, ComboBox } from "std-widgets.slint";
|
|||
import { VTextInput, VButton, VDatePicker, VText, VCheckBox, Palette } from "@vynui";
|
||||
import { Backend } from "../Backend.slint";
|
||||
|
||||
export struct NewTaskData {
|
||||
struct NewTaskData {
|
||||
sourceId: int,
|
||||
eventId: int,
|
||||
title: string,
|
||||
|
@ -10,7 +10,7 @@ export struct NewTaskData {
|
|||
date: Date
|
||||
}
|
||||
|
||||
export struct SaveTaskData {
|
||||
struct SaveTaskData {
|
||||
sourceId: int,
|
||||
id: int,
|
||||
title: string,
|
||||
|
@ -50,12 +50,6 @@ export component TaskWindow inherits Window {
|
|||
enabled: taskId == -1 && eventId == -1;
|
||||
}
|
||||
|
||||
taskTitleInput := VTextInput {
|
||||
label: "Content";
|
||||
wrap: word-wrap;
|
||||
accepted => { button.clicked() }
|
||||
}
|
||||
|
||||
scheduledInput := VCheckBox {
|
||||
text: "Scheduled";
|
||||
}
|
||||
|
@ -65,6 +59,12 @@ export component TaskWindow inherits Window {
|
|||
enabled: eventId == -1 && scheduledInput.checked;
|
||||
}
|
||||
|
||||
taskTitleInput := VTextInput {
|
||||
label: "Content";
|
||||
wrap: word-wrap;
|
||||
accepted => { button.clicked() }
|
||||
}
|
||||
|
||||
button := VButton {
|
||||
text: taskId == -1 ? "Create" : "Save";
|
||||
clicked => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue