first commit

This commit is contained in:
Vyn 2024-04-10 16:53:18 +02:00
commit 3e7d8b4b70
43 changed files with 2681 additions and 0 deletions

51
src/qml/AppButton.qml Normal file
View file

@ -0,0 +1,51 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Mirai
Button {
id: control
icon.color: MiraiColorPalette.buttonIcon
property bool noBackgroundColor: false
contentItem: RowLayout {
spacing: control.icon.source != "" ? 4 : 0
Component {
id: buttonIcon
AppIcon {
icon.source: control.icon.source
icon.color: control?.icon?.color
}
}
Loader {
sourceComponent: control.icon.source != "" ? buttonIcon : undefined
}
Text {
text: control.text
color: MiraiColorPalette.text
leftPadding: 8
rightPadding: 8
}
}
background: Rectangle {
color: control.noBackgroundColor ? "transparent"
: mouse.hovered ? colorPalette.selected.buttonHovered
: colorPalette.selected.buttonBackground
radius: 4
}
HoverHandler {
id: mouse
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
cursorShape: Qt.PointingHandCursor
}
}

41
src/qml/AppCheckbox.qml Normal file
View file

@ -0,0 +1,41 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Controls
import Mirai
CheckBox {
id: control
property alias textComponent: text
contentItem: Text {
id: text
text: control.text
color: MiraiColorPalette.text
verticalAlignment: Text.AlignVCenter
leftPadding: control.indicator.width + control.spacing
}
indicator: Rectangle {
x: control.leftPadding
y: control.topPadding + (control.availableHeight - height) / 2
implicitWidth: 12
implicitHeight: 12
radius: 999
color: control.checked ? colorPalette.selected.palette.green : colorPalette.selected.text
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
implicitWidth: 10
implicitHeight: 10
radius: 999
color: control.checked ? colorPalette.selected.palette.green : colorPalette.selected.fieldBackground
}
}
}

15
src/qml/AppIcon.qml Normal file
View file

@ -0,0 +1,15 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Controls
import Mirai
Button {
icon.color: MiraiColorPalette.buttonIcon
background: Rectangle { color: "transparent" }
}

22
src/qml/AppLineEdit.qml Normal file
View file

@ -0,0 +1,22 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import Mirai
TextField {
color: MiraiColorPalette.text
placeholderTextColor: MiraiColorPalette.textPlaceholder
leftPadding: 10
implicitHeight: 32
background: Rectangle {
color: MiraiColorPalette.fieldBackground
radius: 4
}
}

13
src/qml/AppText.qml Normal file
View file

@ -0,0 +1,13 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Controls
import Mirai
Text {
color: MiraiColorPalette.text
}

77
src/qml/DateField.qml Normal file
View file

@ -0,0 +1,77 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import Mirai
Rectangle {
id: datePickerRoot
property alias text: newTodoDate.text
property alias textFieldComponent: newTodoDate
color: MiraiColorPalette.fieldBackground
radius: 4
implicitHeight: 32
RowLayout {
anchors.fill: parent
AppIcon {
icon.source: "qrc:/qt/qml/Mirai/src/images/calendar.png"
Layout.preferredWidth: 32
Layout.preferredHeight: 32
}
AppLineEdit {
id: newTodoDate
Layout.fillWidth: true
Layout.fillHeight: true
readOnly: true
background: Rectangle {
color: "transparent"
}
MouseArea {
anchors.fill: parent
onClicked: {
datePicker.open()
}
}
}
Popup {
id: datePicker
implicitWidth: 300
implicitHeight: 300
x: datePickerRoot.x
y: datePickerRoot.y - 300 - 10
background: Rectangle {
color: colorPalette.selected.pane
border.color: colorPalette.selected.modalBorder
border.width: 2
}
DatePicker {
anchors.fill: parent
Component.onCompleted: set(new Date()) // today
onClicked: {
const formattedDate = Qt.formatDate(date, 'yyyy-MM-dd')
print('onClicked', formattedDate)
newTodoDate.text = formattedDate
datePicker.close()
}
onReset: {
newTodoDate.text = ""
datePicker.close()
}
}
}
}
}

124
src/qml/DatePicker.qml Normal file
View file

@ -0,0 +1,124 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import Mirai
import QtQuick
ListView {
id: root
function set(date) {
selectedDate = new Date(date)
positionViewAtIndex((selectedDate.getFullYear()) * 12 + selectedDate.getMonth(), ListView.Center) // index from month year
}
signal clicked(date date);
signal reset();
property date selectedDate: new Date()
width: 500
height: 100
snapMode: ListView.SnapOneItem
orientation: Qt.Horizontal
clip: true
model: 3000 * 12 // index == months since January of the year 0
delegate: Item {
property int year: Math.floor(index / 12)
property int month: index % 12 // 0 January
property int firstDay: new Date(year, month, 1).getDay() // 0 Sunday to 6 Saturday
width: root.width
height: root.height
Column {
Item { // month year header
width: root.width
height: root.height - grid.height
AppText { // month year
anchors.centerIn: parent
text: ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'][month] + ' ' + year
font {pixelSize: 0.5 * grid.cellHeight}
}
AppButton {
text: "Remove"
onClicked: {
root.reset()
}
}
}
Grid { // 1 month calender
id: grid
width: root.width
height: 0.875 * root.height
property real cellWidth: width / columns;
property real cellHeight: height / rows // width and height of each cell in the grid.
columns: 7 // days
rows: 7
Repeater {
model: grid.columns * grid.rows // 49 cells per month
delegate: Rectangle { // index is 0 to 48
property int day: index - 7 // 0 = top left below Sunday (-7 to 41)
property int date: day - firstDay + 2 // 1-31
color: internal.selected ? colorPalette.selected.filterSelected
: mouseArea.containsMouse ? colorPalette.selected.filterHovered
: "transparent"
width: grid.cellWidth; height: grid.cellHeight
radius: 0.02 * root.height
opacity: !mouseArea.pressed? 1: 0.3
QtObject {
id: internal
property bool selected: new Date(year, month, date).toDateString() == selectedDate.toDateString() && text.text && day >= 0
}
AppText {
id: text
anchors.centerIn: parent
font.pixelSize: 0.5 * parent.height
font.bold: new Date(year, month, date).toDateString() == new Date().toDateString() // today
text: {
if(day < 0)
['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][index] // Su-Sa
else if(new Date(year, month, date).getMonth() == month)
date // 1-31
else
''
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
enabled: text.text && day >= 0
hoverEnabled: true
onClicked: {
selectedDate = new Date(year, month, date)
root.clicked(selectedDate)
}
}
}
}
}
}
}
// Component.onCompleted: set(new Date()) // today (otherwise Jan 0000)
}

145
src/qml/Main.qml Normal file
View file

@ -0,0 +1,145 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import Mirai
Window {
id: root
width: 640
height: 480
visible: true
title: qsTr("Hello World")
property string selectedView: "list"
Backend {
id: backend
}
Item {
id: colorPalette
property QtObject selected: MiraiColorPalette
}
function newTask() {
taskForm.taskToEdit = undefined
taskForm.taskToEditIndex = -1
taskFormPopup.open()
}
function editTask(task, taskIndex) {
taskForm.taskToEdit = task
taskForm.taskToEditIndex = taskIndex
taskFormPopup.open()
}
RowLayout {
anchors.fill: parent
spacing: 0
Rectangle {
color: MiraiColorPalette.pane
Layout.preferredWidth: childrenRect.width + 20
Layout.fillHeight: true
SideMenu {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 10
}
}
Rectangle {
color: colorPalette.selected.background
Layout.fillWidth: true
Layout.fillHeight: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 16
TabSelector {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
tabs: [
{
label: "List",
onClick: () => { root.selectedView = "list" },
selected: root.selectedView === "list"
},
{
label: "Calendar",
onClick: () => { root.selectedView = "calendar" },
selected: root.selectedView === "calendar"
}
]
}
AppButton {
icon.source: "qrc:/qt/qml/Mirai/src/images/add.png"
icon.color: colorPalette.selected.palette.green
text: "Add task"
onClicked: {
root.newTask()
}
}
Component {
id: listViewComponent
ListView {
}
}
Component {
id: calendarViewComponent
CalendarView {
}
}
Loader {
sourceComponent: selectedView === "list" ? listViewComponent
: selectedView === "calendar" ? calendarViewComponent
: undefined
Layout.fillWidth: true
Layout.fillHeight: true
}
Popup {
id: taskFormPopup
width: parent.width * 0.75
implicitHeight: taskForm.height + padding * 2
x: Math.round((parent.width - width) / 2)
y: Math.round((parent.height * 0.4) / 2)
padding: 8
background: Rectangle {
border.color: colorPalette.selected.modalBorder
border.width: 2
color: colorPalette.selected.pane
radius: 4
}
TaskForm {
id: taskForm
width: parent.width
onConfirmed: {
taskFormPopup.close()
}
}
}
}
}
}
}

61
src/qml/SideMenu.qml Normal file
View file

@ -0,0 +1,61 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import Mirai
ColumnLayout {
AppText {
text: "Tags"
font.pixelSize: 32
}
Item { Layout.preferredHeight: 16 }
Repeater {
model: backend.tags
Rectangle {
Layout.preferredHeight: childrenRect.height
Layout.fillWidth: true
color: backend.activeTagsFilter.includes(modelData) ? MiraiColorPalette.filterSelected : mouse.hovered ? MiraiColorPalette.filterHovered : "transparent"
radius: 4
AppText {
text: modelData
padding: 4
}
MouseArea {
anchors.fill: parent
onClicked: {
if (backend.activeTagsFilter.includes(modelData)) {
backend.removeTagFilter(modelData)
} else {
backend.addTagFilter(modelData)
}
}
HoverHandler {
id: mouse
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
cursorShape: Qt.PointingHandCursor
}
}
}
}
Item {
Layout.fillHeight: true
}
AppButton {
text: `Hide completed tasks: ${backend.shouldHideCompletedTasks ? "ON" : "OFF"}`
onClicked: {
backend.hideCompletedTasks(!backend.shouldHideCompletedTasks)
}
}
}

27
src/qml/TaskItem.qml Normal file
View file

@ -0,0 +1,27 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import QtQuick.Controls
import Mirai
RowLayout {
property taskItem task
AppCheckbox {
id: checkbox
text: task.text
checked: task.state === 'DONE'
textComponent.color: task.date < internal.todayDate ? colorPalette.selected.palette.pink
// : task.date === internal.todayDate ? colorPalette.selected.palette.sapphire
: colorPalette.selected.text
onClicked: {
backend.updateTodo(index, modelData.state === 'DONE' ? "TODO" : "DONE", modelData.text, modelData.date)
}
}
}

View file

@ -0,0 +1,58 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import Mirai
RowLayout {
id: control
property var tabs: []
Repeater {
model: tabs
Item {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
AppText {
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
id: tabText
text: modelData.label
font.pointSize: 24
}
Rectangle {
Layout.fillWidth: true
color: modelData.selected ? "white" : mouse.hovered ? MiraiColorPalette.filterHovered : "transparent"
implicitHeight: 2
}
}
MouseArea {
anchors.fill: parent
onClicked: {
modelData?.onClick()
}
HoverHandler {
id: mouse
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
cursorShape: Qt.PointingHandCursor
}
}
}
}
}

View file

@ -0,0 +1,55 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import Mirai
ColumnLayout {
id: form
property var taskToEdit
property int taskToEditIndex
spacing: 6
signal confirmed
onTaskToEditChanged: {
newTodoContent.text = taskToEdit?.text ?? ""
newTodoDate.text = taskToEdit?.date ?? ""
}
AppText {
text: "New task"
}
AppLineEdit {
id: newTodoContent
Layout.fillWidth: true
placeholderText: "Enter your new task..."
text: taskToEdit?.text ?? ""
Keys.onReturnPressed: {
if (newTodoContent.text == "") {
return
}
if (taskToEdit && taskToEditIndex !== undefined) {
backend.updateTodo(taskToEditIndex, taskToEdit.state, newTodoContent.text, newTodoDate.text)
} else {
backend.addTodo(newTodoContent.text, newTodoDate.text)
}
form.confirmed()
}
}
DateField {
id: newTodoDate
text: taskToEdit?.date ?? ""
textFieldComponent.placeholderText: "No date"
Layout.fillWidth: true
}
}

View file

@ -0,0 +1,38 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
pragma Singleton
import QtQuick 2.5
// Catppuccin Frappe theme (https://github.com/catppuccin/catppuccin)
QtObject {
property string rosewater: "#f2d5cf"
property string flamingo: "#eebebe"
property string pink: "#f4b8e4"
property string mauve: "#ca9ee6"
property string red: "#e78284"
property string maroon: "#ea999c"
property string peach: "#ef9f76"
property string yellow: "#e5c890"
property string green: "#a6d189"
property string teal: "#81c8be"
property string sky: "#99d1db"
property string sapphire: "#85c1dc"
property string blue: "#8caaee"
property string lavender: "#babbf1"
property string text: "#c6d0f5"
property string subtext1: "#b5bfe2"
property string subtext0: "#a5adce"
property string overlay2: "#949cbb"
property string overlay1: "#838ba7"
property string overlay0: "#737994"
property string surface2: "#626880"
property string surface1: "#51576d"
property string surface0: "#414559"
property string base: "#303446"
property string mantle: "#292c3c"
property string crust: "#232634"
}

View file

@ -0,0 +1,24 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
pragma Singleton
import QtQuick 2.5
import Mirai
QtObject {
property QtObject palette: CatppuccinFrappe
property string background: CatppuccinFrappe.base
property string pane: CatppuccinFrappe.mantle
property string text: CatppuccinFrappe.text
property string textPlaceholder: CatppuccinFrappe.overlay1
property string fieldBackground: CatppuccinFrappe.surface0
property string buttonIcon: CatppuccinFrappe.sapphire
property string buttonBackground: CatppuccinFrappe.surface0
property string buttonHovered: CatppuccinFrappe.surface1
property string filterHovered: CatppuccinFrappe.surface0
property string filterSelected: CatppuccinFrappe.surface1
property string modalBorder: CatppuccinFrappe.lavender
}

View file

@ -0,0 +1,17 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import Mirai
ColumnLayout {
AppText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
text: "Not implemented yet :)"
}
}

View file

@ -0,0 +1,98 @@
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import Mirai
ColumnLayout {
QtObject {
id: internal
property string todayDate: Qt.formatDate(new Date(), 'yyyy-MM-dd')
property string tomorrowDate: Qt.formatDate(new Date(new Date().setDate(new Date().getDate() + 1)), 'yyyy-MM-dd')
}
Repeater {
model: backend.tasks
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
id: task
required property var modelData
required property int index
color: "transparent"
HoverHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
cursorShape: Qt.PointingHandCursor
}
ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
Component {
id: dateForTasks
AppText {
topPadding: 32
bottomPadding: 16
text: task.modelData.date === internal.todayDate ? "Today"
: task.modelData.date === internal.tomorrowDate ? "Tomorrow"
: task.modelData.date
color: task.modelData.date < internal.todayDate ? colorPalette.selected.palette.pink
// : task.modelData.date === internal.todayDate ? colorPalette.selected.palette.sapphire
: colorPalette.selected.text
font.pointSize: 24
}
}
Loader {
sourceComponent: task.modelData.shouldShowDate ? dateForTasks : undefined
}
TaskItem {
id: taskItem
task: task.modelData
}
}
Menu {
id: contextMenu
MenuItem {
text: "Edit"
onClicked: {
root.editTask(task.modelData, task.index)
}
}
MenuItem {
text: "Delete"
onClicked: {
backend.removeTodo(task.index)
}
}
}
MouseArea {
id: mouse
anchors.fill: parent
acceptedButtons: Qt.RightButton
propagateComposedEvents: true
onClicked: {
contextMenu.popup()
}
}
}
}
Item {
Layout.fillHeight: true
}
}