mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-08-15 18:43:59 +00:00
initial commit
This commit is contained in:
@@ -343,15 +343,15 @@ Loader {
|
||||
text: {
|
||||
var lang = I18n.locale.name.split("_")[0];
|
||||
var formats = {
|
||||
"en": "dddd, MMMM d",
|
||||
"de": "dddd, d. MMMM",
|
||||
"fr": "dddd d MMMM",
|
||||
"es": "dddd, d 'de' MMMM",
|
||||
"fr": "dddd d MMMM",
|
||||
"pt": "dddd, d 'de' MMMM",
|
||||
"zh": "yyyy年M月d日 dddd",
|
||||
"nl": "dddd d MMMM"
|
||||
"uk": "dddd, d MMMM",
|
||||
"tr": "dddd, d MMMM"
|
||||
};
|
||||
return I18n.locale.toString(Time.now, formats[lang] || "dddd, d MMMM");
|
||||
return I18n.locale.toString(Time.now, formats[lang] || "dddd, MMMM d");
|
||||
}
|
||||
pointSize: Style.fontSizeXL
|
||||
font.weight: Font.Medium
|
||||
@@ -524,7 +524,7 @@ Loader {
|
||||
}
|
||||
Text {
|
||||
id: hibernateText
|
||||
text: Settings.data.general.showHibernateOnLockScreen ? I18n.tr("session-menu.hibernate") : ""
|
||||
text: I18n.tr("session-menu.hibernate")
|
||||
font.pointSize: buttonRowTextMeasurer.fontSize
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
@@ -550,7 +550,7 @@ Loader {
|
||||
// Button row needs: margins + 5 buttons + 4 spacings + margins
|
||||
// Plus ColumnLayout margins (14 on each side = 28 total)
|
||||
// Add extra buffer to ensure password input has proper padding
|
||||
property real minButtonRowWidth: buttonRowTextMeasurer.minButtonWidth > 0 ? ((Settings.data.general.showHibernateOnLockScreen ? 5 : 4) * buttonRowTextMeasurer.minButtonWidth) + 40 + (2 * Style.marginM) + 28 + (2 * Style.marginM) : 750
|
||||
property real minButtonRowWidth: buttonRowTextMeasurer.minButtonWidth > 0 ? (5 * buttonRowTextMeasurer.minButtonWidth) + 40 + (2 * Style.marginM) + 28 + (2 * Style.marginM) : 750
|
||||
width: Math.max(750, minButtonRowWidth)
|
||||
|
||||
ColumnLayout {
|
||||
@@ -749,7 +749,7 @@ Loader {
|
||||
}
|
||||
}
|
||||
|
||||
// Forecast
|
||||
// 3-day forecast
|
||||
RowLayout {
|
||||
visible: Settings.data.location.weatherEnabled && LocationService.data.weather !== null
|
||||
Layout.preferredWidth: 260
|
||||
@@ -757,7 +757,7 @@ Loader {
|
||||
spacing: 4
|
||||
|
||||
Repeater {
|
||||
model: MediaService.currentPlayer && MediaService.canPlay ? 3 : 4
|
||||
model: 3
|
||||
delegate: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 3
|
||||
@@ -804,6 +804,8 @@ Loader {
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
visible: !(Settings.data.location.weatherEnabled && LocationService.data.weather !== null)
|
||||
Layout.preferredWidth: visible ? 1 : 0
|
||||
}
|
||||
|
||||
// Battery and Keyboard Layout (full mode only)
|
||||
@@ -1181,7 +1183,6 @@ Loader {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: Settings.data.general.showHibernateOnLockScreen
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: buttonRowTextMeasurer.minButtonWidth
|
||||
Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48
|
||||
|
||||
@@ -835,24 +835,6 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NCheckbox {
|
||||
label: "Telegram"
|
||||
description: ProgramCheckerService.telegramAvailable ? I18n.tr("settings.color-scheme.templates.programs.telegram.description", {
|
||||
"filepath": "~/.config/telegram-desktop/themes/noctalia.tdesktop-theme"
|
||||
}) : I18n.tr("settings.color-scheme.templates.programs.telegram.description-missing", {
|
||||
"app": "telegram"
|
||||
})
|
||||
checked: Settings.data.templates.telegram
|
||||
enabled: ProgramCheckerService.telegramAvailable
|
||||
opacity: ProgramCheckerService.telegramAvailable ? 1.0 : 0.6
|
||||
onToggled: checked => {
|
||||
if (ProgramCheckerService.telegramAvailable) {
|
||||
Settings.data.templates.telegram = checked;
|
||||
AppThemeService.generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Miscellaneous
|
||||
NCollapsible {
|
||||
|
||||
@@ -26,8 +26,7 @@ Popup {
|
||||
property var schemeColorsCache: ({})
|
||||
property int cacheVersion: 0
|
||||
|
||||
// Cache for available schemes list
|
||||
property string schemesCacheFile: Settings.cacheDir + "color-schemes-list.json"
|
||||
// Cache for available schemes list (uses ShellState singleton)
|
||||
property int schemesCacheUpdateFrequency: 2 * 60 * 60 // 2 hours in seconds
|
||||
|
||||
// Cache for repo branch info (to reduce API calls during downloads)
|
||||
@@ -99,33 +98,6 @@ Popup {
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// Cache file for schemes list
|
||||
FileView {
|
||||
id: schemesCacheFileView
|
||||
path: schemesCacheFile
|
||||
printErrors: false
|
||||
|
||||
JsonAdapter {
|
||||
id: schemesCacheAdapter
|
||||
property var schemes: []
|
||||
property real timestamp: 0
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
loadSchemesFromCache();
|
||||
}
|
||||
|
||||
onLoadFailed: function (error) {
|
||||
if (error.toString().includes("No such file") || error === 2) {
|
||||
// Cache doesn't exist, fetch from API (only if popup is open)
|
||||
if (root.visible) {
|
||||
Qt.callLater(() => {
|
||||
fetchAvailableSchemesFromAPI();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: Color.mSurface
|
||||
@@ -135,58 +107,96 @@ Popup {
|
||||
}
|
||||
|
||||
function loadSchemesFromCache() {
|
||||
const now = Time.timestamp;
|
||||
try {
|
||||
const now = Time.timestamp;
|
||||
const cacheData = ShellState.getColorSchemesList();
|
||||
const cachedSchemes = cacheData.schemes || [];
|
||||
const cachedTimestamp = cacheData.timestamp || 0;
|
||||
|
||||
// Check if cache is expired or missing
|
||||
if (!schemesCacheAdapter.timestamp || (now >= schemesCacheAdapter.timestamp + schemesCacheUpdateFrequency)) {
|
||||
// Only fetch from API if we haven't fetched recently (prevent rapid repeated calls)
|
||||
const timeSinceLastFetch = now - lastApiFetchTime;
|
||||
if (timeSinceLastFetch >= minApiFetchInterval) {
|
||||
Logger.d("ColorSchemeDownload", "Cache expired or missing, fetching new schemes");
|
||||
fetchAvailableSchemesFromAPI();
|
||||
return;
|
||||
} else {
|
||||
// Use cached data even if expired, to avoid rate limits
|
||||
Logger.d("ColorSchemeDownload", "Cache expired but recent API call detected, using cached data");
|
||||
if (schemesCacheAdapter.schemes && schemesCacheAdapter.schemes.length > 0) {
|
||||
availableSchemes = schemesCacheAdapter.schemes;
|
||||
hasInitialData = true;
|
||||
fetching = false;
|
||||
// Check if cache is expired or missing
|
||||
if (!cachedTimestamp || (now >= cachedTimestamp + schemesCacheUpdateFrequency)) {
|
||||
// Try migration first if cache is empty
|
||||
if (cachedSchemes.length === 0) {
|
||||
migrateFromOldSchemesList();
|
||||
}
|
||||
|
||||
// Only fetch from API if we haven't fetched recently (prevent rapid repeated calls)
|
||||
const timeSinceLastFetch = now - lastApiFetchTime;
|
||||
if (timeSinceLastFetch >= minApiFetchInterval) {
|
||||
Logger.d("ColorSchemeDownload", "Cache expired or missing, fetching new schemes");
|
||||
fetchAvailableSchemesFromAPI();
|
||||
return;
|
||||
} else {
|
||||
// Use cached data even if expired, to avoid rate limits
|
||||
Logger.d("ColorSchemeDownload", "Cache expired but recent API call detected, using cached data");
|
||||
if (cachedSchemes.length > 0) {
|
||||
availableSchemes = cachedSchemes;
|
||||
hasInitialData = true;
|
||||
fetching = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ageMinutes = Math.round((now - schemesCacheAdapter.timestamp) / 60);
|
||||
Logger.d("ColorSchemeDownload", "Loading cached schemes (age:", ageMinutes, "minutes)");
|
||||
const ageMinutes = Math.round((now - cachedTimestamp) / 60);
|
||||
Logger.d("ColorSchemeDownload", "Loading cached schemes from ShellState (age:", ageMinutes, "minutes)");
|
||||
|
||||
if (schemesCacheAdapter.schemes && schemesCacheAdapter.schemes.length > 0) {
|
||||
availableSchemes = schemesCacheAdapter.schemes;
|
||||
hasInitialData = true;
|
||||
fetching = false;
|
||||
} else {
|
||||
// Cache is empty, only fetch if we haven't fetched recently
|
||||
const timeSinceLastFetch = now - lastApiFetchTime;
|
||||
if (timeSinceLastFetch >= minApiFetchInterval) {
|
||||
fetchAvailableSchemesFromAPI();
|
||||
} else {
|
||||
Logger.d("ColorSchemeDownload", "Cache empty but recent API call detected, skipping fetch");
|
||||
if (cachedSchemes.length > 0) {
|
||||
availableSchemes = cachedSchemes;
|
||||
hasInitialData = true;
|
||||
fetching = false;
|
||||
} else {
|
||||
// Cache is empty, only fetch if we haven't fetched recently
|
||||
const timeSinceLastFetch = now - lastApiFetchTime;
|
||||
if (timeSinceLastFetch >= minApiFetchInterval) {
|
||||
fetchAvailableSchemesFromAPI();
|
||||
} else {
|
||||
Logger.d("ColorSchemeDownload", "Cache empty but recent API call detected, skipping fetch");
|
||||
fetching = false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.e("ColorSchemeDownload", "Failed to load schemes from cache:", error);
|
||||
fetching = false;
|
||||
}
|
||||
}
|
||||
|
||||
function migrateFromOldSchemesList() {
|
||||
const oldSchemesPath = Settings.cacheDir + "color-schemes-list.json";
|
||||
const migrationFileView = Qt.createQmlObject(`
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
FileView {
|
||||
id: migrationView
|
||||
path: "${oldSchemesPath}"
|
||||
printErrors: false
|
||||
adapter: JsonAdapter {
|
||||
property var schemes: []
|
||||
property real timestamp: 0
|
||||
}
|
||||
onLoaded: {
|
||||
root.availableSchemes = adapter.schemes || [];
|
||||
root.saveSchemesToCache();
|
||||
Logger.i("ColorSchemeDownload", "Migrated color-schemes-list.json to ShellState");
|
||||
migrationView.destroy();
|
||||
}
|
||||
onLoadFailed: {
|
||||
migrationView.destroy();
|
||||
}
|
||||
}
|
||||
`, root, "schemesMigrationView");
|
||||
}
|
||||
|
||||
function saveSchemesToCache() {
|
||||
schemesCacheAdapter.schemes = availableSchemes;
|
||||
schemesCacheAdapter.timestamp = Time.timestamp;
|
||||
|
||||
// Ensure cache directory exists
|
||||
Quickshell.execDetached(["mkdir", "-p", Settings.cacheDir]);
|
||||
|
||||
Qt.callLater(() => {
|
||||
schemesCacheFileView.writeAdapter();
|
||||
Logger.d("ColorSchemeDownload", "Schemes list saved to cache");
|
||||
});
|
||||
try {
|
||||
ShellState.setColorSchemesList({
|
||||
schemes: availableSchemes,
|
||||
timestamp: Time.timestamp
|
||||
});
|
||||
Logger.d("ColorSchemeDownload", "Schemes list saved to ShellState");
|
||||
} catch (error) {
|
||||
Logger.e("ColorSchemeDownload", "Failed to save schemes to cache:", error);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchAvailableSchemes() {
|
||||
@@ -194,19 +204,11 @@ Popup {
|
||||
return;
|
||||
}
|
||||
|
||||
// Path is set when popup becomes visible, so FileView will start loading
|
||||
// Try to load from cache first
|
||||
if (schemesCacheFileView.loaded) {
|
||||
// Try to load from ShellState cache first
|
||||
if (typeof ShellState !== 'undefined' && ShellState.isLoaded) {
|
||||
loadSchemesFromCache();
|
||||
} else if (schemesCacheFileView.path) {
|
||||
// Cache file path is set but not loaded yet, wait for it to load
|
||||
// The FileView will trigger loadSchemesFromCache() when loaded
|
||||
// But if it fails, we should fetch from API
|
||||
if (!schemesCacheFileView.loading) {
|
||||
schemesCacheFileView.reload();
|
||||
}
|
||||
} else {
|
||||
// No cache file path, fetch directly from API
|
||||
// ShellState not ready, fetch directly from API
|
||||
fetchAvailableSchemesFromAPI();
|
||||
}
|
||||
}
|
||||
@@ -725,7 +727,25 @@ Popup {
|
||||
}
|
||||
|
||||
onAvailableSchemesChanged: preFetchSchemeColors()
|
||||
onVisibleChanged: preFetchSchemeColors()
|
||||
onVisibleChanged: {
|
||||
preFetchSchemeColors();
|
||||
|
||||
// Load schemes from ShellState when popup becomes visible
|
||||
if (visible) {
|
||||
if (typeof ShellState !== 'undefined' && ShellState.isLoaded) {
|
||||
loadSchemesFromCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: typeof ShellState !== 'undefined' ? ShellState : null
|
||||
function onIsLoadedChanged() {
|
||||
if (root.visible && ShellState.isLoaded) {
|
||||
loadSchemesFromCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: contentColumn
|
||||
|
||||
@@ -21,13 +21,6 @@ ColumnLayout {
|
||||
checked: Settings.data.general.compactLockScreen
|
||||
onToggled: checked => Settings.data.general.compactLockScreen = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("settings.lock-screen.show-hibernate.label")
|
||||
description: I18n.tr("settings.lock-screen.show-hibernate.description")
|
||||
checked: Settings.data.general.showHibernateOnLockScreen
|
||||
onToggled: checked => Settings.data.general.showHibernateOnLockScreen = checked
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Reference in New Issue
Block a user