WallpaperService: refactored to a simpler signal based approach.

This commit is contained in:
LemmyCook 2025-09-01 09:07:23 -04:00
parent 4193d3c87c
commit 5fef9cfe6b
8 changed files with 217 additions and 76 deletions

View file

@ -18,7 +18,6 @@ Variants {
id: root id: root
// Internal state management // Internal state management
property bool firstWallpaper: true
property string transitionType: "fade" property string transitionType: "fade"
property real transitionProgress: 0 property real transitionProgress: 0
@ -37,17 +36,26 @@ Variants {
property real stripesCount: 16 property real stripesCount: 16
property real stripesAngle: 0 property real stripesAngle: 0
// External state management // Used to debounce wallpaper changes
property string servicedWallpaper: modelData ? WallpaperService.getWallpaper(modelData.name) : ""
property string futureWallpaper: "" property string futureWallpaper: ""
onServicedWallpaperChanged: {
// Set wallpaper immediately on startup // On startup assign wallpaper immediately
if (firstWallpaper) { Component.onCompleted: {
firstWallpaper = false var path = modelData ? WallpaperService.getWallpaper(modelData.name) : ""
setWallpaperImmediate(servicedWallpaper) setWallpaperImmediate(path)
} else { }
futureWallpaper = servicedWallpaper
debounceTimer.restart() // External state management
Connections {
target: WallpaperService
function onWallpaperChanged(screenName, path) {
if (screenName === modelData.name) {
// Update wallpaper display
// Set wallpaper immediately on startup
futureWallpaper = path
debounceTimer.restart()
}
} }
} }

View file

@ -14,11 +14,24 @@ Variants {
active: Settings.isLoaded && CompositorService.isNiri && modelData active: Settings.isLoaded && CompositorService.isNiri && modelData
property string wallpaper: ""
sourceComponent: PanelWindow { sourceComponent: PanelWindow {
Component.onCompleted: { Component.onCompleted: {
if (modelData) { if (modelData) {
Logger.log("Overview", "Loading Overview component for Niri on", modelData.name) Logger.log("Overview", "Loading Overview component for Niri on", modelData.name)
} }
wallpaper = modelData ? WallpaperService.getWallpaper(modelData.name) : ""
}
// External state management
Connections {
target: WallpaperService
function onWallpaperChanged(screenName, path) {
if (screenName === modelData.name) {
wallpaper = path
}
}
} }
color: Color.transparent color: Color.transparent
@ -38,7 +51,7 @@ Variants {
id: bgImage id: bgImage
anchors.fill: parent anchors.fill: parent
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
source: modelData ? WallpaperService.getWallpaper(modelData.name) : "" source: wallpaper
smooth: true smooth: true
mipmap: false mipmap: false
cache: false cache: false

View file

@ -63,7 +63,8 @@ ColumnLayout {
if (exitCode === 0) { if (exitCode === 0) {
// Matugen exists, enable it // Matugen exists, enable it
Settings.data.colorSchemes.useWallpaperColors = true Settings.data.colorSchemes.useWallpaperColors = true
ColorSchemeService.changedWallpaper() Settings.data.colorSchemes.predefinedScheme = ""
MatugenService.generateFromWallpaper()
ToastService.showNotice("Matugen", "Enabled") ToastService.showNotice("Matugen", "Enabled")
} else { } else {
// Matugen not found // Matugen not found

View file

@ -15,8 +15,8 @@ ColumnLayout {
// Avatar preview // Avatar preview
NImageCircled { NImageCircled {
width: 64 * scaling width: 128 * scaling
height: 64 * scaling height: 128 * scaling
imagePath: Settings.data.general.avatarImage imagePath: Settings.data.general.avatarImage
fallbackIcon: "person" fallbackIcon: "person"
borderColor: Color.mPrimary borderColor: Color.mPrimary

View file

@ -12,6 +12,35 @@ ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
property list<string> wallpapersList: []
property string currentWallpaper: ""
Component.onCompleted: {
wallpapersList = screen ? WallpaperService.getWallpapersList(screen.name) : []
currentWallpaper = screen ? WallpaperService.getWallpaper(screen.name) : ""
}
Connections {
target: WallpaperService
function onWallpaperChanged(screenName, path) {
if (screenName === screen.name) {
currentWallpaper = WallpaperService.getWallpaper(screen.name)
}
}
function onWallpaperDirectoryChanged(screenName, directory) {
if (screenName === screen.name) {
wallpapersList = WallpaperService.getWallpapersList(screen.name)
currentWallpaper = WallpaperService.getWallpaper(screen.name)
}
}
function onWallpaperListChanged(screenName, count) {
if (screenName === screen.name) {
wallpapersList = WallpaperService.getWallpapersList(screen.name)
currentWallpaper = WallpaperService.getWallpaper(screen.name)
}
}
}
// Current wallpaper display // Current wallpaper display
NText { NText {
text: "Current Wallpaper" text: "Current Wallpaper"
@ -29,7 +58,7 @@ ColumnLayout {
NImageRounded { NImageRounded {
anchors.fill: parent anchors.fill: parent
anchors.margins: Style.marginXS * scaling anchors.margins: Style.marginXS * scaling
imagePath: screen ? WallpaperService.getWallpaper(screen.name) : "" imagePath: currentWallpaper
fallbackIcon: "image" fallbackIcon: "image"
imageRadius: Style.radiusM * scaling imageRadius: Style.radiusM * scaling
} }
@ -74,11 +103,9 @@ ColumnLayout {
} }
} }
property list<string> wallpapersList: screen ? WallpaperService.getWallpapersList(screen.name) : []
NToggle { NToggle {
label: "Assign selection to all monitors" label: "Apply to all monitors"
description: "Set selected wallpaper on all monitors at once." description: "Apply selected wallpaper to all monitors at once."
checked: Settings.data.wallpaper.setWallpaperOnAllMonitors checked: Settings.data.wallpaper.setWallpaperOnAllMonitors
onToggled: checked => Settings.data.wallpaper.setWallpaperOnAllMonitors = checked onToggled: checked => Settings.data.wallpaper.setWallpaperOnAllMonitors = checked
visible: (wallpapersList.length > 0) visible: (wallpapersList.length > 0)
@ -115,7 +142,7 @@ ColumnLayout {
id: wallpaperItem id: wallpaperItem
property string wallpaperPath: modelData property string wallpaperPath: modelData
property bool isSelected: screen ? (wallpaperPath === WallpaperService.getWallpaper(screen.name)) : false property bool isSelected: screen ? (wallpaperPath === currentWallpaper) : false
width: wallpaperGridView.itemSize width: wallpaperGridView.itemSize
height: Math.round(wallpaperGridView.itemSize * 0.67) height: Math.round(wallpaperGridView.itemSize * 0.67)

View file

@ -35,15 +35,6 @@ Singleton {
schemeReader.path = filePath schemeReader.path = filePath
} }
function changedWallpaper() {
if (Settings.data.colorSchemes.useWallpaperColors) {
Logger.log("ColorScheme", "Starting color generation from wallpaper")
MatugenService.generateFromWallpaper()
// Invalidate potential predefined scheme
Settings.data.colorSchemes.predefinedScheme = ""
}
}
FolderListModel { FolderListModel {
id: folderModel id: folderModel
nameFilters: ["*.json"] nameFilters: ["*.json"]

View file

@ -12,6 +12,17 @@ Singleton {
property string dynamicConfigPath: Settings.cacheDir + "matugen.dynamic.toml" property string dynamicConfigPath: Settings.cacheDir + "matugen.dynamic.toml"
// External state management
Connections {
target: WallpaperService
function onWallpaperChanged(screenName, path) {
// Only detect changes on main screen
if (screenName === Screen.name && Settings.data.colorSchemes.useWallpaperColors) {
generateFromWallpaper()
}
}
}
// Build TOML content based on settings // Build TOML content based on settings
function buildConfigToml() { function buildConfigToml() {
return Matugen.buildConfigToml() return Matugen.buildConfigToml()

View file

@ -11,6 +11,14 @@ Singleton {
Component.onCompleted: { Component.onCompleted: {
Logger.log("Wallpaper", "Service started") Logger.log("Wallpaper", "Service started")
// Initialize cache from Settings on startup
var monitors = Settings.data.wallpaper.monitors || []
for (var i = 0; i < monitors.length; i++) {
if (monitors[i].name && monitors[i].wallpaper) {
currentWallpapers[monitors[i].name] = monitors[i].wallpaper
}
}
} }
// All available wallpaper transitions // All available wallpaper transitions
@ -51,10 +59,45 @@ Singleton {
property int scanningCount: 0 property int scanningCount: 0
readonly property bool scanning: (scanningCount > 0) readonly property bool scanning: (scanningCount > 0)
// Cache for current wallpapers - can be updated directly since we use signals for notifications
property var currentWallpapers: ({})
// Signals for reactive UI updates
signal wallpaperChanged(string screenName, string path)
// Emitted when a wallpaper changes
signal wallpaperDirectoryChanged(string screenName, string directory)
// Emitted when a monitor's directory changes
signal wallpaperListChanged(string screenName, int count)
// Emitted when available wallpapers list changes
Connections { Connections {
target: Settings.data.wallpaper target: Settings.data.wallpaper
function onDirectoryChanged() { function onDirectoryChanged() {
root.refreshWallpapersList() root.refreshWallpapersList()
// Emit directory change signals for monitors using the default directory
if (!Settings.data.wallpaper.enableMultiMonitorDirectories) {
// All monitors use the main directory
for (var i = 0; i < Quickshell.screens.length; i++) {
root.wallpaperDirectoryChanged(Quickshell.screens[i].name, Settings.data.wallpaper.directory)
}
} else {
// Only monitors without custom directories are affected
for (var i = 0; i < Quickshell.screens.length; i++) {
var screenName = Quickshell.screens[i].name
var monitor = root.getMonitorConfig(screenName)
if (!monitor || !monitor.directory) {
root.wallpaperDirectoryChanged(screenName, Settings.data.wallpaper.directory)
}
}
}
}
function onEnableMultiMonitorDirectoriesChanged() {
root.refreshWallpapersList()
// Notify all monitors about potential directory changes
for (var i = 0; i < Quickshell.screens.length; i++) {
var screenName = Quickshell.screens[i].name
root.wallpaperDirectoryChanged(screenName, root.getMonitorDirectory(screenName))
}
} }
function onRandomEnabledChanged() { function onRandomEnabledChanged() {
root.toggleRandomWallpaper() root.toggleRandomWallpaper()
@ -96,26 +139,39 @@ Singleton {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Set specific monitor directory // Set specific monitor directory
function setMonitorDirectory(screenName, directory) { function setMonitorDirectory(screenName, directory) {
var monitor = getMonitorConfig(screenName) var monitors = Settings.data.wallpaper.monitors || []
if (monitor !== undefined) { var found = false
monitor.directory = directory
} else { // Create a new array with updated values
Settings.data.wallpaper.monitors.push({ var newMonitors = monitors.map(function (monitor) {
"name": screenName, if (monitor.name === screenName) {
"directory": directory, found = true
"wallpaper": "" return {
}) "name": screenName,
"directory": directory,
"wallpaper": monitor.wallpaper || ""
}
}
return monitor
})
if (!found) {
newMonitors.push({
"name": screenName,
"directory": directory,
"wallpaper": ""
})
} }
// Update Settings with new array to ensure proper persistence
Settings.data.wallpaper.monitors = newMonitors.slice()
root.wallpaperDirectoryChanged(screenName, directory)
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get specific monitor wallpaper // Get specific monitor wallpaper - now from cache
function getWallpaper(screenName) { function getWallpaper(screenName) {
var monitor = getMonitorConfig(screenName) return currentWallpapers[screenName] || ""
if ((monitor !== undefined) && (monitor["wallpaper"] !== undefined)) {
return monitor["wallpaper"]
}
return ""
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -142,30 +198,53 @@ Singleton {
} }
//Logger.log("Wallpaper", "setWallpaper on", screenName, ": ", path) //Logger.log("Wallpaper", "setWallpaper on", screenName, ": ", path)
var wallpaperChanged = false
var monitor = getMonitorConfig(screenName) // Check if wallpaper actually changed
if (monitor !== undefined) { var oldPath = currentWallpapers[screenName] || ""
wallpaperChanged = (monitor["wallpaper"] !== path) var wallpaperChanged = (oldPath !== path)
monitor["wallpaper"] = path
} else { if (!wallpaperChanged) {
wallpaperChanged = true // No change needed
Settings.data.wallpaper.monitors.push({ return
"name": screenName,
"directory": getMonitorDirectory(screenName),
"wallpaper": path
})
} }
// Update cache directly
currentWallpapers[screenName] = path
// Update Settings - still need immutable update for Settings persistence
// The slice() ensures Settings detects the change and saves properly
var monitors = Settings.data.wallpaper.monitors || []
var found = false
var newMonitors = monitors.map(function (monitor) {
if (monitor.name === screenName) {
found = true
return {
"name": screenName,
"directory": monitor.directory || getMonitorDirectory(screenName),
"wallpaper": path
}
}
return monitor
})
if (!found) {
newMonitors.push({
"name": screenName,
"directory": getMonitorDirectory(screenName),
"wallpaper": path
})
}
Settings.data.wallpaper.monitors = newMonitors.slice()
// Emit signal for this specific wallpaper change
root.wallpaperChanged(screenName, path)
// Restart the random wallpaper timer // Restart the random wallpaper timer
if (randomWallpaperTimer.running) { if (randomWallpaperTimer.running) {
randomWallpaperTimer.restart() randomWallpaperTimer.restart()
} }
// Notify ColorScheme service if the wallpaper actually changed
if (wallpaperChanged) {
ColorSchemeService.changedWallpaper()
}
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -200,7 +279,7 @@ Singleton {
function toggleRandomWallpaper() { function toggleRandomWallpaper() {
Logger.log("Wallpaper", "toggleRandomWallpaper") Logger.log("Wallpaper", "toggleRandomWallpaper")
if (Settings.data.wallpaper.randomEnabled) { if (Settings.data.wallpaper.randomEnabled) {
randomWallpaperTimer.restart() restartRandomWallpaperTimer()
setRandomWallpaper() setRandomWallpaper()
} }
} }
@ -208,8 +287,7 @@ Singleton {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function restartRandomWallpaperTimer() { function restartRandomWallpaperTimer() {
if (Settings.data.wallpaper.isRandom) { if (Settings.data.wallpaper.isRandom) {
randomWallpaperTimer.stop() randomWallpaperTimer.restart()
randomWallpaperTimer.start()
} }
} }
@ -255,23 +333,35 @@ Singleton {
model: Quickshell.screens model: Quickshell.screens
delegate: FolderListModel { delegate: FolderListModel {
property string screenName: modelData.name property string screenName: modelData.name
property string currentDirectory: root.getMonitorDirectory(screenName)
folder: "file://" + root.getMonitorDirectory(screenName) folder: "file://" + currentDirectory
nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.pnm", "*.bmp"] nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.pnm", "*.bmp"]
showDirs: false showDirs: false
sortField: FolderListModel.Name sortField: FolderListModel.Name
// Watch for directory changes via property binding
onCurrentDirectoryChanged: {
folder = "file://" + currentDirectory
}
Component.onCompleted: {
// Connect to directory change signal
root.wallpaperDirectoryChanged.connect(function (screen, directory) {
if (screen === screenName) {
currentDirectory = directory
}
})
}
onStatusChanged: { onStatusChanged: {
if (status === FolderListModel.Null) { if (status === FolderListModel.Null) {
// Flush the list // Flush the list
var lists = root.wallpaperLists root.wallpaperLists[screenName] = []
lists[screenName] = [] root.wallpaperListChanged(screenName, 0)
root.wallpaperLists = lists
} else if (status === FolderListModel.Loading) { } else if (status === FolderListModel.Loading) {
// Flush the list // Flush the list
var lists = root.wallpaperLists root.wallpaperLists[screenName] = []
lists[screenName] = []
root.wallpaperLists = lists
scanningCount++ scanningCount++
} else if (status === FolderListModel.Ready) { } else if (status === FolderListModel.Ready) {
var files = [] var files = []
@ -281,12 +371,12 @@ Singleton {
files.push(filepath) files.push(filepath)
} }
var lists = root.wallpaperLists // Update the list
lists[screenName] = files root.wallpaperLists[screenName] = files
root.wallpaperLists = lists
scanningCount-- scanningCount--
Logger.log("Wallpaper", "List refreshed for", screenName, "count:", files.length) Logger.log("Wallpaper", "List refreshed for", screenName, "count:", files.length)
root.wallpaperListChanged(screenName, files.length)
} }
} }
} }