fix: backend bash wrapper executing python3 directly and GroupCard component
This commit is contained in:
+13
-20
@@ -1,21 +1,14 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env bash
|
||||||
"""Backend per il plasmoide KDE Plasma 6: Antigravity Usage Dashboard.
|
# Backend per il plasmoide KDE Plasma 6: Antigravity Usage Dashboard.
|
||||||
|
# Esegue il client Python incorporato per recuperare le quote da Google CloudCode PA.
|
||||||
|
|
||||||
Interroga il gateway Google CloudCode PA (https://daily-cloudcode-pa.googleapis.com)
|
exec /usr/bin/python3 - "$@" << 'EOF'
|
||||||
leggendo il token OAuth da ~/.gemini/antigravity-cli/antigravity-oauth-token
|
|
||||||
ed eseguendo il refresh automatico se scaduto o non valido.
|
|
||||||
Restituisce lo stato delle quote per le 3 famiglie di modelli:
|
|
||||||
- Gemini (Gemini 3.x Flash / Pro)
|
|
||||||
- Claude (Claude Sonnet 4.6 / Opus 4.6)
|
|
||||||
- GPT-OSS (GPT-OSS 120B)
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import json
|
||||||
import time
|
import time
|
||||||
import urllib.error
|
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
TOKEN_FILE = os.path.expanduser("~/.gemini/antigravity-cli/antigravity-oauth-token")
|
TOKEN_FILE = os.path.expanduser("~/.gemini/antigravity-cli/antigravity-oauth-token")
|
||||||
@@ -27,7 +20,6 @@ UA = "antigravity/cli/1.1.17"
|
|||||||
API_CLIENT = "google-cloud-sdk vscode_cloudshelleditor/0.1"
|
API_CLIENT = "google-cloud-sdk vscode_cloudshelleditor/0.1"
|
||||||
METADATA = json.dumps({"ideType": "ANTIGRAVITY", "platform": "LINUX", "pluginType": "GEMINI"})
|
METADATA = json.dumps({"ideType": "ANTIGRAVITY", "platform": "LINUX", "pluginType": "GEMINI"})
|
||||||
|
|
||||||
|
|
||||||
def get_token_data():
|
def get_token_data():
|
||||||
if not os.path.exists(TOKEN_FILE):
|
if not os.path.exists(TOKEN_FILE):
|
||||||
return None
|
return None
|
||||||
@@ -37,7 +29,6 @@ def get_token_data():
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def save_token_data(data):
|
def save_token_data(data):
|
||||||
try:
|
try:
|
||||||
tmp = TOKEN_FILE + ".tmp"
|
tmp = TOKEN_FILE + ".tmp"
|
||||||
@@ -47,7 +38,6 @@ def save_token_data(data):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def refresh_token(refresh_tok):
|
def refresh_token(refresh_tok):
|
||||||
req_body = json.dumps({
|
req_body = json.dumps({
|
||||||
"client_id": CLIENT_ID,
|
"client_id": CLIENT_ID,
|
||||||
@@ -60,7 +50,6 @@ def refresh_token(refresh_tok):
|
|||||||
res = json.loads(resp.read().decode("utf-8"))
|
res = json.loads(resp.read().decode("utf-8"))
|
||||||
return res.get("access_token"), int(res.get("expires_in", 3600))
|
return res.get("access_token"), int(res.get("expires_in", 3600))
|
||||||
|
|
||||||
|
|
||||||
def call_api(path, token, payload):
|
def call_api(path, token, payload):
|
||||||
url = f"{BASE_URL}{path}"
|
url = f"{BASE_URL}{path}"
|
||||||
headers = {
|
headers = {
|
||||||
@@ -75,7 +64,6 @@ def call_api(path, token, payload):
|
|||||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||||
return json.loads(resp.read().decode("utf-8"))
|
return json.loads(resp.read().decode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
def parse_iso_epoch(ts):
|
def parse_iso_epoch(ts):
|
||||||
if not ts:
|
if not ts:
|
||||||
return 0
|
return 0
|
||||||
@@ -85,7 +73,6 @@ def parse_iso_epoch(ts):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
data = get_token_data()
|
data = get_token_data()
|
||||||
if not data or "token" not in data:
|
if not data or "token" not in data:
|
||||||
@@ -144,6 +131,7 @@ def main():
|
|||||||
gem_reset_str = gem_b.get("resetTime", "")
|
gem_reset_str = gem_b.get("resetTime", "")
|
||||||
gemini_info = {
|
gemini_info = {
|
||||||
"id": "gemini",
|
"id": "gemini",
|
||||||
|
"tag": "GEMINI",
|
||||||
"name": "Gemini 3.x",
|
"name": "Gemini 3.x",
|
||||||
"models": "Pro / Flash",
|
"models": "Pro / Flash",
|
||||||
"remaining": round(gem_rem, 4),
|
"remaining": round(gem_rem, 4),
|
||||||
@@ -159,6 +147,7 @@ def main():
|
|||||||
cld_reset_str = cld_b.get("resetTime", "")
|
cld_reset_str = cld_b.get("resetTime", "")
|
||||||
claude_info = {
|
claude_info = {
|
||||||
"id": "claude",
|
"id": "claude",
|
||||||
|
"tag": "CLAUDE",
|
||||||
"name": "Claude 4.6",
|
"name": "Claude 4.6",
|
||||||
"models": "Sonnet / Opus",
|
"models": "Sonnet / Opus",
|
||||||
"remaining": round(cld_rem, 4),
|
"remaining": round(cld_rem, 4),
|
||||||
@@ -173,6 +162,7 @@ def main():
|
|||||||
gpt_reset_str = gpt_b.get("resetTime", "")
|
gpt_reset_str = gpt_b.get("resetTime", "")
|
||||||
gpt_info = {
|
gpt_info = {
|
||||||
"id": "gpt-oss",
|
"id": "gpt-oss",
|
||||||
|
"tag": "GPT",
|
||||||
"name": "GPT-OSS",
|
"name": "GPT-OSS",
|
||||||
"models": "120B Medium",
|
"models": "120B Medium",
|
||||||
"remaining": round(gpt_rem, 4),
|
"remaining": round(gpt_rem, 4),
|
||||||
@@ -184,10 +174,13 @@ def main():
|
|||||||
out = {
|
out = {
|
||||||
"ok": True,
|
"ok": True,
|
||||||
"project": project_id,
|
"project": project_id,
|
||||||
|
"gemini": gemini_info,
|
||||||
|
"claude": claude_info,
|
||||||
|
"gpt": gpt_info,
|
||||||
"groups": [gemini_info, claude_info, gpt_info]
|
"groups": [gemini_info, claude_info, gpt_info]
|
||||||
}
|
}
|
||||||
print(json.dumps(out, indent=2))
|
print(json.dumps(out, indent=2))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
EOF
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/* Card per gruppo di modelli Antigravity (Gemini, Claude, GPT-OSS) */
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import org.kde.plasma.components 3.0 as PC3
|
||||||
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string tag: ""
|
||||||
|
property string title: ""
|
||||||
|
property string models: ""
|
||||||
|
property real remaining: 1.0
|
||||||
|
property real usedPercent: 0.0
|
||||||
|
property int resetAt: 0
|
||||||
|
property int clockTick: 0
|
||||||
|
property color accentColor: "#818cf8"
|
||||||
|
|
||||||
|
function countdown() {
|
||||||
|
const tick = root.clockTick
|
||||||
|
if (!resetAt || resetAt <= 0) return "—"
|
||||||
|
let mins = Math.max(0, Math.floor((resetAt * 1000 - Date.now()) / 60000))
|
||||||
|
if (mins === 0) return i18n("ora")
|
||||||
|
const days = Math.floor(mins / 1440)
|
||||||
|
mins -= days * 1440
|
||||||
|
const hours = Math.floor(mins / 60)
|
||||||
|
mins -= hours * 60
|
||||||
|
return days > 0 ? i18n("%1g %2h", days, hours) : i18n("%1h %2m", hours, mins)
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 46
|
||||||
|
radius: 5
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.28)
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.accentColor
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 4
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
// Riga 1: Tag + Titolo + Modelli + % Residuo
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.preferredWidth: 38
|
||||||
|
Layout.preferredHeight: 14
|
||||||
|
radius: 7
|
||||||
|
color: root.accentColor
|
||||||
|
PC3.Label {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: root.tag
|
||||||
|
color: "#101012"
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PC3.Label {
|
||||||
|
text: root.title
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PC3.Label {
|
||||||
|
text: "· " + root.models
|
||||||
|
color: Kirigami.Theme.disabledTextColor
|
||||||
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 3
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
PC3.Label {
|
||||||
|
text: Math.round(root.remaining * 100) + "%"
|
||||||
|
color: root.accentColor
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Riga 2: Barra di avanzamento
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 5
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: track
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 2.5
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: track.width * Math.max(0, Math.min(1, root.remaining))
|
||||||
|
height: parent.height
|
||||||
|
radius: 2.5
|
||||||
|
color: root.accentColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Riga 3: Dettaglio usato + Reset countdown
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
PC3.Label {
|
||||||
|
text: i18n("%1% usato", root.usedPercent.toFixed(1))
|
||||||
|
color: Kirigami.Theme.disabledTextColor
|
||||||
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 3
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
PC3.Label {
|
||||||
|
text: i18n("⏱ %1", root.countdown())
|
||||||
|
color: root.accentColor
|
||||||
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
-106
@@ -11,7 +11,7 @@ import org.kde.kirigami as Kirigami
|
|||||||
PlasmoidItem {
|
PlasmoidItem {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var data: null // { ok, project, groups: [ { id, name, models, remaining, used_percent, reset_time, reset_at } ] }
|
property var data: null
|
||||||
property string lastUpdate: ""
|
property string lastUpdate: ""
|
||||||
property string errorMsg: ""
|
property string errorMsg: ""
|
||||||
property bool loading: false
|
property bool loading: false
|
||||||
@@ -30,10 +30,10 @@ PlasmoidItem {
|
|||||||
Plasmoid.icon: "compass"
|
Plasmoid.icon: "compass"
|
||||||
Plasmoid.backgroundHints: PlasmaCore.Types.DefaultBackground
|
Plasmoid.backgroundHints: PlasmaCore.Types.DefaultBackground
|
||||||
toolTipMainText: i18n("Antigravity — quote modelli")
|
toolTipMainText: i18n("Antigravity — quote modelli")
|
||||||
toolTipSubText: root.data && root.data.groups && root.data.groups.length > 0
|
toolTipSubText: root.data && root.data.gemini
|
||||||
? i18n("Gemini: %1% · Claude: %2%",
|
? i18n("Gemini: %1% · Claude: %2%",
|
||||||
Math.round((root.data.groups[0].remaining || 0) * 100),
|
Math.round((root.data.gemini.remaining || 0) * 100),
|
||||||
Math.round((root.data.groups.length > 1 ? root.data.groups[1].remaining || 0 : 0) * 100))
|
Math.round((root.data.claude ? root.data.claude.remaining || 0 : 0) * 100))
|
||||||
: (root.errorMsg || "")
|
: (root.errorMsg || "")
|
||||||
|
|
||||||
preferredRepresentation: fullRepresentation
|
preferredRepresentation: fullRepresentation
|
||||||
@@ -53,11 +53,12 @@ PlasmoidItem {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse((result["stdout"] || "").trim())
|
const stdout = (result["stdout"] || "").trim()
|
||||||
|
const parsed = JSON.parse(stdout)
|
||||||
if (parsed && parsed.ok === false) {
|
if (parsed && parsed.ok === false) {
|
||||||
root.errorMsg = parsed.error + (parsed.detail ? " — " + parsed.detail : "")
|
root.errorMsg = parsed.error + (parsed.detail ? " — " + parsed.detail : "")
|
||||||
root.data = null
|
root.data = null
|
||||||
} else if (parsed && parsed.ok && parsed.groups) {
|
} else if (parsed && parsed.ok) {
|
||||||
root.data = parsed
|
root.data = parsed
|
||||||
root.errorMsg = ""
|
root.errorMsg = ""
|
||||||
root.lastUpdate = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss")
|
root.lastUpdate = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss")
|
||||||
@@ -89,18 +90,6 @@ PlasmoidItem {
|
|||||||
return root.themeIndigo
|
return root.themeIndigo
|
||||||
}
|
}
|
||||||
|
|
||||||
function countdownFor(resetAt) {
|
|
||||||
const tick = root.clockTick
|
|
||||||
if (!resetAt || resetAt <= 0) return "—"
|
|
||||||
let mins = Math.max(0, Math.floor((resetAt * 1000 - Date.now()) / 60000))
|
|
||||||
if (mins === 0) return i18n("ora")
|
|
||||||
const days = Math.floor(mins / 1440)
|
|
||||||
mins -= days * 1440
|
|
||||||
const hours = Math.floor(mins / 60)
|
|
||||||
mins -= hours * 60
|
|
||||||
return days > 0 ? i18n("%1g %2h", days, hours) : i18n("%1h %2m", hours, mins)
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: root.refresh()
|
Component.onCompleted: root.refresh()
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -196,7 +185,7 @@ PlasmoidItem {
|
|||||||
color: Qt.rgba(0.66, 0.33, 0.97, 0.35)
|
color: Qt.rgba(0.66, 0.33, 0.97, 0.35)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visualizzazione Errore
|
// Messaggio Errore
|
||||||
PC3.Label {
|
PC3.Label {
|
||||||
visible: root.errorMsg.length > 0
|
visible: root.errorMsg.length > 0
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -205,95 +194,40 @@ PlasmoidItem {
|
|||||||
text: i18n("Errore: %1", root.errorMsg)
|
text: i18n("Errore: %1", root.errorMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lista delle 3 quote (Gemini, Claude, GPT-OSS)
|
// 1. Gemini Card
|
||||||
Repeater {
|
GroupCard {
|
||||||
model: root.data && root.data.groups ? root.data.groups : []
|
tag: "GEMINI"
|
||||||
|
title: "Gemini 3.x"
|
||||||
|
models: root.data && root.data.gemini ? (root.data.gemini.models || "Pro/Flash") : "Pro/Flash"
|
||||||
|
remaining: root.data && root.data.gemini ? (root.data.gemini.remaining || 0) : 1.0
|
||||||
|
usedPercent: root.data && root.data.gemini ? (root.data.gemini.used_percent || 0) : 0
|
||||||
|
resetAt: root.data && root.data.gemini ? (root.data.gemini.reset_at || 0) : 0
|
||||||
|
clockTick: root.clockTick
|
||||||
|
accentColor: root.accentColorFor(Math.round((root.data && root.data.gemini ? root.data.gemini.remaining : 1.0) * 100))
|
||||||
|
}
|
||||||
|
|
||||||
delegate: Rectangle {
|
// 2. Claude Card
|
||||||
required property var modelData
|
GroupCard {
|
||||||
required property int index
|
tag: "CLAUDE"
|
||||||
|
title: "Claude 4.6"
|
||||||
|
models: root.data && root.data.claude ? (root.data.claude.models || "Sonnet/Opus") : "Sonnet/Opus"
|
||||||
|
remaining: root.data && root.data.claude ? (root.data.claude.remaining || 0) : 1.0
|
||||||
|
usedPercent: root.data && root.data.claude ? (root.data.claude.used_percent || 0) : 0
|
||||||
|
resetAt: root.data && root.data.claude ? (root.data.claude.reset_at || 0) : 0
|
||||||
|
clockTick: root.clockTick
|
||||||
|
accentColor: root.accentColorFor(Math.round((root.data && root.data.claude ? root.data.claude.remaining : 1.0) * 100))
|
||||||
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
// 3. GPT Card
|
||||||
Layout.preferredHeight: 46
|
GroupCard {
|
||||||
radius: 5
|
tag: "GPT"
|
||||||
color: Qt.rgba(0, 0, 0, 0.28)
|
title: "GPT-OSS"
|
||||||
border.width: 1
|
models: root.data && root.data.gpt ? (root.data.gpt.models || "120B") : "120B"
|
||||||
border.color: root.accentColorFor(Math.round((modelData.remaining || 0) * 100))
|
remaining: root.data && root.data.gpt ? (root.data.gpt.remaining || 0) : 1.0
|
||||||
|
usedPercent: root.data && root.data.gpt ? (root.data.gpt.used_percent || 0) : 0
|
||||||
ColumnLayout {
|
resetAt: root.data && root.data.gpt ? (root.data.gpt.reset_at || 0) : 0
|
||||||
anchors.fill: parent
|
clockTick: root.clockTick
|
||||||
anchors.margins: 4
|
accentColor: root.accentColorFor(Math.round((root.data && root.data.gpt ? root.data.gpt.remaining : 1.0) * 100))
|
||||||
spacing: 2
|
|
||||||
|
|
||||||
// Riga 1: Nome gruppo + Modelli + % Residuo
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: 4
|
|
||||||
|
|
||||||
PC3.Label {
|
|
||||||
text: modelData.name || ""
|
|
||||||
font.bold: true
|
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
PC3.Label {
|
|
||||||
text: "· " + (modelData.models || "")
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 3
|
|
||||||
Layout.fillWidth: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
PC3.Label {
|
|
||||||
text: Math.round((modelData.remaining || 0) * 100) + "%"
|
|
||||||
color: root.accentColorFor(Math.round((modelData.remaining || 0) * 100))
|
|
||||||
font.bold: true
|
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Riga 2: Barra di avanzamento
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 5
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 2.5
|
|
||||||
color: Qt.rgba(0, 0, 0, 0.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: parent.width * Math.max(0, Math.min(1, modelData.remaining || 0))
|
|
||||||
height: parent.height
|
|
||||||
radius: 2.5
|
|
||||||
color: root.accentColorFor(Math.round((modelData.remaining || 0) * 100))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Riga 3: Dettaglio usato + Reset countdown
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: 4
|
|
||||||
|
|
||||||
PC3.Label {
|
|
||||||
text: i18n("%1% usato", modelData.used_percent !== undefined ? modelData.used_percent : 0)
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 3
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { Layout.fillWidth: true }
|
|
||||||
|
|
||||||
PC3.Label {
|
|
||||||
text: i18n("reset %1", root.countdownFor(modelData.reset_at))
|
|
||||||
color: root.themeIndigo
|
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
Item { Layout.fillHeight: true }
|
||||||
|
|||||||
Reference in New Issue
Block a user