about: supporters subtab

This commit is contained in:
Lemmy
2026-02-05 09:34:24 -05:00
parent f13bc738be
commit e8f0822118
21 changed files with 502 additions and 1 deletions
+5
View File
@@ -469,6 +469,7 @@
"sources": "Quellen",
"start": "Start",
"stop": "Stopp",
"supporters": "Unterstützer",
"suspend": "Energie sparen",
"templates": "Vorlagen",
"tertiary": "Tertiär",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Werde Unterstützer",
"changelog": "Änderungsprotokoll anzeigen",
"contributors-desc": "Ein Dankeschön an unseren {count} <b>großartigen</b> Mitwirkenden!",
"contributors-description-plural": "Ein Dankeschön an unsere {count} <b>großartigen</b> Mitwirkenden!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia Shell",
"privacy-policy": "Datenschutzbestimmungen",
"support": "Unterstütze uns",
"supporter-badge": "Unterstützer",
"supporters-desc-singular": "Ein riesiges Dankeschön an unseren großartigen Unterstützer!",
"supporters-loading": "Supporter werden geladen...",
"system-cpu": "CPU:",
"system-disk": "Festplatte:",
"system-gpu": "GPU:",
+6
View File
@@ -469,6 +469,7 @@
"sources": "Sources",
"start": "Start",
"stop": "Stop",
"supporters": "Supporters",
"suspend": "Suspend",
"templates": "Templates",
"tertiary": "Tertiary",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Become a supporter",
"changelog": "View changelog",
"contributors-desc": "Shout-out to our {count} <b>awesome</b> contributor!",
"contributors-description-plural": "Shout-out to our {count} <b>awesome</b> contributors!",
@@ -658,6 +660,10 @@
"noctalia-title": "Noctalia shell",
"privacy-policy": "Privacy policy",
"support": "Support us",
"supporter-badge": "Supporter",
"supporters-desc-plural": "A huge thank you to our <b>{count} amazing</b> supporters!",
"supporters-desc-singular": "A huge thank you to our amazing supporter!",
"supporters-loading": "Loading supporters...",
"system-cpu": "CPU:",
"system-disk": "Disk:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Fuentes",
"start": "Comienzo",
"stop": "Parar",
"supporters": "Apoyadores",
"suspend": "Suspender",
"templates": "Plantillas",
"tertiary": "Terciario",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Hazte patrocinador",
"changelog": "Ver registro de cambios",
"contributors-desc": "¡Un saludo a nuestro <b>increíble</b> colaborador número {count}!",
"contributors-description-plural": "¡Un saludo a nuestros {count} <b>increíbles</b> colaboradores!",
@@ -658,6 +660,9 @@
"noctalia-title": "Shell Noctalia",
"privacy-policy": "Política de privacidad",
"support": "Apóyanos",
"supporter-badge": "Colaborador",
"supporters-desc-singular": "¡Un enorme agradecimiento a nuestro increíble colaborador!",
"supporters-loading": "Cargando patrocinadores...",
"system-cpu": "CPU:",
"system-disk": "Disco:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Sources",
"start": "Commencer",
"stop": "Arrêtez",
"supporters": "Soutiens",
"suspend": "Mettre en veille",
"templates": "Modèles",
"tertiary": "Tertiaire",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Devenir un soutien",
"changelog": "Afficher le journal des modifications",
"contributors-desc": "Un grand merci à notre {count} <b>super</b> contributeur !",
"contributors-description-plural": "Un grand merci à nos {count} <b>super</b> contributeurs !",
@@ -658,6 +660,9 @@
"noctalia-title": "Shell Noctalia",
"privacy-policy": "Politique de confidentialité",
"support": "Soutenez-nous",
"supporter-badge": "Soutien",
"supporters-desc-singular": "Un immense merci à notre incroyable soutien !",
"supporters-loading": "Chargement des contributeurs...",
"system-cpu": "Processeur :",
"system-disk": "Disque :",
"system-gpu": "GPU :",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Források",
"start": "Kezdés",
"stop": "Állj",
"supporters": "Támogatók",
"suspend": "Felfüggesztés",
"templates": "Sablonok",
"tertiary": "Harmadlagos",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Legyél támogató",
"changelog": "Változások megtekintése",
"contributors-desc": "Köszönet a(z) {count} <b>fantasztikus</b> közreműködőnknek!",
"contributors-description-plural": "Köszönet a(z) {count} <b>fantasztikus</b> közreműködőnknek!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia shell",
"privacy-policy": "Adatvédelmi irányelvek",
"support": "Támogasson minket",
"supporter-badge": "Támogató",
"supporters-desc-singular": "Hatalmas köszönet csodálatos támogatóinknak!",
"supporters-loading": "Támogatók betöltése...",
"system-cpu": "CPU:",
"system-disk": "Lemez:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "ソース",
"start": "開始",
"stop": "停止",
"supporters": "サポーター",
"suspend": "サスペンド",
"templates": "テンプレート",
"tertiary": "第三",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "サポーターになる",
"changelog": "変更履歴を見る",
"contributors-desc": "{count}人の<b>素晴らしい</b>コントリビューターに感謝!",
"contributors-description-plural": "{count}人の<b>素晴らしい</b>コントリビューターに感謝!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia shell",
"privacy-policy": "プライバシーポリシー",
"support": "支援する",
"supporter-badge": "サポーター",
"supporters-desc-singular": "素晴らしいサポーターに心からの感謝を!",
"supporters-loading": "サポーターを読み込み中...",
"system-cpu": "CPU",
"system-disk": "ディスク:",
"system-gpu": "GPU",
+5
View File
@@ -469,6 +469,7 @@
"sources": "소스",
"start": "시작",
"stop": "중지",
"supporters": "후원자",
"suspend": "대기 모드",
"templates": "템플릿",
"tertiary": "세번째",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "후원자 되기",
"changelog": "변경 로그 보기",
"contributors-desc": "{count}명의 <b>멋진</b> 기여자에게 감사를 전합니다!",
"contributors-description-plural": "{count}명의 <b>멋진</b> 기여자들에게 감사를 전합니다!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia 셸",
"privacy-policy": "개인정보 처리방침",
"support": "후원하기",
"supporter-badge": "후원자",
"supporters-desc-singular": "멋진 후원자분께 진심으로 감사드립니다!",
"supporters-loading": "후원자 불러오는 중...",
"system-cpu": "CPU:",
"system-disk": "디스크:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Bronnen",
"start": "Begin",
"stop": "Stop",
"supporters": "Ondersteuners",
"suspend": "Onderbreken",
"templates": "Sjablonen",
"tertiary": "Tertiair",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Word supporter",
"changelog": "Bekijk wijzigingslogboek",
"contributors-desc": "Een shout-out naar onze {count} <b>geweldige</b> bijdrager!",
"contributors-description-plural": "Een shout-out naar onze {count} <b>geweldige</b> bijdragers!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia-shell",
"privacy-policy": "Privacybeleid",
"support": "Steun ons",
"supporter-badge": "Supporter",
"supporters-desc-singular": "Een enorme dank aan onze geweldige supporter!",
"supporters-loading": "Donateurs laden...",
"system-cpu": "CPU:",
"system-disk": "Schijf:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Źródła",
"start": "Start",
"stop": "Stop",
"supporters": "Wspierający",
"suspend": "Wstrzymaj",
"templates": "Szablony",
"tertiary": "Trzeciorzędowy",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Zostań wspierającym",
"changelog": "Zobacz dziennik zmian",
"contributors-desc": "Podziękowania dla naszego {count} <b>niesamowitego</b> współtwórcy!",
"contributors-description-plural": "Podziękowania dla naszych {count} <b>niesamowitych</b> współtwórców!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia shell",
"privacy-policy": "Polityka prywatności",
"support": "Wesprzyj nas",
"supporter-badge": "Wspierający",
"supporters-desc-singular": "Ogromne podziękowania dla naszego wspaniałego wspierającego!",
"supporters-loading": "Ładowanie wspierających...",
"system-cpu": "Procesor:",
"system-disk": "Dysk:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Fontes",
"start": "Começar",
"stop": "Pare",
"supporters": "Apoiadores",
"suspend": "Suspender",
"templates": "Modelos",
"tertiary": "Terciário",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Torne-se um apoiador",
"changelog": "Ver histórico de alterações",
"contributors-desc": "Agradecimentos ao nosso <b>incrível</b> colaborador!",
"contributors-description-plural": "Agradecimentos aos nossos {count} <b>incríveis</b> colaboradores!",
@@ -658,6 +660,9 @@
"noctalia-title": "Shell Noctalia",
"privacy-policy": "Política de privacidade",
"support": "Apoie-nos",
"supporter-badge": "Apoiador",
"supporters-desc-singular": "Um enorme obrigado ao nosso incrível apoiador!",
"supporters-loading": "Carregando apoiadores...",
"system-cpu": "CPU:",
"system-disk": "Disco:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Источники",
"start": "Начать",
"stop": "Стоп",
"supporters": "Поддерживающие",
"suspend": "Приостановить",
"templates": "Шаблоны",
"tertiary": "Третичный",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Стать спонсором",
"changelog": "Посмотреть список изменений",
"contributors-desc": "Благодарим нашего <b>замечательного</b> участника: {count}!",
"contributors-description-plural": "Благодарим наших <b>замечательных</b> участников: {count}!",
@@ -658,6 +660,9 @@
"noctalia-title": "Оболочка Noctalia",
"privacy-policy": "Политика конфиденциальности",
"support": "Поддержать нас",
"supporter-badge": "Сторонник",
"supporters-desc-singular": "Огромное спасибо нашему замечательному стороннику!",
"supporters-loading": "Загрузка спонсоров...",
"system-cpu": "ЦП:",
"system-disk": "Диск:",
"system-gpu": "Графический процессор",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Källor",
"start": "Starta",
"stop": "Stoppa",
"supporters": "Stödjare",
"suspend": "Avbryt",
"templates": "Mallar",
"tertiary": "Tertiär",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Bli supporter",
"changelog": "Visa ändringslogg",
"contributors-desc": "Tack till våra {count} <b>fantastiska</b> bidragsgivare!",
"contributors-description-plural": "Tack till våra {count} <b>fantastiska</b> bidragsgivare!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia-skal",
"privacy-policy": "Sekretesspolicy",
"support": "Stöd oss",
"supporter-badge": "Supporter",
"supporters-desc-singular": "Ett stort tack till vår fantastiska supporter!",
"supporters-loading": "Laddar supportrar...",
"system-cpu": "CPU:",
"system-disk": "Disk:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Kaynaklar",
"start": "Başlat",
"stop": "Dur",
"supporters": "Destekçiler",
"suspend": "Askıya al",
"templates": "Şablonlar",
"tertiary": "Üçüncül",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Destekçi ol",
"changelog": "Değişiklik günlüğünü görüntüle",
"contributors-desc": "{count} <b>harika</b> katılımcımıza <b>teşekkürler</b>!",
"contributors-description-plural": "{count} <b>harika</b> katılımcımıza <b>teşekkürler</b>!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia kabuğu",
"privacy-policy": "Gizlilik politikası",
"support": "Bizi destekleyin",
"supporter-badge": "Destekçi",
"supporters-desc-singular": "Harika destekçimize kocaman bir teşekkür!",
"supporters-loading": "Destekçiler yükleniyor...",
"system-cpu": "İşlemci:",
"system-disk": "Disk:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "Джерела",
"start": "Почати",
"stop": "Зупиніться",
"supporters": "Прихильники",
"suspend": "Призупинити",
"templates": "Шаблони",
"tertiary": "Третинний",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "Стати прихильником",
"changelog": "Переглянути журнал змін",
"contributors-desc": "Подяка нашому {count} <b>чудовому</b> учаснику!",
"contributors-description-plural": "Подяка нашим {count} <b>чудовим</b> учасникам!",
@@ -658,6 +660,9 @@
"noctalia-title": "Оболонка Noctalia",
"privacy-policy": "Політика конфіденційності",
"support": "Підтримати нас",
"supporter-badge": "Прихильник",
"supporters-desc-singular": "Величезне дякую нашому чудовому прихильнику!",
"supporters-loading": "Завантаження прихильників...",
"system-cpu": "ЦП:",
"system-disk": "Диск:",
"system-gpu": "GPU:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "来源",
"start": "开始",
"stop": "停止",
"supporters": "支持者",
"suspend": "挂起",
"templates": "模板",
"tertiary": "第三",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "成为支持者",
"changelog": "查看更改日志",
"contributors-desc": "向我们 {count} 位<b>超棒的</b>贡献者致敬!",
"contributors-description-plural": "向我们 {count} 位<b>超棒的</b>贡献者致敬!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia shell",
"privacy-policy": "隐私政策",
"support": "支持我们",
"supporter-badge": "支持者",
"supporters-desc-singular": "非常感谢我们出色的支持者!",
"supporters-loading": "正在加载支持者...",
"system-cpu": "中央处理器:",
"system-disk": "磁盘:",
"system-gpu": "图形处理器:",
+5
View File
@@ -469,6 +469,7 @@
"sources": "來源",
"start": "開始",
"stop": "停止",
"supporters": "支持者",
"suspend": "暫停",
"templates": "模板",
"tertiary": "第三",
@@ -646,6 +647,7 @@
},
"panels": {
"about": {
"become-supporter": "成為支持者",
"changelog": "檢視更新日誌",
"contributors-desc": "特別感謝我們這{count}位<b>超讚</b>的貢獻者!!",
"contributors-description-plural": "特別感謝我們這{count}位<b>超讚</b>的貢獻者!!",
@@ -658,6 +660,9 @@
"noctalia-title": "Noctalia Shell",
"privacy-policy": "隱私權政策",
"support": "支持我們",
"supporter-badge": "支持者",
"supporters-desc-singular": "非常感謝我們出色的支持者!",
"supporters-loading": "正在載入支持者...",
"system-cpu": "CPU:",
"system-disk": "磁碟:",
"system-gpu": "GPU:",
@@ -25,6 +25,11 @@ ColumnLayout {
tabIndex: 1
checked: subTabBar.currentIndex === 1
}
NTabButton {
text: I18n.tr("common.supporters")
tabIndex: 2
checked: subTabBar.currentIndex === 2
}
}
Item {
@@ -38,5 +43,6 @@ ColumnLayout {
VersionSubTab {}
ContributorsSubTab {}
SupportersSubTab {}
}
}
@@ -0,0 +1,244 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services.Noctalia
import qs.Services.UI
import qs.Widgets
ColumnLayout {
id: root
property var supporters: SupporterService.supporters
property int avatarCacheVersion: 0
Connections {
target: SupporterService
function onCachedAvatarsChanged() {
root.avatarCacheVersion++;
}
}
spacing: Style.marginL
NHeader {
description: root.supporters.length === 0 ? I18n.tr("panels.about.supporters-loading") : root.supporters.length === 1 ? I18n.tr("panels.about.supporters-desc-singular", {
"count": 1
}) : I18n.tr("panels.about.supporters-desc-plural", {
"count": root.supporters.length
})
enableDescriptionRichText: true
}
NButton {
Layout.alignment: Qt.AlignHCenter
icon: "heart"
text: I18n.tr("panels.about.become-supporter")
outlined: true
onClicked: {
Quickshell.execDetached(["xdg-open", "https://buymeacoffee.com/noctalia"]);
ToastService.showNotice(I18n.tr("panels.about.support"), I18n.tr("toast.donation-opened"));
}
}
NDivider {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
}
// Supporter cards
Flow {
id: supportersFlow
visible: root.supporters.length > 0
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
spacing: Style.marginL
Repeater {
model: root.supporters.length
delegate: Rectangle {
id: supporterCard
property bool hasGithub: !!root.supporters[index].github_username
width: Math.max(Math.round(supportersFlow.width / 2 - Style.marginL - 1), Math.round(Style.baseWidgetSize * 4.5))
height: Math.round(Style.baseWidgetSize * 2.6)
radius: Style.radiusM
color: supporterArea.containsMouse && hasGithub ? Color.mHover : Qt.alpha(Color.mPrimary, 0.05)
border.width: Style.borderM
border.color: supporterArea.containsMouse && hasGithub ? Color.mPrimary : Qt.alpha(Color.mPrimary, 0.5)
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on border.color {
ColorAnimation {
duration: Style.animationFast
}
}
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginM
// Avatar with heart badge
Item {
id: avatarWrapper
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: Style.baseWidgetSize * 2.0
Layout.preferredHeight: Style.baseWidgetSize * 2.0
property bool isRounded: false
Item {
anchors.fill: parent
Image {
anchors.fill: parent
visible: supporterCard.hasGithub
source: {
if (!supporterCard.hasGithub)
return "";
var _ = root.avatarCacheVersion;
var username = root.supporters[index].github_username;
var cached = SupporterService.getAvatarPath(username);
if (cached) {
avatarWrapper.isRounded = true;
return cached;
}
return "https://github.com/" + username + ".png?size=256";
}
fillMode: Image.PreserveAspectFit
mipmap: true
smooth: true
asynchronous: true
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
// Fallback logo for supporters without GitHub
Rectangle {
anchors.fill: parent
visible: !supporterCard.hasGithub
radius: width * 0.5
color: Qt.alpha(Color.mPrimary, 0.15)
Image {
anchors.centerIn: parent
source: "../../../../../Assets/noctalia.svg"
width: parent.width * 0.8
height: width
fillMode: Image.PreserveAspectFit
mipmap: true
smooth: true
}
}
}
Rectangle {
visible: avatarWrapper.isRounded
anchors.fill: parent
color: "transparent"
radius: width * 0.5
border.width: Style.borderM
border.color: Color.mPrimary
}
// Heart badge
Rectangle {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: -2
anchors.bottomMargin: -2
width: Style.fontSizeM + Style.marginS
height: width
radius: width * 0.5
color: Color.mPrimary
NIcon {
anchors.centerIn: parent
icon: "heart-filled"
pointSize: Style.fontSizeXS
color: Color.mOnPrimary
}
}
}
// Info column
ColumnLayout {
spacing: 2
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
NText {
text: root.supporters[index].name || root.supporters[index].github_username || "Unknown"
font.weight: Style.fontWeightBold
color: supporterArea.containsMouse && supporterCard.hasGithub ? Color.mOnHover : Color.mOnSurface
elide: Text.ElideRight
Layout.fillWidth: true
pointSize: Style.fontSizeS
}
RowLayout {
spacing: Style.marginXS
Layout.fillWidth: true
NIcon {
icon: "heart"
pointSize: Style.fontSizeXS
color: Color.mPrimary
}
NText {
text: I18n.tr("panels.about.supporter-badge")
pointSize: Style.fontSizeXS
color: Color.mPrimary
font.weight: Style.fontWeightMedium
}
}
}
// Hover indicator (only for supporters with GitHub)
NIcon {
Layout.alignment: Qt.AlignVCenter
icon: "arrow-right"
pointSize: Style.fontSizeS
color: Color.mPrimary
visible: supporterCard.hasGithub
opacity: supporterArea.containsMouse ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
}
MouseArea {
id: supporterArea
anchors.fill: parent
hoverEnabled: true
cursorShape: supporterCard.hasGithub ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
var username = root.supporters[index].github_username;
if (username) {
Quickshell.execDetached(["xdg-open", "https://github.com/" + username]);
}
}
}
}
}
}
}
@@ -515,7 +515,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter
onClicked: {
Quickshell.execDetached(["xdg-open", "https://buymeacoffee.com/noctalia"]);
ToastService.showNotice(I18n.tr("panels.about.support"), I18n.tr("toast.kofi-opened"));
ToastService.showNotice(I18n.tr("panels.about.support"), I18n.tr("toast.donation-opened"));
}
}
}
+169
View File
@@ -0,0 +1,169 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Services.UI
Singleton {
id: root
property string supporterDataFile: Settings.cacheDir + "supporters.json"
property int updateFrequency: 60 * 60 // 1 hour in seconds
property bool isFetching: false
property bool isInitialized: false
readonly property alias data: adapter
property var supporters: []
property var cachedAvatars: ({}) // username -> file:// path
property bool avatarsCached: false
FileView {
id: supporterDataFileView
path: supporterDataFile
printErrors: false
watchChanges: false
onLoaded: {
if (!root.isInitialized) {
root.isInitialized = true;
loadFromCache();
}
}
onLoadFailed: function (error) {
if (error.toString().includes("No such file") || error === 2) {
root.isInitialized = true;
fetchFromApi();
}
}
JsonAdapter {
id: adapter
property var supporters: []
property real timestamp: 0
}
}
function init() {
Logger.i("Supporter", "Service started");
}
function loadFromCache() {
const now = Time.timestamp;
var needsRefetch = false;
if (!data.timestamp || (now >= data.timestamp + updateFrequency)) {
needsRefetch = true;
Logger.i("Supporter", "Cache expired or missing, scheduling fetch");
} else {
Logger.i("Supporter", "Cache is fresh, using cached data");
}
if (data.supporters && data.supporters.length > 0) {
root.supporters = data.supporters;
Logger.d("Supporter", "Loaded", data.supporters.length, "supporters from cache");
}
if (needsRefetch) {
fetchFromApi();
}
}
function fetchFromApi() {
if (isFetching) {
Logger.d("Supporter", "Already fetching");
return;
}
isFetching = true;
supporterProcess.running = true;
}
function saveData() {
data.timestamp = Time.timestamp;
Quickshell.execDetached(["mkdir", "-p", Settings.cacheDir]);
try {
supporterDataFileView.writeAdapter();
Logger.d("Supporter", "Cache file written successfully");
} catch (error) {
Logger.e("Supporter", "Failed to write cache file:", error);
}
}
function getAvatarPath(username) {
return cachedAvatars[username] || "";
}
function cacheAvatars() {
if (supporters.length === 0)
return;
avatarsCached = true;
for (var i = 0; i < supporters.length; i++) {
var supporter = supporters[i];
var username = supporter.github_username;
// Only cache avatars for supporters with GitHub accounts
if (!username)
continue;
var avatarUrl = "https://github.com/" + username + ".png?size=256";
(function (uname, url) {
ImageCacheService.getCircularAvatar(url, "supporter_" + uname, function (cachedPath, success) {
if (success) {
cachedAvatars[uname] = "file://" + cachedPath;
cachedAvatarsChanged();
}
});
})(username, avatarUrl);
}
}
onSupportersChanged: {
if (supporters.length > 0 && !avatarsCached && ImageCacheService.initialized) {
Qt.callLater(cacheAvatars);
}
}
Connections {
target: ImageCacheService
function onInitializedChanged() {
if (ImageCacheService.initialized && supporters.length > 0 && !avatarsCached) {
Qt.callLater(cacheAvatars);
}
}
}
Process {
id: supporterProcess
command: ["curl", "-s", "https://noctalia.dev:7777/supporters"]
stdout: StdioCollector {
onStreamFinished: {
try {
const response = text;
if (response && response.trim()) {
const parsed = JSON.parse(response);
if (Array.isArray(parsed)) {
root.data.supporters = parsed;
root.supporters = parsed;
root.saveData();
Logger.d("Supporter", "Fetched", parsed.length, "supporters");
} else if (parsed.message) {
Logger.w("Supporter", "API error:", parsed.message);
}
}
} catch (e) {
Logger.e("Supporter", "Failed to parse response:", e);
}
root.isFetching = false;
}
}
}
}
+1
View File
@@ -102,6 +102,7 @@ ShellRoot {
PowerProfileService.init();
HostService.init();
GitHubService.init();
SupporterService.init();
delayedInitTimer.running = true;
}