Files
dotfiles/noctalia/plugins/clipper/NoteCardsPanel.qml
T
Domipoke 955801c666 noctalia
2026-06-25 19:58:23 +02:00

221 lines
6.9 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
import qs.Services.UI
import qs.Widgets
Item {
id: root
property var pluginApi: null
property var screen: null
// Function to sync all notecard changes before saving
function syncAllChanges() {
for (let i = 0; i < noteCardsRepeater.count; i++) {
const card = noteCardsRepeater.itemAt(i);
if (card && card.syncChanges) {
card.syncChanges();
}
}
}
// Background MouseArea - ALWAYS closes panel on click
MouseArea {
anchors.fill: parent
z: -1
onClicked: {
const closeButtonOn = root.pluginApi?.pluginSettings?.showCloseButton ?? false;
if (!closeButtonOn && root.pluginApi && root.screen) {
root.pluginApi.closePanel(root.screen);
}
}
}
// Empty state UI (shown when no notes)
Item {
anchors.centerIn: parent
width: 400
height: 200
visible: !(root.pluginApi && root.pluginApi.mainInstance && root.pluginApi.mainInstance.noteCards) || root.pluginApi.mainInstance.noteCards.length === 0
ColumnLayout {
anchors.centerIn: parent
spacing: 16
NIcon {
Layout.alignment: Qt.AlignHCenter
icon: "notes"
pointSize: 64
color: Color.mOnSurfaceVariant
opacity: 0.5
}
NText {
Layout.alignment: Qt.AlignHCenter
text: pluginApi?.tr("notecards.empty-state")
font.pointSize: Style.fontSizeL
font.bold: true
color: Color.mOnSurfaceVariant
}
NText {
Layout.alignment: Qt.AlignHCenter
text: pluginApi?.tr("notecards.empty-hint")
font.pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
opacity: 0.7
}
NButton {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 16
text: pluginApi?.tr("notecards.create-note")
icon: "add"
onClicked: {
if (root.pluginApi && root.pluginApi.mainInstance) {
root.pluginApi.mainInstance.createNoteCard("");
}
}
}
}
}
// Use ListModel to avoid binding loop
ListModel {
id: noteCardsModel
}
property int lastRevision: -1
// Manual update function
function updateNoteCardsModel() {
noteCardsModel.clear();
if (root.pluginApi && root.pluginApi.mainInstance) {
const notes = root.pluginApi.mainInstance.noteCards || [];
for (let i = 0; i < notes.length; i++) {
noteCardsModel.append({
"noteData": notes[i],
"noteIdx": i
});
}
lastRevision = root.pluginApi.mainInstance.noteCardsRevision || 0;
}
}
// Timer to check for changes
Timer {
id: revisionTimer
interval: 200
running: root.visible
repeat: true
onTriggered: {
if (root.pluginApi && root.pluginApi.mainInstance) {
const currentRevision = root.pluginApi.mainInstance.noteCardsRevision || 0;
if (currentRevision !== root.lastRevision) {
root.updateNoteCardsModel();
}
}
}
}
Component.onCompleted: {
updateNoteCardsModel();
}
// Repeater for note cards
Repeater {
id: noteCardsRepeater
model: noteCardsModel
NoteCard {
pluginApi: root.pluginApi
note: noteData
noteIndex: noteIdx
z: 1 // Above background MouseArea
}
}
Rectangle {
anchors.left: parent.left
anchors.top: parent.top
anchors.margins: 16
width: contentRow.width + 16
height: 40
color: Color.mSurfaceVariant
border.color: Color.mOnSurfaceVariant
border.width: 1
radius: Style.radiusM
visible: (root.pluginApi && root.pluginApi.mainInstance && root.pluginApi.mainInstance.noteCards) ? root.pluginApi.mainInstance.noteCards.length > 0 : false
z: 2 // Above everything
RowLayout {
id: contentRow
anchors.centerIn: parent
spacing: 8
// Add note button
NIconButton {
width: 28
height: 28
icon: "add"
tooltipText: pluginApi?.tr("notecards.create-note")
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
colorBgHover: Qt.lighter(Color.mPrimary, 1.2)
colorFgHover: Color.mOnPrimary
onClicked: {
if (root.pluginApi && root.pluginApi.mainInstance) {
const count = root.pluginApi.mainInstance.noteCards ? root.pluginApi.mainInstance.noteCards.length : 0;
const max = root.pluginApi.mainInstance.maxNoteCards || 20;
if (count >= max) {
ToastService.showWarning(pluginApi?.tr("toast.max-notes").replace("{max}", max));
} else {
root.pluginApi.mainInstance.createNoteCard("");
}
}
}
}
// Vertical separator
Rectangle {
width: 1
height: 24
color: Color.mOnSurfaceVariant
opacity: 0.3
}
// Note icon
NIcon {
icon: "note"
pointSize: 16
color: Color.mOnSurfaceVariant
}
// Count text
NText {
text: {
const count = (root.pluginApi && root.pluginApi.mainInstance && root.pluginApi.mainInstance.noteCards) ? root.pluginApi.mainInstance.noteCards.length : 0;
const max = (root.pluginApi && root.pluginApi.mainInstance) ? (root.pluginApi.mainInstance.maxNoteCards || 20) : 20;
return count + " / " + max;
}
font.pointSize: Style.fontSizeM
font.bold: true
color: {
const count = (root.pluginApi && root.pluginApi.mainInstance && root.pluginApi.mainInstance.noteCards) ? root.pluginApi.mainInstance.noteCards.length : 0;
const max = (root.pluginApi && root.pluginApi.mainInstance) ? (root.pluginApi.mainInstance.maxNoteCards || 20) : 20;
return count >= max ? Color.mError : Color.mOnSurfaceVariant;
}
}
}
}
Component.onDestruction: {
revisionTimer.stop();
noteCardsModel.clear();
}
}