From 77e0f5da3255f3a4e5441cd5a8fc2fd32a0df0a9 Mon Sep 17 00:00:00 2001 From: moWerk Date: Tue, 31 Mar 2026 20:15:48 +0200 Subject: [PATCH 1/5] Add WatchfaceHelper singleton for user-space watchface management Introduces WatchfaceHelper as a QML singleton registered under org.asteroid.settings 1.0. Provides network-backed file downloads via QNetworkAccessManager, directory creation, watchface removal, font cache rebuilding and launcher restart. All filesystem writes are enforced against a whitelist of user-writable paths mirroring what the ./watchface deploy script writes: the XDG GenericDataLocation asteroid-launcher subtree, ~/.fonts/ and the QStandardPaths cache location. Any write outside these paths is blocked and logged. readFile() is additionally restricted to the cache location only, preventing arbitrary filesystem reads from QML. Path helpers userWatchfacePath(), userAssetPath(), userFontsPath() and cachePath() expose the resolved paths to QML consumers. restartSession() runs fc-cache -f synchronously before issuing systemctl --user restart asteroid-launcher so newly installed fonts are visible immediately after the compositor restarts. Adds Qt5::Network to CMakeLists target_link_libraries. --- src/CMakeLists.txt | 7 +- src/WatchfaceHelper.cpp | 214 ++++++++++++++++++++++++++++++++++++++++ src/WatchfaceHelper.h | 113 +++++++++++++++++++++ src/main.cpp | 3 + 4 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 src/WatchfaceHelper.cpp create mode 100644 src/WatchfaceHelper.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ccaf5ed..572ec898 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,12 +14,14 @@ set(SRC sysinfo.cpp taptowake.cpp tilttowake.cpp - volumecontrol.cpp) + volumecontrol.cpp + WatchfaceHelper.cpp) set(HEADERS sysinfo.h taptowake.h tilttowake.h - volumecontrol.h) + volumecontrol.h + WatchfaceHelper.h) add_library(asteroid-settings ${SRC} ${HEADERS} resources.qrc ${CMAKE_CURRENT_BINARY_DIR}/mceiface.h @@ -34,6 +36,7 @@ target_link_libraries(asteroid-settings PRIVATE Qt5::Quick Qt5::DBus Qt5::Multimedia + Qt5::Network AsteroidApp) install(TARGETS asteroid-settings diff --git a/src/WatchfaceHelper.cpp b/src/WatchfaceHelper.cpp new file mode 100644 index 00000000..f92b6493 --- /dev/null +++ b/src/WatchfaceHelper.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2026 - Timo Könnecke + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "WatchfaceHelper.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static const QStringList PREVIEW_SIZES = { + QStringLiteral("112"), QStringLiteral("128"), + QStringLiteral("144"), QStringLiteral("160"), QStringLiteral("182") +}; + +WatchfaceHelper *WatchfaceHelper::s_instance = nullptr; + +WatchfaceHelper::WatchfaceHelper(QObject *parent) +: QObject(parent) +, m_nam(new QNetworkAccessManager(this)) +{ + s_instance = this; + // Ensure user watchface and cache directories exist on first run + QDir().mkpath(userWatchfacePath()); + QDir().mkpath(cachePath()); +} + +WatchfaceHelper *WatchfaceHelper::instance() +{ + if (!s_instance) + s_instance = new WatchfaceHelper(); + return s_instance; +} + +QObject *WatchfaceHelper::qmlInstance(QQmlEngine *, QJSEngine *) +{ + return instance(); +} + +// ── Path helpers ────────────────────────────────────────────────────────────── + +QString WatchfaceHelper::userDataPath() const +{ + return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + + QStringLiteral("/asteroid-launcher/"); +} + +QString WatchfaceHelper::userWatchfacePath() const +{ + return userDataPath() + QStringLiteral("watchfaces/"); +} + +QString WatchfaceHelper::userAssetPath() const +{ + return QStringLiteral("file://") + userDataPath(); +} + +QString WatchfaceHelper::userFontsPath() const +{ + return QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QStringLiteral("/.fonts/"); +} + +QString WatchfaceHelper::cachePath() const +{ + return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + + QStringLiteral("/watchface-store/"); +} + +bool WatchfaceHelper::isPathAllowed(const QString &path) const +{ + if (path.startsWith(cachePath())) return true; + if (path.startsWith(userDataPath())) return true; + if (path.startsWith(userFontsPath())) return true; + return false; +} + +// ── Public API ──────────────────────────────────────────────────────────────── + +void WatchfaceHelper::downloadFile(const QString &url, const QString &destPath) +{ + if (!isPathAllowed(destPath)) { + qWarning() << "WatchfaceHelper: blocked write attempt to" << destPath; + emit downloadComplete(destPath, false); + return; + } + + QUrl qurl(url); + QNetworkRequest req(qurl); + req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, + QNetworkRequest::NoLessSafeRedirectPolicy); + QNetworkReply *reply = m_nam->get(req); + + connect(reply, &QNetworkReply::downloadProgress, + this, [this, destPath](qint64 recv, qint64 total) { + emit downloadProgress(destPath, recv, total); + }); + + connect(reply, &QNetworkReply::finished, + this, [this, reply, destPath]() { + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "WatchfaceHelper: download error for" + << destPath << ":" << reply->errorString(); + emit downloadComplete(destPath, false); + return; + } + + const QFileInfo fi(destPath); + if (!QDir().mkpath(fi.absolutePath())) { + qWarning() << "WatchfaceHelper: cannot create directory" + << fi.absolutePath(); + emit downloadComplete(destPath, false); + return; + } + + QFile file(destPath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "WatchfaceHelper: cannot open for writing:" << destPath; + emit downloadComplete(destPath, false); + return; + } + + file.write(reply->readAll()); + file.close(); + emit downloadComplete(destPath, true); + }); +} + +bool WatchfaceHelper::mkpath(const QString &dirPath) +{ + return QDir().mkpath(dirPath); +} + +bool WatchfaceHelper::removeWatchface(const QString &name) +{ + bool removedQml = false; + + const QString qmlPath = userWatchfacePath() + name + QStringLiteral(".qml"); + if (QFile::exists(qmlPath)) + removedQml = QFile::remove(qmlPath); + + for (const QString &size : PREVIEW_SIZES) { + const QString p = userDataPath() + + QStringLiteral("watchfaces-preview/") + + size + QStringLiteral("/") + name + QStringLiteral(".png"); + if (QFile::exists(p)) QFile::remove(p); + } + + QDir imgDir(userDataPath() + QStringLiteral("watchface-img/")); + if (imgDir.exists()) { + const QStringList filters = { + name + QStringLiteral("-*"), + name + QStringLiteral(".*") + }; + for (const QString &f : imgDir.entryList(filters, QDir::Files)) + imgDir.remove(f); + } + + return removedQml; +} + +void WatchfaceHelper::restartSession() +{ + QProcess::execute(QStringLiteral("fc-cache"), {QStringLiteral("-f")}); + QProcess::startDetached(QStringLiteral("systemctl"), + {QStringLiteral("--user"), QStringLiteral("restart"), QStringLiteral("asteroid-launcher")}); +} + +QString WatchfaceHelper::readFile(const QString &path) const +{ + if (!path.startsWith(cachePath())) { + qWarning() << "WatchfaceHelper: blocked read attempt from" << path; + return QString(); + } + QFile f(path); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) + return QString(); + return QString::fromUtf8(f.readAll()); +} + +bool WatchfaceHelper::writeFile(const QString &path, const QString &content) +{ + if (!isPathAllowed(path)) { + qWarning() << "WatchfaceHelper: blocked write attempt to" << path; + return false; + } + const QFileInfo fi(path); + QDir().mkpath(fi.absolutePath()); + QFile f(path); + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) + return false; + f.write(content.toUtf8()); + return true; +} diff --git a/src/WatchfaceHelper.h b/src/WatchfaceHelper.h new file mode 100644 index 00000000..e32552b2 --- /dev/null +++ b/src/WatchfaceHelper.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2026 - Timo Könnecke + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WATCHFACEHELPER_H +#define WATCHFACEHELPER_H + +#include +#include +#include +#include + +class WatchfaceHelper : public QObject +{ + Q_OBJECT + +public: + explicit WatchfaceHelper(QObject *parent = nullptr); + static WatchfaceHelper *instance(); + static QObject *qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine); + + /*! + * \brief Download a remote URL and write to destPath. + * destPath must be within an allowed user-writable path — blocked otherwise. + */ + Q_INVOKABLE void downloadFile(const QString &url, const QString &destPath); + + /*! + * \brief Remove all user-folder files belonging to a community watchface. + */ + Q_INVOKABLE bool removeWatchface(const QString &name); + + /*! + * \brief Create a directory path recursively (mkdir -p equivalent). + */ + Q_INVOKABLE bool mkpath(const QString &dirPath); + + /*! + * \brief Rebuild the fontconfig user cache after font install. + */ + Q_INVOKABLE void restartSession(); + + /*! + * \brief Base path for cached watchface store thumbnails. + * Returns QStandardPaths::CacheLocation + "/watchface-store/" + */ + Q_INVOKABLE QString cachePath() const; + + /*! + * \brief User-writable watchface QML directory. + * Returns ~/.local/share/asteroid-launcher/watchfaces/ + */ + Q_INVOKABLE QString userWatchfacePath() const; + + /*! + * \brief User-writable asteroid-launcher data root as file:// URL. + * Returns file://~/.local/share/asteroid-launcher/ + */ + Q_INVOKABLE QString userAssetPath() const; + + /*! + * \brief User-writable fonts directory. + * Returns ~/.fonts/ + */ + Q_INVOKABLE QString userFontsPath() const; + + /*! + * \brief Read a file from the cache location and return its contents. + * Only files within cachePath() are readable — all other paths are blocked. + */ + Q_INVOKABLE QString readFile(const QString &path) const; + + /*! + * \brief Write content to a file at destPath. + * destPath must be within an allowed user-writable path — blocked otherwise. + */ + Q_INVOKABLE bool writeFile(const QString &path, const QString &content); + +signals: + /*! + * \brief Emitted when a downloadFile() call completes. + * \param destPath the destination path originally requested + * \param success true if the file was written successfully + */ + void downloadComplete(const QString &destPath, bool success); + + /*! + * \brief Emitted periodically during a download for progress tracking. + */ + void downloadProgress(const QString &destPath, qint64 received, qint64 total); + +private: + bool isPathAllowed(const QString &path) const; + QString userDataPath() const; + + QNetworkAccessManager *m_nam; + static WatchfaceHelper *s_instance; +}; + +#endif // WATCHFACEHELPER_H diff --git a/src/main.cpp b/src/main.cpp index c73b3889..678a6817 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ #include "tilttowake.h" #include "taptowake.h" #include "sysinfo.h" +#include "WatchfaceHelper.h" int main(int argc, char *argv[]) { @@ -38,6 +39,8 @@ int main(int argc, char *argv[]) qmlRegisterType("org.asteroid.settings", 1, 0, "TiltToWake"); qmlRegisterType("org.asteroid.settings", 1, 0, "TapToWake"); qmlRegisterType("org.asteroid.settings", 1, 0, "SysInfo"); + qmlRegisterSingletonType("org.asteroid.settings", 1, 0, "WatchfaceHelper", + WatchfaceHelper::qmlInstance); view->setSource(QUrl("qrc:/qml/main.qml")); view->rootContext()->setContextProperty("qtVersion", QString(qVersion())); view->rootContext()->setContextProperty("kernelVersion", QString(buf.release)); From 128b2de0e6ff101dc304b9d2591cf32a0f4ac06a Mon Sep 17 00:00:00 2001 From: moWerk Date: Tue, 31 Mar 2026 20:16:34 +0200 Subject: [PATCH 2/5] Add WatchfaceStorePage and extend WatchfaceSelector with store access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WatchfaceSelector gains a second FolderListModel watching the XDG user watchface path alongside the system path. Both are merged into a unified ListModel via a debounced Timer to prevent double-clear during simultaneous count changes. A HEAD probe to api.github.com fires on Component.onCompleted and gates a persistent store footer button that is greyed out with an alternative label when offline. WatchfaceStorePage fetches the unofficial-watchfaces repo catalog via the GitHub Contents API and caches the response JSON to disk. Subsequent page opens load from cache and only hit the network on explicit refresh. Thumbnail previews are downloaded lazily at the device-appropriate resolution and cached permanently. Watchfaces whose preview returns a 404 are pruned from the model silently. Directory listings recurse into subdirectories to handle watchfaces with nested asset structures. Installs land in the XDG user data tree so no root access is required. The QML file, single-resolution preview PNG, watchfaces-img assets and fonts are fetched in parallel. The downloaded watchface is auto-activated on install complete. A persistent footer offers a RemorseTimer-guarded launcher restart to pick up new fonts and QML paths — the page fades to black when the remorse timer fires and holds until the process is killed, preventing a flash back to page content. Interaction model on both pages uses manual onPressed tracking with a Dims.l(2) scroll detection threshold, matching the IntSelector scrubber pattern. Press immediately starts an opacity animation giving frame-one feedback. Scroll cancels and reverses the animation. Release within threshold confirms the action. Long press triggers deletion via RemorseTimer on both pages. Install state is conveyed through color and opacity transitions on a per-tile circle with no discrete timer: green animates in from press, bumps on completion, flashes red on network failure. The selector page uses the same circle in black to indicate the active watchface at opacity 0.2 with the press animation fading toward 0.5 over the full longpress budget as a continuous gesture discriminator. --- src/qml/WatchfaceSelector.qml | 384 +++++++++++++++----- src/qml/WatchfaceStorePage.qml | 636 +++++++++++++++++++++++++++++++++ src/resources.qrc | 1 + 3 files changed, 934 insertions(+), 87 deletions(-) create mode 100644 src/qml/WatchfaceStorePage.qml diff --git a/src/qml/WatchfaceSelector.qml b/src/qml/WatchfaceSelector.qml index 1b56d5be..f5da3b1f 100644 --- a/src/qml/WatchfaceSelector.qml +++ b/src/qml/WatchfaceSelector.qml @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 - Timo Könnecke + * Copyright (C) 2026 - Timo Könnecke * 2022 - Darrel Griët * 2015 - Florent Revest * @@ -20,24 +20,26 @@ import QtQuick 2.9 import QtGraphicalEffects 1.12 import Qt.labs.folderlistmodel 2.1 +import Nemo.Configuration 1.0 import org.asteroid.controls 1.0 import org.asteroid.utils 1.0 -import Nemo.Configuration 1.0 +import org.asteroid.settings 1.0 import Nemo.Time 1.0 Item { id: watchfaceSelector + property bool storeAvailable: false + property string deletingName: "" + readonly property var previewSizes: [112, 128, 144, 160, 182] readonly property int idealPreviewSize: Math.round(Dims.w(40)) readonly property int previewSize: { let best = previewSizes[0]; let minDiff = Math.abs(best - idealPreviewSize); - for (let i = 1, n = previewSizes.length; i < n; ++i) { const size = previewSizes[i]; const diff = Math.abs(size - idealPreviewSize); - if (diff < minDiff || (diff === minDiff && size > best)) { minDiff = diff; best = size; @@ -46,154 +48,318 @@ Item { return best; } - GridView { - id: grid - cellWidth: Dims.w(50) - cellHeight: Dims.h(40) - anchors.fill: parent + ConfigurationValue { + id: activeWatchface + key: "/desktop/asteroid/watchface" + defaultValue: "file:///usr/share/asteroid-launcher/watchfaces/000-default-digital.qml" + } - model: FolderListModel { - id: folderModel - folder: assetPath + "watchfaces" - nameFilters: ["*.qml"] - onCountChanged: { - var i = 0 - while (i < folderModel.count){ - var fileName = folderModel.get(i, "fileName") - if(watchface === folderModel.folder + "/" + fileName) - grid.positionViewAtIndex(i, GridView.Center) - - i = i+1 - } - } + // ── Network probe + + Component.onCompleted: probeConnection() + + function probeConnection() { + var xhr = new XMLHttpRequest() + xhr.open("HEAD", "https://api.github.com") + xhr.timeout = 6000 + xhr.onreadystatechange = function() { + if (xhr.readyState !== XMLHttpRequest.DONE) return + watchfaceSelector.storeAvailable = (xhr.status > 0 && xhr.status < 500) } + xhr.send() + } - Item { - id: burnInProtectionManager + // ── Watchface store component - property int leftOffset - property int rightOffset - property int topOffset - property int bottomOffset - property int widthOffset - property int heightOffset - } + Component { + id: watchfaceStoreComponent + WatchfaceStorePage {} + } + + // ── Unified model from system + user watchface folders + + ListModel { id: unifiedModel } + + FolderListModel { + id: folderModel + folder: assetPath + "watchfaces" + nameFilters: ["*.qml"] + onCountChanged: rebuildTimer.restart() + } - WallClock { - id: wallClock - enabled: true - updateFrequency: WallClock.Second + FolderListModel { + id: userFolderModel + folder: "file://" + WatchfaceHelper.userWatchfacePath() + nameFilters: ["*.qml"] + onCountChanged: rebuildTimer.restart() + } + + Timer { + id: rebuildTimer + interval: 0 + repeat: false + onTriggered: _rebuildUnified() + } + + function _rebuildUnified() { + unifiedModel.clear() + var i, fn + for (i = 0; i < folderModel.count; i++) { + fn = folderModel.get(i, "fileName") + unifiedModel.append({ fileName: fn, filePath: assetPath + "watchfaces/" + fn, isUser: false }) + } + for (i = 0; i < userFolderModel.count; i++) { + fn = userFolderModel.get(i, "fileName") + unifiedModel.append({ fileName: fn, filePath: "file://" + WatchfaceHelper.userWatchfacePath() + fn, isUser: true }) } + for (i = 0; i < unifiedModel.count; i++) { + if (watchface === unifiedModel.get(i).filePath) { + grid.positionViewAtIndex(i, GridView.Center) + break + } + } + } + + // ── Removal remorse timer + +RemorseTimer { + id: deleteRemorse - QtObject { - id: localeManager - property string changesObserver: "" + property string watchfaceName: "" + + duration: 3000 + gaugeSegmentAmount: 8 + gaugeStartDegree: -130 + gaugeEndFromStartDegree: 265 + //% "Tap to cancel" + cancelText: qsTrId("id-tap-to-cancel") + + onTriggered: { + var targetPath = WatchfaceHelper.userAssetPath() + "watchfaces/" + watchfaceName + ".qml" + if (activeWatchface.value === targetPath) + activeWatchface.value = activeWatchface.defaultValue + WatchfaceHelper.removeWatchface(watchfaceName) + watchfaceSelector.deletingName = "" } - delegate: Component { + onCancelled: watchfaceSelector.deletingName = "" + } + + // ── Watchface grid + + GridView { + id: grid + cellWidth: Dims.w(50) + cellHeight: Dims.h(45) + anchors.fill: parent + model: unifiedModel + + Item { id: burnInProtectionManager; property int leftOffset; property int rightOffset; property int topOffset; property int bottomOffset; property int widthOffset; property int heightOffset } + WallClock { id: wallClock; enabled: true; updateFrequency: WallClock.Second } + QtObject { id: localeManager; property string changesObserver: "" } + + delegate: Component { Item { width: grid.cellWidth height: grid.cellHeight - + + property bool _pressActive: false + property bool _scrollCancelled: false + property bool _wasDeleting: false + readonly property bool isActive: watchface === model.filePath + + Rectangle { + id: pressCircle + width: Dims.l(40) + height: width + radius: width + anchors.centerIn: parent + color: "#000000" + opacity: isActive ? 0.2 : 0.0 + + NumberAnimation { id: pressAnim; target: pressCircle; property: "opacity"; to: 0.5; duration: 800; easing.type: Easing.Linear } + NumberAnimation { id: releaseAnim; target: pressCircle; property: "opacity"; duration: 150; easing.type: Easing.OutQuad } + } + + onIsActiveChanged: { + if (_pressActive) return + pressAnim.stop() + releaseAnim.stop() + releaseAnim.from = pressCircle.opacity + releaseAnim.to = isActive ? 0.2 : 0.0 + releaseAnim.start() + } + + Connections { + target: watchfaceSelector + function onDeletingNameChanged() { + var thisName = model.fileName.slice(0, -4) + if (watchfaceSelector.deletingName === thisName) { + _wasDeleting = true + } else if (_wasDeleting) { + _wasDeleting = false + pressAnim.stop() + releaseAnim.from = pressCircle.opacity + releaseAnim.to = isActive ? 0.2 : 0.0 + releaseAnim.start() + } + } + } + + Timer { + id: selectorHoldTimer + interval: 800 + repeat: false + onTriggered: { + if (!model.isUser) { + pressAnim.stop() + releaseAnim.from = pressCircle.opacity + releaseAnim.to = isActive ? 0.2 : 0.0 + releaseAnim.start() + return + } + watchfaceSelector.deletingName = model.fileName.slice(0, -4) + deleteRemorse.watchfaceName = model.fileName.slice(0, -4) + //% "Remove" + deleteRemorse.action = qsTrId("id-remove") + " " + model.fileName.slice(0, -4) + deleteRemorse.start() + } + } + Rectangle { id: maskArea - - width: Dims.w(40) - height: grid.cellHeight + width: Dims.l(40) + height: width anchors.centerIn: parent color: "transparent" - radius: DeviceSpecs.hasRoundScreen ? - width : - Dims.w(3) + radius: DeviceSpecs.hasRoundScreen ? width : Dims.l(3) clip: true - + Image { id: previewPng - - readonly property string previewFolder: `${assetPath}watchfaces-preview/${previewSize}/` - readonly property string previewImg: `${previewFolder}${fileName.slice(0, -4)}.png` - property bool previewExists: FileInfo.exists(previewImg) - + readonly property string sysPreviewImg: assetPath + "watchfaces-preview/" + previewSize + "/" + model.fileName.slice(0, -4) + ".png" + readonly property string userPreviewImg: WatchfaceHelper.userAssetPath() + "watchfaces-preview/" + previewSize + "/" + model.fileName.slice(0, -4) + ".png" + readonly property string cachePreviewImg: "file://" + WatchfaceHelper.cachePath() + previewSize + "/" + model.fileName.slice(0, -4) + ".png" + readonly property string previewImg: FileInfo.exists(sysPreviewImg) ? sysPreviewImg : FileInfo.exists(userPreviewImg) ? userPreviewImg : cachePreviewImg + property bool previewExists: FileInfo.exists(sysPreviewImg) || FileInfo.exists(userPreviewImg) || FileInfo.exists(cachePreviewImg) z: 1 anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: width - source: !previewExists ? "" : previewImg + source: previewExists ? previewImg : "" asynchronous: true fillMode: Image.PreserveAspectFit mipmap: true } - + Loader { id: previewQml - z: 2 visible: !previewPng.previewExists active: visible anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: width - source: folderModel.folder + "/" + fileName + source: model.filePath asynchronous: true } - + MouseArea { anchors.fill: parent - onClicked: watchface = folderModel.folder + "/" + fileName + property real startX: 0 + property real startY: 0 + + onPressed: { + startX = mouse.x + startY = mouse.y + _scrollCancelled = false + _pressActive = true + pressAnim.stop() + releaseAnim.stop() + pressAnim.from = pressCircle.opacity + pressAnim.start() + selectorHoldTimer.restart() + } + + onPositionChanged: { + if (_scrollCancelled) return + var dx = Math.abs(mouse.x - startX) + var dy = Math.abs(mouse.y - startY) + if (dx > Dims.l(2) || dy > Dims.l(2)) { + _scrollCancelled = true + _pressActive = false + selectorHoldTimer.stop() + pressAnim.stop() + releaseAnim.from = pressCircle.opacity + releaseAnim.to = isActive ? 0.2 : 0.0 + releaseAnim.start() + mouse.accepted = false + } + } + + onReleased: { + if (_scrollCancelled) return + selectorHoldTimer.stop() + pressAnim.stop() + if (watchfaceSelector.deletingName === "") + watchface = model.filePath + releaseAnim.from = pressCircle.opacity + releaseAnim.to = watchface === model.filePath ? 0.2 : 0.0 + releaseAnim.start() + _pressActive = false + _scrollCancelled = false + } + + onCanceled: { + selectorHoldTimer.stop() + pressAnim.stop() + _pressActive = false + _scrollCancelled = false + releaseAnim.from = pressCircle.opacity + releaseAnim.to = isActive ? 0.2 : 0.0 + releaseAnim.start() + } } - + Image { id: wallpaperBack - property string previewSizePath: "wallpapers/" + Dims.w(50) property string wallpaperPreviewImg: wallpaperSource.value.replace("\\wallpapers/full\\", previewSizePath).slice(0, -3) + "jpg" - z: 0 anchors.fill: parent fillMode: Image.PreserveAspectFit visible: opacity - opacity: watchface === folderModel.folder + "/" + fileName ? 1 : 0 - source: opacity > 0 ? FileInfo.exists(wallpaperPreviewImg) ? - wallpaperPreviewImg : - wallpaperSource.value : "" + opacity: watchface === model.filePath ? 1 : 0 + source: opacity > 0 ? FileInfo.exists(wallpaperPreviewImg) ? wallpaperPreviewImg : wallpaperSource.value : "" Behavior on opacity { NumberAnimation { duration: 100 } } } - + layer.enabled: true layer.effect: OpacityMask { - maskSource: - Rectangle { - anchors.centerIn: parent - width: Math.min(wallpaperBack.width, wallpaperBack.height) - height: width - radius: maskArea.radius - } + maskSource: Rectangle { + anchors.centerIn: parent + width: Math.min(wallpaperBack.width, wallpaperBack.height) + height: width + radius: maskArea.radius + } } } - + Icon { name: "ios-checkmark-circle" - z: 100 width: parent.width * .3 height: width - visible: watchface === folderModel.folder + "/" + fileName + visible: watchface === model.filePath anchors { bottom: parent.bottom - bottomMargin: DeviceSpecs.hasRoundScreen ? - -parent.height * .03 : - -parent.height * .08 + bottomMargin: DeviceSpecs.hasRoundScreen ? -parent.height * .03 : -parent.height * .08 horizontalCenter: parent.horizontalCenter horizontalCenterOffset: index % 2 ? - DeviceSpecs.hasRoundScreen ? - -parent.height * .45 : - -parent.height * .40 : - DeviceSpecs.hasRoundScreen ? - parent.height * .45 : - parent.height * .40 + (DeviceSpecs.hasRoundScreen ? -parent.height * .45 : -parent.height * .40) : + (DeviceSpecs.hasRoundScreen ? parent.height * .45 : parent.height * .40) } - layer.enabled: visible layer.effect: DropShadow { transparentBorder: true @@ -206,5 +372,49 @@ Item { } } } + + // ── "Get More" footer + + footer: Column { + width: grid.width + + Item { width: parent.width; height: Dims.l(4) } + + RowSeparator {} + + Item { + width: parent.width + height: Dims.h(32) + opacity: watchfaceSelector.storeAvailable ? 1.0 : 0.45 + + Column { + anchors.centerIn: parent + + Icon { + name: "ios-cloud-download-outline" + width: Dims.l(12) + height: width + anchors.horizontalCenter: parent.horizontalCenter + } + + Label { + width: Dims.l(70) + horizontalAlignment: Text.AlignHCenter + text: watchfaceSelector.storeAvailable ? + //% "Get More Watchfaces" + qsTrId("id-get-more-watchfaces") : + //% "Connect to get more watchfaces" + qsTrId("id-connect-for-watchfaces") + font { pixelSize: Dims.l(8); family: "Noto Sans"; styleName: "SemiCondensed SemiBold" } + anchors.horizontalCenter: parent.horizontalCenter + } + } + + HighlightBar { + enabled: watchfaceSelector.storeAvailable + onClicked: layerStack.push(watchfaceStoreComponent, { assetPath: assetPath, previewSize: watchfaceSelector.previewSize }) + } + } + } } } diff --git a/src/qml/WatchfaceStorePage.qml b/src/qml/WatchfaceStorePage.qml new file mode 100644 index 00000000..d3b6e43d --- /dev/null +++ b/src/qml/WatchfaceStorePage.qml @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2026 - Timo Könnecke + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.9 +import QtGraphicalEffects 1.12 +import Qt.labs.folderlistmodel 2.1 +import Nemo.Configuration 1.0 +import org.asteroid.controls 1.0 +import org.asteroid.utils 1.0 +import org.asteroid.settings 1.0 + +Item { + id: storePage + + property string assetPath: "file:///usr/share/asteroid-launcher/" + property int previewSize: 128 + + property bool loadingCatalog: true + property string downloadingName: "" + property bool restartPending: false + property int cacheVersion: 0 + property int _pendingFiles: 0 + property int _inFlightXhrs: 0 + property var _pendingPreviews: ({}) + property string deletingName: "" + property string installingName: "" + property string failedName: "" + property bool _restartFired: false + + readonly property string _cacheBase: WatchfaceHelper.cachePath() + readonly property string _catalogCache: WatchfaceHelper.cachePath() + "catalog.json" + readonly property string _apiBase: "https://api.github.com/repos/AsteroidOS/unofficial-watchfaces/contents/" + readonly property string _rawBase: "https://raw.githubusercontent.com/AsteroidOS/unofficial-watchfaces/master/" + + ConfigurationValue { + id: activeWatchface + key: "/desktop/asteroid/watchface" + defaultValue: "file:///usr/share/asteroid-launcher/watchfaces/000-default-digital.qml" + } + + ListModel { id: storeModel } + + Component.onCompleted: { + var cached = WatchfaceHelper.readFile(_catalogCache) + if (cached) { + try { + loadingCatalog = false + _addCommunityWatchfaces(JSON.parse(cached)) + } catch(e) { + _fetchCatalog() + } + } else { + _fetchCatalog() + } + } + + // ── Grid + + GridView { + id: storeGrid + anchors { + top: parent.top + // ── Margin to offset list from PageHeader + topMargin: title.height + bottom: parent.bottom + left: parent.left + right: parent.right + } + cellWidth: Dims.w(50) + cellHeight: Dims.h(45) + + model: storeModel + + delegate: Item { + width: storeGrid.cellWidth + height: storeGrid.cellHeight + + property bool _pressActive: false + property bool _scrollCancelled: false + property bool _wasDeleting: false + readonly property bool isInstalling: storePage.installingName === model.name + + onIsInstallingChanged: { + if (!isInstalling && model.isInstalled) + bumpAnim.start() + } + + Rectangle { + id: stateBg + width: Dims.l(40) + height: width + radius: width + anchors.centerIn: parent + color: model.isInstalled ? "#44ff88" : "#000000" + opacity: model.isInstalled ? 0.5 : 0.2 + + NumberAnimation { id: opacityAnim; target: stateBg; property: "opacity"; easing.type: Easing.OutQuad } + ColorAnimation { id: colorAnim; target: stateBg; property: "color"; easing.type: Easing.OutQuad } + + SequentialAnimation { + id: bumpAnim + NumberAnimation { target: stateBg; property: "opacity"; to: 0.65; duration: 120; easing.type: Easing.OutQuad } + NumberAnimation { target: stateBg; property: "opacity"; to: 0.5; duration: 200; easing.type: Easing.InQuad } + } + + SequentialAnimation { + id: failAnim + ColorAnimation { target: stateBg; property: "color"; to: "#ff4444"; duration: 200 } + PauseAnimation { duration: 1200 } + ColorAnimation { target: stateBg; property: "color"; to: "#000000"; duration: 400 } + NumberAnimation { target: stateBg; property: "opacity"; to: 0.2; duration: 300 } + onStopped: storePage.failedName = "" + } + } + + Connections { + target: storePage + function onFailedNameChanged() { + if (storePage.failedName === model.name) failAnim.start() + } + function onDeletingNameChanged() { + if (model.isInstalled) { + if (storePage.deletingName === model.name) { + _wasDeleting = true + } else if (_wasDeleting) { + _wasDeleting = false + opacityAnim.stop() + opacityAnim.from = stateBg.opacity + opacityAnim.to = 0.5 + opacityAnim.duration = 200 + opacityAnim.start() + } + } + } + } + + Timer { + id: storeHoldTimer + interval: 800 + repeat: false + onTriggered: { + if (!model.isInstalled) return + storePage.deletingName = model.name + removeRemorse.watchfaceName = model.name + //% "Remove" + removeRemorse.action = qsTrId("id-remove") + " " + model.name + removeRemorse.start() + } + } + + Rectangle { + id: storeItemMask + width: Dims.l(40) + height: width + anchors.centerIn: parent + color: "transparent" + radius: DeviceSpecs.hasRoundScreen ? width : Dims.l(3) + clip: true + + Image { + id: storePreview + anchors.centerIn: parent + width: Math.min(parent.width, parent.height) + height: width + asynchronous: true + fillMode: Image.PreserveAspectFit + mipmap: true + opacity: model.isInstalled ? 1.0 : 0.7 + + source: { + var _cv = storePage.cacheVersion + if (model.isInstalled) + return WatchfaceHelper.userAssetPath() + "watchfaces-preview/" + storePage.previewSize + "/" + model.name + ".png" + var cacheDest = storePage._cacheBase + storePage.previewSize + "/" + model.name + ".png" + return FileInfo.exists(cacheDest) ? "file://" + cacheDest : "" + } + + Component.onCompleted: { + if (!model.isInstalled) + storePage._ensurePreview(model.name) + } + } + + MouseArea { + anchors.fill: parent + property real startX: 0 + property real startY: 0 + + onPressed: { + startX = mouse.x + startY = mouse.y + _scrollCancelled = false + _pressActive = true + bumpAnim.stop() + failAnim.stop() + opacityAnim.stop() + colorAnim.stop() + if (model.isInstalled) { + opacityAnim.from = stateBg.opacity + opacityAnim.to = 0.0 + opacityAnim.duration = 800 + opacityAnim.easing.type = Easing.Linear + opacityAnim.start() + storeHoldTimer.restart() + } else if (storePage.downloadingName === "") { + colorAnim.from = stateBg.color + colorAnim.to = "#44ff88" + colorAnim.duration = 300 + colorAnim.start() + opacityAnim.from = stateBg.opacity + opacityAnim.to = 0.35 + opacityAnim.duration = 300 + opacityAnim.easing.type = Easing.OutQuad + opacityAnim.start() + } + } + + onPositionChanged: { + if (_scrollCancelled) return + var dx = Math.abs(mouse.x - startX) + var dy = Math.abs(mouse.y - startY) + if (dx > Dims.l(2) || dy > Dims.l(2)) { + _scrollCancelled = true + _pressActive = false + storeHoldTimer.stop() + opacityAnim.stop() + colorAnim.stop() + colorAnim.from = stateBg.color + colorAnim.to = model.isInstalled ? "#44ff88" : "#000000" + colorAnim.duration = 150 + colorAnim.start() + opacityAnim.from = stateBg.opacity + opacityAnim.to = model.isInstalled ? 0.5 : 0.2 + opacityAnim.duration = 150 + opacityAnim.easing.type = Easing.OutQuad + opacityAnim.start() + mouse.accepted = false + } + } + + onReleased: { + if (_scrollCancelled) return + storeHoldTimer.stop() + _pressActive = false + _scrollCancelled = false + if (!model.isInstalled && storePage.downloadingName === "") { + // keep animating toward full green — do not stop + colorAnim.stop() + opacityAnim.stop() + colorAnim.from = stateBg.color + colorAnim.to = "#44ff88" + colorAnim.duration = 300 + colorAnim.start() + opacityAnim.from = stateBg.opacity + opacityAnim.to = 0.5 + opacityAnim.duration = 300 + opacityAnim.easing.type = Easing.OutQuad + opacityAnim.start() + storePage._startDownload(model.name) + } else if (model.isInstalled && storePage.deletingName === "") { + opacityAnim.stop() + opacityAnim.from = stateBg.opacity + opacityAnim.to = 0.5 + opacityAnim.duration = 200 + opacityAnim.easing.type = Easing.OutQuad + opacityAnim.start() + } + } + + onCanceled: { + storeHoldTimer.stop() + _pressActive = false + _scrollCancelled = false + opacityAnim.stop() + colorAnim.stop() + colorAnim.from = stateBg.color + colorAnim.to = model.isInstalled ? "#44ff88" : "#000000" + colorAnim.duration = 200 + colorAnim.start() + opacityAnim.from = stateBg.opacity + opacityAnim.to = model.isInstalled ? 0.5 : 0.2 + opacityAnim.duration = 200 + opacityAnim.easing.type = Easing.OutQuad + opacityAnim.start() + } + } + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + anchors.centerIn: parent + width: Math.min(storePreview.width, storePreview.height) + height: width + radius: storeItemMask.radius + } + } + } + + Icon { + name: "ios-checkmark-circle" + z: 100 + width: parent.width * .3 + height: width + visible: activeWatchface.value === WatchfaceHelper.userAssetPath() + "watchfaces/" + model.name + ".qml" + anchors { + bottom: parent.bottom + bottomMargin: DeviceSpecs.hasRoundScreen ? -parent.height * .03 : -parent.height * .08 + horizontalCenter: parent.horizontalCenter + horizontalCenterOffset: index % 2 ? + (DeviceSpecs.hasRoundScreen ? -parent.height * .45 : -parent.height * .40) : + (DeviceSpecs.hasRoundScreen ? parent.height * .45 : parent.height * .40) + } + layer.enabled: visible + layer.effect: DropShadow { + transparentBorder: true + horizontalOffset: 2 + verticalOffset: 2 + radius: 8.0 + samples: 17 + color: "#88000000" + } + } + } + + // ── Footer: restart + refresh + + footer: Column { + width: storeGrid.width + + Item { width: parent.width; height: Dims.l(4) } + + RowSeparator {} + + Item { + width: parent.width + height: Dims.h(32) + + Column { + anchors.centerIn: parent + + Icon { + name: "ios-cloud-download-outline" + width: Dims.l(12) + height: width + anchors.horizontalCenter: parent.horizontalCenter + } + + Label { + width: Dims.l(70) + horizontalAlignment: Text.AlignHCenter + //% "Refresh store" + text: qsTrId("id-refresh-store") + font { pixelSize: Dims.l(8); family: "Noto Sans"; styleName: "SemiCondensed SemiBold" } + anchors.horizontalCenter: parent.horizontalCenter + } + } + + HighlightBar { onClicked: _fetchCatalog() } + } + + RowSeparator {} + + Item { + width: parent.width + height: Dims.h(32) + + Column { + anchors.centerIn: parent + spacing: Dims.l(1) + + Icon { + name: "ios-refresh" + width: Dims.l(12) + height: width + anchors.horizontalCenter: parent.horizontalCenter + } + + Label { + width: Dims.l(70) + horizontalAlignment: Text.AlignHCenter + //% "Restart launcher" + text: qsTrId("id-restart-launcher") + font { pixelSize: Dims.l(8); family: "Noto Sans"; styleName: "SemiCondensed SemiBold" } + anchors.horizontalCenter: parent.horizontalCenter + } + } + + HighlightBar { onClicked: restartRemorse.start() } + } + } + } + + // ── Loading indicator + + Label { + anchors.centerIn: parent + visible: loadingCatalog && storeModel.count === 0 + //% "Loading..." + text: qsTrId("id-loading") + font { pixelSize: Dims.l(6); styleName: "Light" } + color: "#80ffffff" + } + + // ── Page header + + PageHeader { + id: title + //% "Watchface Store" + text: qsTrId("id-watchface-store") + } + + // ── Removal remorse timer + + RemorseTimer { + id: removeRemorse + + property string watchfaceName: "" + + duration: 3000 + gaugeSegmentAmount: 8 + gaugeStartDegree: -130 + gaugeEndFromStartDegree: 265 + //% "Tap to cancel" + cancelText: qsTrId("id-tap-to-cancel") + + onTriggered: { + var targetPath = WatchfaceHelper.userAssetPath() + "watchfaces/" + watchfaceName + ".qml" + if (activeWatchface.value === targetPath) + activeWatchface.value = activeWatchface.defaultValue + if (WatchfaceHelper.removeWatchface(watchfaceName)) { + for (var i = 0; i < storeModel.count; i++) { + if (storeModel.get(i).name === watchfaceName) { + storeModel.setProperty(i, "isInstalled", false) + break + } + } + } + storePage.deletingName = "" + } + + onCancelled: storePage.deletingName = "" + } + + // ── Launcher restart remorse timer with full black cut off before restart + + Rectangle { + anchors.fill: parent + color: "#000000" + opacity: _restartFired ? 0.92 : restartRemorse.opacity * 0.92 + visible: opacity > 0 + } + + RemorseTimer { + id: restartRemorse + duration: 4000 + gaugeSegmentAmount: 6 + gaugeStartDegree: -130 + gaugeEndFromStartDegree: 265 + //% "Restart launcher" + action: qsTrId("id-restart-launcher") + //% "Tap to cancel" + cancelText: qsTrId("id-tap-to-cancel") + onTriggered: { + storePage._restartFired = true + WatchfaceHelper.restartSession() + } + } + + // ── WatchfaceHelper connections + + Connections { + target: WatchfaceHelper + + function onDownloadComplete(destPath, success) { + if (destPath.startsWith(storePage._cacheBase)) { + if (!success) { + var cacheName = destPath.split("/").pop().replace(".png", "") + for (var i = 0; i < storeModel.count; i++) { + if (storeModel.get(i).name === cacheName) { storeModel.remove(i); break } + } + } else { + storePage.cacheVersion++ + } + return + } + if (storePage.downloadingName !== "") { + if (!success) { + console.warn("WatchfaceStorePage: download failed:", destPath) + if (destPath.endsWith(".qml")) + storePage.failedName = storePage.downloadingName + } + storePage._pendingFiles-- + storePage._checkInstallComplete() + } + } + } + + // ── Private functions + + function _fetchCatalog() { + loadingCatalog = true + storeModel.clear() + var xhr = new XMLHttpRequest() + xhr.open("GET", _apiBase) + xhr.timeout = 10000 + xhr.onreadystatechange = function() { + if (xhr.readyState !== XMLHttpRequest.DONE) return + loadingCatalog = false + if (xhr.status !== 200) { + console.warn("WatchfaceStorePage: catalog fetch failed, status", xhr.status) + return + } + try { + var text = xhr.responseText + WatchfaceHelper.writeFile(_catalogCache, text) + _addCommunityWatchfaces(JSON.parse(text)) + } catch(e) { + console.warn("WatchfaceStorePage: catalog parse error:", e) + } + } + xhr.send() + } + + function _addCommunityWatchfaces(catalog) { + var skipList = { "tests": true, "fake-components": true } + for (var j = 0; j < catalog.length; j++) { + var entry = catalog[j] + if (entry.type !== "dir") continue + if (entry.name[0] === ".") continue + if (skipList[entry.name]) continue + var isInstalled = FileInfo.exists(WatchfaceHelper.userWatchfacePath() + entry.name + ".qml") + storeModel.append({ name: entry.name, isInstalled: isInstalled }) + } + } + + function _ensurePreview(name) { + if (_pendingPreviews[name]) return + var cacheDest = _cacheBase + previewSize + "/" + name + ".png" + if (FileInfo.exists(cacheDest)) return + _pendingPreviews[name] = true + WatchfaceHelper.mkpath(_cacheBase + previewSize) + WatchfaceHelper.downloadFile( + _rawBase + name + "/usr/share/asteroid-launcher/watchfaces-preview/" + previewSize + "/" + name + ".png", + cacheDest) + } + + function _startDownload(name) { + if (downloadingName !== "") return + downloadingName = name + installingName = name + _pendingFiles = 0 + _inFlightXhrs = 0 + + var userBase = WatchfaceHelper.userWatchfacePath() + var userRoot = userBase.substring(0, userBase.lastIndexOf("watchfaces/")) + + _queueDownload( + _rawBase + name + "/usr/share/asteroid-launcher/watchfaces/" + name + ".qml", + userBase + name + ".qml") + _queueDownload( + _rawBase + name + "/usr/share/asteroid-launcher/watchfaces-preview/" + previewSize + "/" + name + ".png", + userRoot + "watchfaces-preview/" + previewSize + "/" + name + ".png") + _fetchDirectory( + _apiBase + name + "/usr/share/asteroid-launcher/watchfaces-img/", + userRoot + "watchfaces-img/", + false) + _fetchDirectory( + _apiBase + name + "/usr/share/fonts/", + WatchfaceHelper.userFontsPath(), + true) + } + + function _queueDownload(url, dest) { + _pendingFiles++ + WatchfaceHelper.mkpath(dest.substring(0, dest.lastIndexOf("/"))) + WatchfaceHelper.downloadFile(url, dest) + } + + function _fetchDirectory(apiUrl, destPrefix, isFont) { + _inFlightXhrs++ + var xhr = new XMLHttpRequest() + xhr.open("GET", apiUrl) + xhr.timeout = 10000 + xhr.onreadystatechange = function() { + if (xhr.readyState !== XMLHttpRequest.DONE) return + _inFlightXhrs-- + if (xhr.status === 200) { + try { + var files = JSON.parse(xhr.responseText) + for (var i = 0; i < files.length; i++) { + if (files[i].type === "file") + _queueDownload(files[i].download_url, destPrefix + files[i].name) + } + } catch(e) { + console.warn("WatchfaceStorePage: directory parse error:", e) + } + } + _checkInstallComplete() + } + xhr.send() + } + + function _checkInstallComplete() { + if (_pendingFiles !== 0 || _inFlightXhrs !== 0) return + if (downloadingName === "") return + + var name = downloadingName + downloadingName = "" + + if (storePage.failedName !== name) { + for (var i = 0; i < storeModel.count; i++) { + if (storeModel.get(i).name === name) { + storeModel.setProperty(i, "isInstalled", true) + break + } + } + activeWatchface.value = WatchfaceHelper.userAssetPath() + "watchfaces/" + name + ".qml" + restartPending = true + } + installingName = "" + } +} diff --git a/src/resources.qrc b/src/resources.qrc index b4bafbb7..734d2b55 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -15,6 +15,7 @@ qml/WallpaperPage.qml qml/WatchfacePage.qml qml/WatchfaceSelector.qml + qml/WatchfaceStorePage.qml qml/LauncherPage.qml qml/USBPage.qml qml/PowerPage.qml From e89b61a76ebc712879a1e4c0283bcf1263a9779d Mon Sep 17 00:00:00 2001 From: moWerk Date: Tue, 31 Mar 2026 21:54:17 +0200 Subject: [PATCH 3/5] Add wallpaper download support to WatchfaceStorePage Community watchfaces that ship a custom wallpaper now have it fetched into the XDG user wallpapers folder during install. The existing _fetchDirectory call pattern handles all file types in the wallpapers/full/ folder including jpg, png and svg. --- src/qml/WatchfaceStorePage.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qml/WatchfaceStorePage.qml b/src/qml/WatchfaceStorePage.qml index d3b6e43d..8102ec09 100644 --- a/src/qml/WatchfaceStorePage.qml +++ b/src/qml/WatchfaceStorePage.qml @@ -578,6 +578,10 @@ Item { _apiBase + name + "/usr/share/asteroid-launcher/watchfaces-img/", userRoot + "watchfaces-img/", false) + _fetchDirectory( + _apiBase + name + "/usr/share/asteroid-launcher/wallpapers/full/", + userRoot + "wallpapers/full/", + false) _fetchDirectory( _apiBase + name + "/usr/share/fonts/", WatchfaceHelper.userFontsPath(), From cada5f30e84d662c54384b24aa34541997c79bea Mon Sep 17 00:00:00 2001 From: moWerk Date: Wed, 1 Apr 2026 00:09:22 +0200 Subject: [PATCH 4/5] Update translations using lupdate-qt5 and complete english and german translation --- i18n/asteroid-settings.ar.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.az.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.be.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.ca.ts | 33 +++++++++++-- i18n/asteroid-settings.cs.ts | 31 ++++++++++-- i18n/asteroid-settings.da.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.de_DE.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.el.ts | 29 ++++++++++- i18n/asteroid-settings.en_GB.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.eo.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.es.ts | 81 ++++++++++++++++++++++--------- i18n/asteroid-settings.es_AR.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.fa.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.fi.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.fr.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.gl.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.he.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.hi.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.hr.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.hu.ts | 29 ++++++++++- i18n/asteroid-settings.ia.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.id.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.it.ts | 29 ++++++++++- i18n/asteroid-settings.ja.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.ka.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.ko.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.lb.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.lt.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.mr.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.ms.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.nb_NO.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.nl_BE.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.nl_NL.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.oc.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.pl.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.pt.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.pt_BR.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.pt_PT.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.ro.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.ru.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.sk.ts | 29 ++++++++++- i18n/asteroid-settings.sq.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.sv.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.ta.ts | 29 ++++++++++- i18n/asteroid-settings.te.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.th.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.tr.ts | 31 ++++++++++-- i18n/asteroid-settings.uk.ts | 79 +++++++++++++++++++++--------- i18n/asteroid-settings.vi.ts | 77 +++++++++++++++++++++-------- i18n/asteroid-settings.zh_Hans.ts | 29 ++++++++++- i18n/asteroid-settings.zh_Hant.ts | 77 +++++++++++++++++++++-------- 51 files changed, 2612 insertions(+), 917 deletions(-) diff --git a/i18n/asteroid-settings.ar.ts b/i18n/asteroid-settings.ar.ts index dd517f9e..1abf4b32 100644 --- a/i18n/asteroid-settings.ar.ts +++ b/i18n/asteroid-settings.ar.ts @@ -83,60 +83,60 @@ بلوتوث - + Display العرض - + Brightness السطوع - + Off - + High - + Medium - + Low - + Automatic brightness سطوع تلقائي - - + + Always on Display دائمة الظهور - + Burn-in Protection Burn in protection الحماية من الاحتراق - + Tilt-to-wake إمالة للإيقاظ - + Tap-to-wake انقر للاستيقاظ @@ -153,7 +153,7 @@ - + Nightstand منضدة السرير @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ حول - + Enable تمكين - + Brightness Nightstand Brightness السطوع - + Delay Nightstand delay التأخير - + Custom watchface واجهة شاشة مخصصة - + Select watchface select nightstand watchface اختر واجهة الساعة @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.az.ts b/i18n/asteroid-settings.az.ts index 651ade80..ca2d2fb9 100644 --- a/i18n/asteroid-settings.az.ts +++ b/i18n/asteroid-settings.az.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Ekran - + Brightness Parlaqlıq - + Off - + High - + Medium - + Low - + Automatic brightness Avtomatik parlaqlıq - - + + Always on Display Həmişə açıq Ekran - + Burn-in Protection Burn in protection Ekran yanığı qorunması - + Tilt-to-wake Əyərək oyandırın - + Tap-to-wake Toxunaraq oyandır @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Haqqında - + Enable Aktivləşdirin - + Brightness Nightstand Brightness Parlaqlıq - + Delay Nightstand delay Gecikmə - + Custom watchface - + Select watchface select nightstand watchface Saat ekranı seç @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.be.ts b/i18n/asteroid-settings.be.ts index 2bdbfd17..8a6bc93b 100644 --- a/i18n/asteroid-settings.be.ts +++ b/i18n/asteroid-settings.be.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Дысплэй - + Brightness Яркасць - + Off - + High - + Medium - + Low - + Automatic brightness Аўтаматычная яркасць - - + + Always on Display Заўсёды на дысплэі - + Burn-in Protection Burn in protection Абарона ад выгарання - + Tilt-to-wake Абуджэнне па нахілу - + Tap-to-wake Абуджэнне па націску @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Інфармацыя - + Enable Уключыць - + Brightness Nightstand Brightness Яркасць - + Delay Nightstand delay Затрымка - + Custom watchface Наладжвальны цыферблат - + Select watchface select nightstand watchface Выбар цыферблата @@ -366,10 +369,42 @@ Enable colored battery? Уключыць колеры батарэі? - - - Settings - Налады + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.ca.ts b/i18n/asteroid-settings.ca.ts index aae3afbd..9bacdf28 100644 --- a/i18n/asteroid-settings.ca.ts +++ b/i18n/asteroid-settings.ca.ts @@ -88,10 +88,6 @@ About Quant a - - Settings - Paràmetres - Charging only Només càrrega @@ -264,6 +260,7 @@ Tap to cancel + Off @@ -281,6 +278,34 @@ Low + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store + + AboutPage diff --git a/i18n/asteroid-settings.cs.ts b/i18n/asteroid-settings.cs.ts index 8cd49a2f..2f23e4ad 100644 --- a/i18n/asteroid-settings.cs.ts +++ b/i18n/asteroid-settings.cs.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,9 +278,33 @@ Low - - Settings - Nastavení + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store + diff --git a/i18n/asteroid-settings.da.ts b/i18n/asteroid-settings.da.ts index fa1a6cda..4ad402ac 100644 --- a/i18n/asteroid-settings.da.ts +++ b/i18n/asteroid-settings.da.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Skærm - + Brightness Lysstyrke - + Off - + High - + Medium - + Low - + Automatic brightness Automatisk lysstyrke - - + + Always on Display Skærm altid tændt - + Burn-in Protection Burn in protection Beskyttelse mod fastbrænding - + Tilt-to-wake Tilt-for-at-vågne - + Tap-to-wake Tryk-for-at-vække @@ -153,7 +153,7 @@ - + Nightstand Natbord @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Om - + Enable Aktiver - + Brightness Nightstand Brightness Lysstyrke - + Delay Nightstand delay Forsinke - + Custom watchface Tilpasset urskive - + Select watchface select nightstand watchface Vælg urskive @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.de_DE.ts b/i18n/asteroid-settings.de_DE.ts index e42f55ad..d5ab4824 100644 --- a/i18n/asteroid-settings.de_DE.ts +++ b/i18n/asteroid-settings.de_DE.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Bildschirm - + Brightness Helligkeit - + Off Aus - + High Hoch - + Medium Mittel - + Low Niedrig - + Automatic brightness Automatische Helligkeit - - + + Always on Display Immer aktiver Bildschirm (AOD) - + Burn-in Protection Burn in protection Einbrennschutz - + Tilt-to-wake Neigen zum Aufwachen - + Tap-to-wake Tippen zum Aufwachen @@ -153,7 +153,7 @@ - + Nightstand Nachttisch @@ -213,6 +213,9 @@ + + + Tap to cancel Drücken bricht ab @@ -222,29 +225,29 @@ Über - + Enable Aktivieren - + Brightness Nightstand Brightness Helligkeit - + Delay Nightstand delay Verzögerung - + Custom watchface Benutzerdefiniertes Zifferblatt - + Select watchface select nightstand watchface Zifferblatt wählen @@ -366,10 +369,42 @@ Enable colored battery? Farbige Batterie Anzeige? - - - Settings - Einstellungen + + + + Remove + Entfernen + + + + Get More Watchfaces + Mehr Ziffernblätter + + + + Connect to get more watchfaces + Mehr Ziffernblätter + + + + Refresh store + Neu laden + + + + + Restart launcher + Launcher Neustarten + + + + Loading... + Lade... + + + + Watchface Store + Herunterladen diff --git a/i18n/asteroid-settings.el.ts b/i18n/asteroid-settings.el.ts index 25adcf35..ec0321a0 100644 --- a/i18n/asteroid-settings.el.ts +++ b/i18n/asteroid-settings.el.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,8 +278,32 @@ Low - - Settings + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store diff --git a/i18n/asteroid-settings.en_GB.ts b/i18n/asteroid-settings.en_GB.ts index e3282d1c..01dfe694 100644 --- a/i18n/asteroid-settings.en_GB.ts +++ b/i18n/asteroid-settings.en_GB.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Display - + Brightness Brightness - + Off Off - + High High - + Medium Medium - + Low Low - + Automatic brightness Automatic brightness - - + + Always on Display Always on Display - + Burn-in Protection Burn in protection Burn in protection - + Tilt-to-wake Tilt-to-wake - + Tap-to-wake Tap-to-wake @@ -153,7 +153,7 @@ - + Nightstand Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel Tap to cancel @@ -222,29 +225,29 @@ About - + Enable Enable - + Brightness Nightstand Brightness Brightness - + Delay Nightstand delay Delay - + Custom watchface Custom watchface - + Select watchface select nightstand watchface Select watchface @@ -366,10 +369,42 @@ Enable colored battery? Enable colored battery fill? - - - Settings - Settings + + + + Remove + Remove + + + + Get More Watchfaces + Get More Watchfaces + + + + Connect to get more watchfaces + Connect to get more watchfaces + + + + Refresh store + Refresh store + + + + + Restart launcher + Restart launcher + + + + Loading... + Loading... + + + + Watchface Store + Watchface Store diff --git a/i18n/asteroid-settings.eo.ts b/i18n/asteroid-settings.eo.ts index e3ae8f7c..e3c20cc0 100644 --- a/i18n/asteroid-settings.eo.ts +++ b/i18n/asteroid-settings.eo.ts @@ -83,60 +83,60 @@ Bludento - + Display Ekrano - + Brightness Brilo - + Off - + High - + Medium - + Low - + Automatic brightness Aŭtomate adapti brilon - - + + Always on Display Ĉiam aktiva ekrano - + Burn-in Protection Burn in protection enbrulada protekto - + Tilt-to-wake Klini por veki - + Tap-to-wake Tuŝi por veki @@ -153,7 +153,7 @@ - + Nightstand Noktotablo @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Pri - + Enable Ebligi - + Brightness Nightstand Brightness Brileco - + Delay Nightstand delay Prokrastu - + Custom watchface Propra ciferplata aspekto - + Select watchface select nightstand watchface Elekti ciferplata aspekto @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.es.ts b/i18n/asteroid-settings.es.ts index 73619d8d..b9f2096b 100644 --- a/i18n/asteroid-settings.es.ts +++ b/i18n/asteroid-settings.es.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Pantalla - + Brightness Brillo - + Off - + High - + Medium - + Low - + Automatic brightness Brillo automático - - + + Always on Display Pantalla siempre encendida - + Burn-in Protection Burn in protection Protección contra imagen fantasma - + Tilt-to-wake Inclinar para encender - + Tap-to-wake Tocar para encender @@ -153,7 +153,7 @@ - + Nightstand Mesa de noche @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -221,35 +224,30 @@ About Acerca de - - - Settings - Configuración - - + Enable Activar - + Brightness Nightstand Brightness Brillo - + Delay Nightstand delay Retraso - + Custom watchface Esfera personalizada - + Select watchface select nightstand watchface Seleccione la esfera del reloj @@ -371,6 +369,43 @@ Enable colored battery? + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + + AboutPage diff --git a/i18n/asteroid-settings.es_AR.ts b/i18n/asteroid-settings.es_AR.ts index 0ab9c59b..3c5c6287 100644 --- a/i18n/asteroid-settings.es_AR.ts +++ b/i18n/asteroid-settings.es_AR.ts @@ -83,60 +83,60 @@ - + Display Pantalla - + Brightness Brillo - + Off - + High - + Medium - + Low - + Automatic brightness Brillo automático - - + + Always on Display Pantalla siempre activa - + Burn-in Protection Burn in protection Protección contra pantalla fantasma - + Tilt-to-wake Inclinar para activar - + Tap-to-wake Tocar para activar @@ -153,7 +153,7 @@ - + Nightstand Mesita de luz @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Acerca de - + Enable Activar - + Brightness Nightstand Brightness Brillo - + Delay Nightstand delay Demora - + Custom watchface Carátula personalizada - + Select watchface select nightstand watchface Elige una carátula @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.fa.ts b/i18n/asteroid-settings.fa.ts index b075d757..cf4aa76d 100644 --- a/i18n/asteroid-settings.fa.ts +++ b/i18n/asteroid-settings.fa.ts @@ -83,60 +83,60 @@ بلوتوث - + Display صفحهٔ نمایش - + Brightness روشنایی - + Off - + High - + Medium - + Low - + Automatic brightness روشنایی خودکار - - + + Always on Display صفحهٔ همواره روشن - + Burn-in Protection Burn in protection محافظت از سوختن - + Tilt-to-wake چرخاندن برای بیداری - + Tap-to-wake ضربه برای بیداری @@ -153,7 +153,7 @@ - + Nightstand پایهٔ شبانه @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ درباره - + Enable به کار انداختن - + Brightness Nightstand Brightness روشنایی - + Delay Nightstand delay تأخیر - + Custom watchface صفحهٔ ساعت شخصی - + Select watchface select nightstand watchface گزینش صفحهٔ ساعت @@ -366,10 +369,42 @@ Enable colored battery? به کار انداختن باتری رنگی؟ - - - Settings - تنظیمات + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.fi.ts b/i18n/asteroid-settings.fi.ts index f589da43..6a204b39 100644 --- a/i18n/asteroid-settings.fi.ts +++ b/i18n/asteroid-settings.fi.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Näyttö - + Brightness Kirkkaus - + Off - + High - + Medium - + Low - + Automatic brightness Automaattinen kirkkaus - - + + Always on Display Tyyni näyttö (ei sammu) - + Burn-in Protection Burn in protection Burn-in suojaus - + Tilt-to-wake Nosta herättääksesi puhelin - + Tap-to-wake Napauta herättääksesi puhelin @@ -153,7 +153,7 @@ - + Nightstand Yöpöytä @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Tietoa - + Enable Ota käyttöön - + Brightness Nightstand Brightness Kirkkaus - + Delay Nightstand delay Viive - + Custom watchface Mukautettu kellon ilme - + Select watchface select nightstand watchface Valitse kellon ilme @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.fr.ts b/i18n/asteroid-settings.fr.ts index 7392e7eb..366277b9 100644 --- a/i18n/asteroid-settings.fr.ts +++ b/i18n/asteroid-settings.fr.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Écran - + Brightness Luminosité - + Off - + High - + Medium - + Low - + Automatic brightness Luminosité automatique - - + + Always on Display Toujours allumé - + Burn-in Protection Burn in protection Prévention des brûlures d'écran - + Tilt-to-wake Incliner pour réveiller - + Tap-to-wake Tapoter pour réveiller @@ -153,7 +153,7 @@ - + Nightstand Table de nuit @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ À propos - + Enable Activer - + Brightness Nightstand Brightness Luminosité - + Delay Nightstand delay Délai - + Custom watchface Cadran personnalisé - + Select watchface select nightstand watchface Sélectionner le cadran @@ -366,10 +369,42 @@ Enable colored battery? Activer batterie colorée ? - - - Settings - Paramètres + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.gl.ts b/i18n/asteroid-settings.gl.ts index 6dba6d51..bf7c675d 100644 --- a/i18n/asteroid-settings.gl.ts +++ b/i18n/asteroid-settings.gl.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Pantalla - + Brightness Luminosidade - + Off - + High - + Medium - + Low - + Automatic brightness Brillo automático - - + + Always on Display Pantalla sempre acesa - + Burn-in Protection Burn in protection Protección contra queimaduras - + Tilt-to-wake Inclinar para prender - + Tap-to-wake Tocar para despertar @@ -153,7 +153,7 @@ - + Nightstand Mesita de noite @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Acerca de - + Enable Activar - + Brightness Nightstand Brightness Brillo - + Delay Nightstand delay Atraso - + Custom watchface Esfera do reloxo personalizable - + Select watchface select nightstand watchface Seleccionala esfera do reloxo @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.he.ts b/i18n/asteroid-settings.he.ts index 71b7ffa4..0488d660 100644 --- a/i18n/asteroid-settings.he.ts +++ b/i18n/asteroid-settings.he.ts @@ -83,60 +83,60 @@ Bluetooth - + Display תצוגה - + Brightness בהירות - + Off - + High - + Medium - + Low - + Automatic brightness בהירות אוטומטית - - + + Always on Display תצוגה פעילה תמידית - + Burn-in Protection Burn in protection הגנה מצריבה פנימית - + Tilt-to-wake להטות כדי להעיר - + Tap-to-wake לגעת כדי להעיר @@ -153,7 +153,7 @@ - + Nightstand שידה @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ על אודות - + Enable הפעלה - + Brightness Nightstand Brightness בהירות - + Delay Nightstand delay השהיה - + Custom watchface פני שעון בהתאמה אישית - + Select watchface select nightstand watchface בחירת פני השעון @@ -366,10 +369,42 @@ Enable colored battery? להפעיל סוללה צבעונית? - - - Settings - הגדרות + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.hi.ts b/i18n/asteroid-settings.hi.ts index 90378aa7..ffba74e2 100644 --- a/i18n/asteroid-settings.hi.ts +++ b/i18n/asteroid-settings.hi.ts @@ -83,60 +83,60 @@ ब्लूटूथ - + Display डिस्प्ले - + Brightness चमक - + Off - + High - + Medium - + Low - + Automatic brightness स्वचालित चमक - - + + Always on Display हमेशा डिस्प्ले ऑन (AOD) - + Burn-in Protection Burn in protection डिस्प्ले जलने का बचाव - + Tilt-to-wake टिल्ट-टु-वेक - + Tap-to-wake टैप-टु-वेक @@ -153,7 +153,7 @@ - + Nightstand रात्रिस्तंभ @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ एस्टेरोइड ओ. एस. के बारे में - + Enable चालून करे - + Brightness Nightstand Brightness चमक - + Delay Nightstand delay देरी - + Custom watchface कस्टम वॉचफेस - + Select watchface select nightstand watchface वॉचफेस चुनें @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.hr.ts b/i18n/asteroid-settings.hr.ts index 3830ce19..4378f078 100644 --- a/i18n/asteroid-settings.hr.ts +++ b/i18n/asteroid-settings.hr.ts @@ -83,60 +83,60 @@ - + Display Ekran - + Brightness Svjetlina - + Off - + High - + Medium - + Low - + Automatic brightness Automatska svjetlina - - + + Always on Display Uvijek na ekranu - + Burn-in Protection Burn in protection Zaštita ekrana - + Tilt-to-wake Nagni-za-buđenje - + Tap-to-wake Dodirni-za-buđenje @@ -153,7 +153,7 @@ - + Nightstand Prikaz sata tijekom noćnog napajanja @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Informacije - + Enable Aktiviraj - + Brightness Nightstand Brightness Svjetlina - + Delay Nightstand delay Odgoda - + Custom watchface Prilagođena pozadina sata - + Select watchface select nightstand watchface Odaberi pozadinu sata @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.hu.ts b/i18n/asteroid-settings.hu.ts index 015c3472..e3f761de 100644 --- a/i18n/asteroid-settings.hu.ts +++ b/i18n/asteroid-settings.hu.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,8 +278,32 @@ Low - - Settings + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store diff --git a/i18n/asteroid-settings.ia.ts b/i18n/asteroid-settings.ia.ts index d821f8ae..8303b13d 100644 --- a/i18n/asteroid-settings.ia.ts +++ b/i18n/asteroid-settings.ia.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Schermo - + Brightness Luminositate - + Off - + High - + Medium - + Low - + Automatic brightness Luminositate automatic - - + + Always on Display Schermo sempre active - + Burn-in Protection Burn in protection Protection contra ardituras - + Tilt-to-wake Inclinar pro activar - + Tap-to-wake Toccar pro activar @@ -153,7 +153,7 @@ - + Nightstand Tabula de nocte @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ A proposito de - + Enable Activar - + Brightness Nightstand Brightness Luminositate - + Delay Nightstand delay Retardo - + Custom watchface Cadran personnalisé - + Select watchface select nightstand watchface @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.id.ts b/i18n/asteroid-settings.id.ts index fcaed386..4086d164 100644 --- a/i18n/asteroid-settings.id.ts +++ b/i18n/asteroid-settings.id.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Layar - + Brightness Kecerahan - + Off - + High - + Medium - + Low - + Automatic brightness Kecerahan otomatis - - + + Always on Display Selalu Dipajang - + Burn-in Protection Burn in protection Proteksi pembakaran - + Tilt-to-wake miringkan untuk bangun - + Tap-to-wake Ketuk untuk membangunkan @@ -153,7 +153,7 @@ - + Nightstand Dudukan malam @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Tentang - + Enable Aktifkan - + Brightness Nightstand Brightness Kecerahan - + Delay Nightstand delay Tunda - + Custom watchface Tampilan jam kustom - + Select watchface select nightstand watchface Pilih tampilan jam @@ -366,10 +369,42 @@ Enable colored battery? Aktifkan baterai berwarna? - - - Settings - Pengaturan + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.it.ts b/i18n/asteroid-settings.it.ts index 200bfd1e..39d75427 100644 --- a/i18n/asteroid-settings.it.ts +++ b/i18n/asteroid-settings.it.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,8 +278,32 @@ Low - - Settings + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store diff --git a/i18n/asteroid-settings.ja.ts b/i18n/asteroid-settings.ja.ts index 15b93243..386055d8 100644 --- a/i18n/asteroid-settings.ja.ts +++ b/i18n/asteroid-settings.ja.ts @@ -83,60 +83,60 @@ Bluetooth - + Display ディスプレイ - + Brightness 明るさ - + Off - + High - + Medium - + Low - + Automatic brightness - - + + Always on Display - + Burn-in Protection Burn in protection - + Tilt-to-wake 振ってスリープを解除 - + Tap-to-wake @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ 情報 - + Enable - + Brightness Nightstand Brightness 輝度 - + Delay Nightstand delay - + Custom watchface - + Select watchface select nightstand watchface @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.ka.ts b/i18n/asteroid-settings.ka.ts index fe937c4e..df5240a9 100644 --- a/i18n/asteroid-settings.ka.ts +++ b/i18n/asteroid-settings.ka.ts @@ -83,60 +83,60 @@ ბლუთუზი - + Display - + Brightness სიკაშკაშე - + Off - + High - + Medium - + Low - + Automatic brightness - - + + Always on Display - + Burn-in Protection Burn in protection - + Tilt-to-wake დახრით გაღვიძება - + Tap-to-wake @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ შესახებ - + Enable - + Brightness Nightstand Brightness სიკაშკაშე - + Delay Nightstand delay - + Custom watchface - + Select watchface select nightstand watchface @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.ko.ts b/i18n/asteroid-settings.ko.ts index abe70737..b73824c7 100644 --- a/i18n/asteroid-settings.ko.ts +++ b/i18n/asteroid-settings.ko.ts @@ -83,60 +83,60 @@ 블루투스 - + Display 화면 - + Brightness 밝기 - + Off - + High - + Medium - + Low - + Automatic brightness 자동 밝기 - - + + Always on Display 항상 켜기 - + Burn-in Protection Burn in protection 번인 보호 - + Tilt-to-wake 시계를 볼 때 화면 켜기 - + Tap-to-wake 탭할 때 화면 켜기 @@ -153,7 +153,7 @@ - + Nightstand 나이트스탠드 @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ 정보 - + Enable 활성화 - + Brightness Nightstand Brightness 밝기 - + Delay Nightstand delay 지연 - + Custom watchface 시계화면 사용자 정의 - + Select watchface select nightstand watchface 시계 모드 선택 @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.lb.ts b/i18n/asteroid-settings.lb.ts index a7ce0aa1..7737a93d 100644 --- a/i18n/asteroid-settings.lb.ts +++ b/i18n/asteroid-settings.lb.ts @@ -83,60 +83,60 @@ - + Display - + Brightness Hellegkeet - + Off - + High - + Medium - + Low - + Automatic brightness - - + + Always on Display - + Burn-in Protection Burn in protection - + Tilt-to-wake - + Tap-to-wake @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Iwwer - + Enable - + Brightness Nightstand Brightness Hellegkeet - + Delay Nightstand delay - + Custom watchface - + Select watchface select nightstand watchface @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.lt.ts b/i18n/asteroid-settings.lt.ts index 8aec798f..1fa3d641 100644 --- a/i18n/asteroid-settings.lt.ts +++ b/i18n/asteroid-settings.lt.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Ekranas - + Brightness Ryškumas - + Off - + High - + Medium - + Low - + Automatic brightness Automatinis ryškumas - - + + Always on Display Visada įjungtas ekranas - + Burn-in Protection Burn in protection Apsauga nuo ekrano išdegimo - + Tilt-to-wake Pakreipti, kad pabustų - + Tap-to-wake Paliesti, kas pabustų @@ -153,7 +153,7 @@ - + Nightstand Naktinis staliukas @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Apie - + Enable Įjungti - + Brightness Nightstand Brightness Ryškumas - + Delay Nightstand delay Atidėjimas - + Custom watchface Tinkinamas laikrodžio ekrano dizainas - + Select watchface select nightstand watchface Pasirinkite laikrodžio ekrano dizainą @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.mr.ts b/i18n/asteroid-settings.mr.ts index 422efd7d..580078a1 100644 --- a/i18n/asteroid-settings.mr.ts +++ b/i18n/asteroid-settings.mr.ts @@ -83,60 +83,60 @@ ब्लूटुथ - + Display प्रदर्शन - + Brightness उज्ज्वलता - + Off - + High - + Medium - + Low - + Automatic brightness स्वयंचलित ब्राइटनेस - - + + Always on Display नेहमी प्रदर्शनावर - + Burn-in Protection Burn in protection संरक्षणात बर्न करा - + Tilt-to-wake टिल्ट टू वेक - + Tap-to-wake टॅप टू वेक @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ बद्दल - + Enable - + Brightness Nightstand Brightness उज्ज्वलता - + Delay Nightstand delay विलंब - + Custom watchface - + Select watchface select nightstand watchface @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.ms.ts b/i18n/asteroid-settings.ms.ts index f8672725..96b78dc0 100644 --- a/i18n/asteroid-settings.ms.ts +++ b/i18n/asteroid-settings.ms.ts @@ -83,60 +83,60 @@ - + Display Paparan - + Brightness Kecerahan - + Off - + High - + Medium - + Low - + Automatic brightness - - + + Always on Display Sentiasa Dipamerkan - + Burn-in Protection Burn in protection - + Tilt-to-wake Pusing-untuk-bangun - + Tap-to-wake Ketik untuk bangun @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Mengenai - + Enable - + Brightness Nightstand Brightness Kecerahan - + Delay Nightstand delay - + Custom watchface - + Select watchface select nightstand watchface @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.nb_NO.ts b/i18n/asteroid-settings.nb_NO.ts index 0deb22a6..ec16d29b 100644 --- a/i18n/asteroid-settings.nb_NO.ts +++ b/i18n/asteroid-settings.nb_NO.ts @@ -83,60 +83,60 @@ Blåtann - + Display Skjerm - + Brightness Lysstyrke - + Off - + High - + Medium - + Low - + Automatic brightness Automatisk lysstyrke - - + + Always on Display Skjerm alltid påslått - + Burn-in Protection Burn in protection Innbrenningsbeskyttelse - + Tilt-to-wake Skakke-vekking - + Tap-to-wake Trykk for å vekke @@ -153,7 +153,7 @@ - + Nightstand Nattbord @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Om - + Enable Skru på - + Brightness Nightstand Brightness Lysstyrke - + Delay Nightstand delay Forsinkelse - + Custom watchface Egendefinert urskive - + Select watchface select nightstand watchface Velg urskive @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.nl_BE.ts b/i18n/asteroid-settings.nl_BE.ts index f39a4fab..5992bf54 100644 --- a/i18n/asteroid-settings.nl_BE.ts +++ b/i18n/asteroid-settings.nl_BE.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Scherm - + Brightness Helderheid - + Off - + High - + Medium - + Low - + Automatic brightness Automatische helderheid - - + + Always on Display Actief scherm - + Burn-in Protection Burn in protection Burn-in preventie - + Tilt-to-wake Kantelen om te ontwaken - + Tap-to-wake Drukken om te ontwaken @@ -153,7 +153,7 @@ - + Nightstand Nachtmodus @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Over - + Enable Inschakelen - + Brightness Nightstand Brightness Helderheid - + Delay Nightstand delay Vertragen - + Custom watchface Aangepaste wijzerplaat - + Select watchface select nightstand watchface Selecteer wijzerplaat @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.nl_NL.ts b/i18n/asteroid-settings.nl_NL.ts index 39038950..c52c6bed 100644 --- a/i18n/asteroid-settings.nl_NL.ts +++ b/i18n/asteroid-settings.nl_NL.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Scherm - + Brightness Helderheid - + Off - + High - + Medium - + Low - + Automatic brightness Automatische helderheid - - + + Always on Display Actief scherm - + Burn-in Protection Burn in protection Burn-in preventie - + Tilt-to-wake Kantelen om te ontwaken - + Tap-to-wake Drukken om te ontwaken @@ -153,7 +153,7 @@ - + Nightstand Nachtkast @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Over - + Enable Inschakelen - + Brightness Nightstand Brightness Helderheid - + Delay Nightstand delay Wachttijd - + Custom watchface Aangepaste wijzerplaat - + Select watchface select nightstand watchface Kies wijzerplaat @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.oc.ts b/i18n/asteroid-settings.oc.ts index b75a4075..5bda49dc 100644 --- a/i18n/asteroid-settings.oc.ts +++ b/i18n/asteroid-settings.oc.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Ecran - + Brightness Luminositat - + Off - + High - + Medium - + Low - + Automatic brightness Luminositat automatica - - + + Always on Display Totjorn alucat - + Burn-in Protection Burn in protection Proteccion contra las cremaduras - + Tilt-to-wake Inclinar per desrevelhar - + Tap-to-wake Tocar per desrevelhar @@ -153,7 +153,7 @@ - + Nightstand Tauleta de nuèch @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ A prepaus - + Enable Activar - + Brightness Nightstand Brightness Luminositat - + Delay Nightstand delay Relambi - + Custom watchface Quadran personalizat - + Select watchface select nightstand watchface Seleccionatz un quadran @@ -366,10 +369,42 @@ Enable colored battery? Activar la batariá colorada ? - - - Settings - Paramètres + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.pl.ts b/i18n/asteroid-settings.pl.ts index 135972ab..fa7ff5be 100644 --- a/i18n/asteroid-settings.pl.ts +++ b/i18n/asteroid-settings.pl.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Wyświetlacz - + Brightness Jasność - + Off - + High - + Medium - + Low - + Automatic brightness Automatyczna jasność - - + + Always on Display Ekran zawsze włączony - + Burn-in Protection Burn in protection Ochrona przed wypaleniem - + Tilt-to-wake Przechyl, aby wybudzić - + Tap-to-wake Dotknij, aby wybudzić @@ -153,7 +153,7 @@ - + Nightstand Szafka nocna @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ O urządzeniu - + Enable Włącz - + Brightness Nightstand Brightness Jasność - + Delay Nightstand delay Opóźnienie - + Custom watchface Niestandardowa tarcza zegarka - + Select watchface select nightstand watchface Wybierz tarczę @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.pt.ts b/i18n/asteroid-settings.pt.ts index 86852977..c750c0e4 100644 --- a/i18n/asteroid-settings.pt.ts +++ b/i18n/asteroid-settings.pt.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Ecrã - + Brightness Brilho - + Off - + High - + Medium - + Low - + Automatic brightness Brilho automático - - + + Always on Display Ecrã sempre ligado - + Burn-in Protection Burn in protection Proteção de queimadura - + Tilt-to-wake Inclinar para acordar - + Tap-to-wake Tocar para acordar @@ -153,7 +153,7 @@ - + Nightstand Modo criado-mudo @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Sobre - + Enable Ativar - + Brightness Nightstand Brightness Brilho - + Delay Nightstand delay Atraso - + Custom watchface Face do relógio personalizado - + Select watchface select nightstand watchface Selecione a face do relógio @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.pt_BR.ts b/i18n/asteroid-settings.pt_BR.ts index 975f222a..6735b97a 100644 --- a/i18n/asteroid-settings.pt_BR.ts +++ b/i18n/asteroid-settings.pt_BR.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Tela - + Brightness Brilho - + Off - + High - + Medium - + Low - + Automatic brightness Brilho automático - - + + Always on Display Tela sempre ligada - + Burn-in Protection Burn in protection Proteção contra queima - + Tilt-to-wake Inclinar para acordar - + Tap-to-wake Tocar para acordar @@ -153,7 +153,7 @@ - + Nightstand Modo criado-mudo @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Sobre - + Enable Habilitar - + Brightness Nightstand Brightness Brilho - + Delay Nightstand delay Atraso - + Custom watchface Mostrador personalizado - + Select watchface select nightstand watchface Selecionar face do relógio @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.pt_PT.ts b/i18n/asteroid-settings.pt_PT.ts index de87728c..c8ac67d0 100644 --- a/i18n/asteroid-settings.pt_PT.ts +++ b/i18n/asteroid-settings.pt_PT.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Ecrã - + Brightness Brilho - + Off - + High - + Medium - + Low - + Automatic brightness Brilho automático - - + + Always on Display Ecrã sempre ligado - + Burn-in Protection Burn in protection Proteção de queimadura - + Tilt-to-wake Inclinar para acordar - + Tap-to-wake Tocar para acordar @@ -153,7 +153,7 @@ - + Nightstand Modo criado-mudo @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Sobre - + Enable Ativar - + Brightness Nightstand Brightness Brilho - + Delay Nightstand delay Atraso - + Custom watchface Face do relógio personalizado - + Select watchface select nightstand watchface Selecione a face do relógio @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.ro.ts b/i18n/asteroid-settings.ro.ts index d90b8d87..1614a088 100644 --- a/i18n/asteroid-settings.ro.ts +++ b/i18n/asteroid-settings.ro.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Ecran - + Brightness Luminozitate - + Off - + High - + Medium - + Low - + Automatic brightness Luminozitate automată - - + + Always on Display Întotdeauna pe ecran - + Burn-in Protection Burn in protection Protecție persistența imaginii - + Tilt-to-wake Înclinați să se trezească - + Tap-to-wake Atingeți pentru a trezi @@ -153,7 +153,7 @@ - + Nightstand Noptieră @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Despre - + Enable Pornește - + Brightness Nightstand Brightness Luminozitate - + Delay Nightstand delay Întârziere - + Custom watchface Fata costumizata ceas - + Select watchface select nightstand watchface Selectează față de ceas @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.ru.ts b/i18n/asteroid-settings.ru.ts index e885f219..703f8cad 100644 --- a/i18n/asteroid-settings.ru.ts +++ b/i18n/asteroid-settings.ru.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Дисплей - + Brightness Яркость - + Off - + High - + Medium - + Low - + Automatic brightness Автоматическая яркость - - + + Always on Display AoD режим - + Burn-in Protection Burn in protection Защита от выгорания - + Tilt-to-wake Пробуждение по наклону - + Tap-to-wake Пробуждение по касанию @@ -153,7 +153,7 @@ - + Nightstand Прикроватный режим @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ О продукте - + Enable Включить - + Brightness Nightstand Brightness Яркость - + Delay Nightstand delay Задержка - + Custom watchface Пользовательский циферблат - + Select watchface select nightstand watchface Выбрать циферблат @@ -366,10 +369,42 @@ Enable colored battery? Вкл. цвет. батар. - - - Settings - Настройки + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.sk.ts b/i18n/asteroid-settings.sk.ts index e6d635f2..ebf4cf84 100644 --- a/i18n/asteroid-settings.sk.ts +++ b/i18n/asteroid-settings.sk.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,8 +278,32 @@ Low - - Settings + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store diff --git a/i18n/asteroid-settings.sq.ts b/i18n/asteroid-settings.sq.ts index 3245bf40..fee1ebb5 100644 --- a/i18n/asteroid-settings.sq.ts +++ b/i18n/asteroid-settings.sq.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Shfaq - + Brightness Drita - + Off - + High - + Medium - + Low - + Automatic brightness Drita automatike - - + + Always on Display Ekrani gjithmonë i aktivizuar - + Burn-in Protection Burn in protection Mbrojte nga ndezja - + Tilt-to-wake - + Tap-to-wake Shtyp-për-Zgjim @@ -153,7 +153,7 @@ - + Nightstand @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Rreth nesh - + Enable Aktivizo - + Brightness Nightstand Brightness Drita - + Delay Nightstand delay Vonimi - + Custom watchface Watchface i përvetsuar - + Select watchface select nightstand watchface Zgjedh një watchface @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.sv.ts b/i18n/asteroid-settings.sv.ts index 7b049d54..b0bfbe2c 100644 --- a/i18n/asteroid-settings.sv.ts +++ b/i18n/asteroid-settings.sv.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Skärm - + Brightness Ljus styrka - + Off - + High - + Medium - + Low - + Automatic brightness Automatisk ljusstyrka - - + + Always on Display Allid på-skärm - + Burn-in Protection Burn in protection Inbränningsskydd - + Tilt-to-wake Skaka för att aktivera - + Tap-to-wake Tryck-för-att-väcka @@ -153,7 +153,7 @@ - + Nightstand Nattduksbord @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Om - + Enable Aktivera - + Brightness Nightstand Brightness Ljusstyrka - + Delay Nightstand delay Fördröjning - + Custom watchface Anpassad urtavla - + Select watchface select nightstand watchface Välj urtavla @@ -366,10 +369,42 @@ Enable colored battery? - - - Settings - Inställningar + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.ta.ts b/i18n/asteroid-settings.ta.ts index 1d0df5e0..aef2801e 100644 --- a/i18n/asteroid-settings.ta.ts +++ b/i18n/asteroid-settings.ta.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,8 +278,32 @@ Low - - Settings + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store diff --git a/i18n/asteroid-settings.te.ts b/i18n/asteroid-settings.te.ts index 7d5fcb80..8b942ccd 100644 --- a/i18n/asteroid-settings.te.ts +++ b/i18n/asteroid-settings.te.ts @@ -83,60 +83,60 @@ బ్లూటూత్ - + Display ప్రదర్శన - + Brightness ప్రకాశం - + Off - + High - + Medium - + Low - + Automatic brightness - - + + Always on Display ఎల్లప్పుడూ ప్రదర్శనలో ఉంటుంది - + Burn-in Protection Burn in protection - + Tilt-to-wake వంపు నుండి మేల్కొలపండి - + Tap-to-wake మేల్కొలపడానికి నొక్కండి @@ -153,7 +153,7 @@ - + Nightstand నైట్‌స్టాండ్ @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ గురించి - + Enable ప్రారంభించు - + Brightness Nightstand Brightness ప్రకాశం - + Delay Nightstand delay ఆలస్యం - + Custom watchface అనుకూల వాచ్‌ఫేస్ - + Select watchface select nightstand watchface వాచ్‌ఫేస్‌ని ఎంచుకోండి @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.th.ts b/i18n/asteroid-settings.th.ts index de2c271b..001bb34c 100644 --- a/i18n/asteroid-settings.th.ts +++ b/i18n/asteroid-settings.th.ts @@ -83,60 +83,60 @@ บลูทูธ - + Display แสดงผล - + Brightness ความสว่าง - + Off - + High - + Medium - + Low - + Automatic brightness ความสว่างอัตโนมัติ - - + + Always on Display แสดงบนหน้าจอ - + Burn-in Protection Burn in protection ป้องกันการเบิร์น - + Tilt-to-wake เอียงเพื่อปลุก - + Tap-to-wake แตะเพื่อปลุก @@ -153,7 +153,7 @@ - + Nightstand ข้างเตียง @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ เกี่ยวกับ - + Enable ใช้งาน - + Brightness Nightstand Brightness ความสว่าง - + Delay Nightstand delay เลื่อนเวลา - + Custom watchface ปรับแต่งหน้าปัด - + Select watchface select nightstand watchface เลือกหน้าปัดนาฬิกา @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.tr.ts b/i18n/asteroid-settings.tr.ts index e9cabd09..df932f42 100644 --- a/i18n/asteroid-settings.tr.ts +++ b/i18n/asteroid-settings.tr.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,9 +278,33 @@ Low - - Settings - Ayarlar + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store + diff --git a/i18n/asteroid-settings.uk.ts b/i18n/asteroid-settings.uk.ts index 5e394e92..5fc4e6ad 100644 --- a/i18n/asteroid-settings.uk.ts +++ b/i18n/asteroid-settings.uk.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Дисплей - + Brightness Яскравість - + Off - + High - + Medium - + Low - + Automatic brightness Автоматична яскравість - - + + Always on Display AOD - + Burn-in Protection Burn in protection Захист від вигорання - + Tilt-to-wake Пробудження нахилом - + Tap-to-wake Пробудження дотиком @@ -153,7 +153,7 @@ - + Nightstand Нічний вид @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Про - + Enable Увімкнути - + Brightness Nightstand Brightness Яскравість - + Delay Nightstand delay Затримка - + Custom watchface Користувацький циферблат - + Select watchface select nightstand watchface Виберіть циферблат @@ -366,10 +369,42 @@ Enable colored battery? Увімкнути кольорову батарею? - - - Settings - Налаштування + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store + diff --git a/i18n/asteroid-settings.vi.ts b/i18n/asteroid-settings.vi.ts index 9fee68d3..e8374cff 100644 --- a/i18n/asteroid-settings.vi.ts +++ b/i18n/asteroid-settings.vi.ts @@ -83,60 +83,60 @@ Bluetooth - + Display Hiển thị - + Brightness Độ sáng - + Off - + High - + Medium - + Low - + Automatic brightness Độ sáng tự động - - + + Always on Display Màn hình luôn bật - + Burn-in Protection Burn in protection Bảo vệ máy tính khỏi việc để lâu ngày - + Tilt-to-wake Nghiêng để đánh thức - + Tap-to-wake Nhấn để đánh thức @@ -153,7 +153,7 @@ - + Nightstand Đầu giường @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ Giới thiệu - + Enable Bật - + Brightness Nightstand Brightness Độ sáng - + Delay Nightstand delay Trì hoãn - + Custom watchface Mặt đồng hồ tuỳ chỉnh - + Select watchface select nightstand watchface Chọn mặt đồng hồ @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store diff --git a/i18n/asteroid-settings.zh_Hans.ts b/i18n/asteroid-settings.zh_Hans.ts index 48167e10..c3c32cee 100644 --- a/i18n/asteroid-settings.zh_Hans.ts +++ b/i18n/asteroid-settings.zh_Hans.ts @@ -260,6 +260,7 @@ Tap to cancel + Off @@ -277,8 +278,32 @@ Low - - Settings + + Remove + + + + Get More Watchfaces + + + + Connect to get more watchfaces + + + + Refresh store + + + + Restart launcher + + + + Loading... + + + + Watchface Store diff --git a/i18n/asteroid-settings.zh_Hant.ts b/i18n/asteroid-settings.zh_Hant.ts index 894b0759..486cfd47 100644 --- a/i18n/asteroid-settings.zh_Hant.ts +++ b/i18n/asteroid-settings.zh_Hant.ts @@ -83,60 +83,60 @@ 藍牙 - + Display 顯示 - + Brightness 亮度 - + Off - + High - + Medium - + Low - + Automatic brightness 自動亮度 - - + + Always on Display 始終在顯示幕上 - + Burn-in Protection Burn in protection 燒傷螢幕保護 - + Tilt-to-wake 傾斜喚醒 - + Tap-to-wake 點擊喚醒 @@ -153,7 +153,7 @@ - + Nightstand 夜間待機模式 @@ -213,6 +213,9 @@ + + + Tap to cancel @@ -222,29 +225,29 @@ 關於 - + Enable 啟用 - + Brightness Nightstand Brightness 亮度 - + Delay Nightstand delay 延遲 - + Custom watchface 自訂錶盤 - + Select watchface select nightstand watchface 選擇錶盤 @@ -366,9 +369,41 @@ Enable colored battery? - - - Settings + + + + Remove + + + + + Get More Watchfaces + + + + + Connect to get more watchfaces + + + + + Refresh store + + + + + + Restart launcher + + + + + Loading... + + + + + Watchface Store From 69b26d5851fd180d1946da803ae730bf9ea08840 Mon Sep 17 00:00:00 2001 From: moWerk Date: Wed, 1 Apr 2026 00:25:22 +0200 Subject: [PATCH 5/5] Add round screen bottom margin to watchface page buttons Footer buttons on WatchfaceSelector and WatchfaceStorePage were clipped at the bottom edge on round watches. Adds a conditional spacer below the button stack sized to Dims.l(8) on round screens and zero on square screens. --- src/qml/WatchfaceSelector.qml | 2 ++ src/qml/WatchfaceStorePage.qml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/qml/WatchfaceSelector.qml b/src/qml/WatchfaceSelector.qml index f5da3b1f..0bbdd2d7 100644 --- a/src/qml/WatchfaceSelector.qml +++ b/src/qml/WatchfaceSelector.qml @@ -415,6 +415,8 @@ RemorseTimer { onClicked: layerStack.push(watchfaceStoreComponent, { assetPath: assetPath, previewSize: watchfaceSelector.previewSize }) } } + + Item { width: parent.width; height: DeviceSpecs.hasRoundScreen ? Dims.l(8) : 0 } } } } diff --git a/src/qml/WatchfaceStorePage.qml b/src/qml/WatchfaceStorePage.qml index 8102ec09..74698bdd 100644 --- a/src/qml/WatchfaceStorePage.qml +++ b/src/qml/WatchfaceStorePage.qml @@ -401,6 +401,8 @@ Item { HighlightBar { onClicked: restartRemorse.start() } } + + Item { width: parent.width; height: DeviceSpecs.hasRoundScreen ? Dims.l(8) : 0 } } }