Merge branch 'wallpaper-selector'

This commit is contained in:
LemmyCook
2025-09-18 18:22:32 -04:00
10 changed files with 497 additions and 318 deletions
+3
View File
@@ -177,6 +177,9 @@ Singleton {
MatugenService.init()
// Ensure wallpapers are restored after settings have been loaded
WallpaperService.init()
FontService.init()
HooksService.init()
+6
View File
@@ -127,6 +127,12 @@ Item {
// Wallpaper IPC: trigger a new random wallpaper
IpcHandler {
target: "wallpaper"
function toggle() {
if (Settings.data.wallpaper.enabled) {
wallpaperSelector.toggle()
}
}
function random() {
if (Settings.data.wallpaper.enabled) {
WallpaperService.setRandomWallpaper()
+19 -40
View File
@@ -21,6 +21,8 @@ NPanel {
panelKeyboardFocus: true
draggable: true
// Tabs enumeration, order is NOT relevant
enum Tab {
About,
@@ -36,8 +38,7 @@ NPanel {
Network,
Notification,
ScreenRecorder,
Wallpaper,
WallpaperSelector
Wallpaper
}
property int requestedTab: SettingsPanel.Tab.General
@@ -45,13 +46,6 @@ NPanel {
property var tabsModel: []
property var activeScrollView: null
Connections {
target: Settings.data.wallpaper
function onEnabledChanged() {
updateTabsModel()
}
}
Component.onCompleted: {
updateTabsModel()
}
@@ -92,10 +86,7 @@ NPanel {
id: wallpaperTab
Tabs.WallpaperTab {}
}
Component {
id: wallpaperSelectorTab
Tabs.WallpaperSelectorTab {}
}
Component {
id: screenRecorderTab
Tabs.ScreenRecorderTab {}
@@ -174,35 +165,23 @@ NPanel {
"label": "Wallpaper",
"icon": "settings-wallpaper",
"source": wallpaperTab
}, {
"id": SettingsPanel.Tab.ScreenRecorder,
"label": "Screen Recorder",
"icon": "settings-screen-recorder",
"source": screenRecorderTab
}, {
"id": SettingsPanel.Tab.Hooks,
"label": "Hooks",
"icon": "settings-hooks",
"source": hooksTab
}, {
"id": SettingsPanel.Tab.About,
"label": "About",
"icon": "settings-about",
"source": aboutTab
}]
// Only add the Wallpaper Selector tab if the feature is enabled
if (Settings.data.wallpaper.enabled) {
newTabs.push({
"id": SettingsPanel.Tab.WallpaperSelector,
"label": "Wallpaper Selector",
"icon": "settings-wallpaper-selector",
"source": wallpaperSelectorTab
})
}
newTabs.push({
"id": SettingsPanel.Tab.ScreenRecorder,
"label": "Screen Recorder",
"icon": "settings-screen-recorder",
"source": screenRecorderTab
}, {
"id": SettingsPanel.Tab.Hooks,
"label": "Hooks",
"icon": "settings-hooks",
"source": hooksTab
}, {
"id": SettingsPanel.Tab.About,
"label": "About",
"icon": "settings-about",
"source": aboutTab
})
root.tabsModel = newTabs // Assign the generated list to the model
}
// When the panel opens, choose the appropriate tab
@@ -1,268 +0,0 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Qt.labs.folderlistmodel
import qs.Commons
import qs.Services
import qs.Widgets
ColumnLayout {
id: root
width: parent.width
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
NHeader {
label: "Current Wallpaper"
description: "Preview and manage your desktop background."
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 140 * scaling
radius: Style.radiusM * scaling
color: Color.transparent
NImageRounded {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: currentWallpaper
fallbackIcon: "image"
imageRadius: Style.radiusM * scaling
borderColor: Color.mSecondary
borderWidth: Style.borderL * 2 * scaling
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
// Wallpaper selector
RowLayout {
Layout.fillWidth: true
ColumnLayout {
Layout.fillWidth: true
// Wallpaper grid
NHeader {
label: "Wallpaper Selector"
description: "Click on a wallpaper to set it as your current wallpaper."
}
}
NIconButton {
icon: "refresh"
tooltipText: "Refresh wallpaper list"
onClicked: {
WallpaperService.refreshWallpapersList()
}
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
}
}
NToggle {
label: "Apply to all monitors"
description: "Apply selected wallpaper to all monitors at once."
checked: Settings.data.wallpaper.setWallpaperOnAllMonitors
onToggled: checked => Settings.data.wallpaper.setWallpaperOnAllMonitors = checked
visible: (wallpapersList.length > 0)
}
// Wallpaper grid container
Item {
visible: !WallpaperService.scanning
Layout.fillWidth: true
Layout.preferredHeight: {
return Math.ceil(wallpapersList.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
}
GridView {
id: wallpaperGridView
anchors.fill: parent
model: wallpapersList
interactive: false
clip: true
property int columns: 4
property int itemSize: Math.floor((width - leftMargin - rightMargin - (4 * Style.marginS * scaling)) / columns)
cellWidth: Math.floor((width - leftMargin - rightMargin) / columns)
cellHeight: Math.floor(itemSize * 0.67) + Style.marginS * scaling
leftMargin: Style.marginS * scaling
rightMargin: Style.marginS * scaling
topMargin: Style.marginS * scaling
bottomMargin: Style.marginS * scaling
delegate: Rectangle {
id: wallpaperItem
property string wallpaperPath: modelData
property bool isSelected: screen ? (wallpaperPath === currentWallpaper) : false
width: wallpaperGridView.itemSize
height: Math.round(wallpaperGridView.itemSize * 0.67)
color: Color.transparent
// NImageCached relies on the image being visible to work properly.
// MultiEffect relies on the image being invisible to apply effects.
// That's why we don't have rounded corners here, as we don't want to bring back qt5compat.
NImageCached {
id: img
imagePath: wallpaperPath
anchors.fill: parent
}
// Borders on top
Rectangle {
anchors.fill: parent
color: Color.transparent
border.color: isSelected ? Color.mSecondary : Color.mSurface
border.width: Math.max(1, Style.borderL * 1.5 * scaling)
}
// Selection tick-mark
Rectangle {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Style.marginS * scaling
width: 28 * scaling
height: 28 * scaling
radius: width / 2
color: Color.mSecondary
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: isSelected
NIcon {
icon: "check"
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
anchors.centerIn: parent
}
}
// Hover effect
Rectangle {
anchors.fill: parent
color: Color.mSurface
opacity: (mouseArea.containsMouse || isSelected) ? 0 : 0.3
radius: parent.radius
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onPressed: {
if (Settings.data.wallpaper.setWallpaperOnAllMonitors) {
WallpaperService.changeWallpaper(wallpaperPath, undefined)
} else if (screen) {
WallpaperService.changeWallpaper(wallpaperPath, screen.name)
}
}
}
}
}
}
// Empty state
Rectangle {
color: Color.mSurface
radius: Style.radiusM * scaling
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: wallpapersList.length === 0 || WallpaperService.scanning
Layout.fillWidth: true
Layout.preferredHeight: 130 * scaling
ColumnLayout {
anchors.fill: parent
visible: WallpaperService.scanning
NBusyIndicator {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
ColumnLayout {
anchors.fill: parent
visible: wallpapersList.length === 0 && !WallpaperService.scanning
Item {
Layout.fillHeight: true
}
NIcon {
icon: "folder-open"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mOnSurface
Layout.alignment: Qt.AlignHCenter
}
NText {
text: "No wallpaper found."
color: Color.mOnSurface
font.weight: Style.fontWeightBold
Layout.alignment: Qt.AlignHCenter
}
NText {
text: "Make sure your wallpaper directory is configured and contains image files."
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.alignment: Qt.AlignHCenter
}
Item {
Layout.fillHeight: true
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
}
+2 -8
View File
@@ -55,14 +55,8 @@ NBox {
visible: Settings.data.wallpaper.enabled
icon: "wallpaper-selector"
tooltipText: "Left click: Open wallpaper selector.\nRight click: Set random wallpaper."
onClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
settingsPanel.requestedTab = SettingsPanel.Tab.WallpaperSelector
settingsPanel.open()
}
onRightClicked: {
WallpaperService.setRandomWallpaper()
}
onClicked: PanelService.getPanel("wallpaperSelector")?.toggle(this)
onRightClicked: WallpaperService.setRandomWallpaper()
}
Item {
@@ -0,0 +1,353 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import qs.Commons
import qs.Services
import qs.Widgets
import "../../Helpers/FuzzySort.js" as FuzzySort
NPanel {
id: root
preferredWidth: 640
preferredHeight: 480
preferredWidthRatio: 0.4
preferredHeightRatio: 0.52
panelAnchorHorizontalCenter: true
panelAnchorVerticalCenter: true
panelKeyboardFocus: true
draggable: true
panelContent: Rectangle {
// Local reactive state
property list<string> wallpapersList: []
property string currentWallpaper: ""
property string filterText: ""
property list<string> filteredWallpapers: []
Component.onCompleted: {
refreshWallpaperScreenData()
}
Connections {
target: WallpaperService
function onWallpaperChanged(screenName, path) {
if (screen !== null && screenName === screen.name) {
currentWallpaper = WallpaperService.getWallpaper(screen.name)
}
}
function onWallpaperDirectoryChanged(screenName, directory) {
if (screen !== null && screenName === screen.name) {
refreshWallpaperScreenData()
}
}
function onWallpaperListChanged(screenName, count) {
if (screen !== null && screenName === screen.name) {
refreshWallpaperScreenData()
}
}
}
function refreshWallpaperScreenData() {
if (screen === null) {
return
}
wallpapersList = WallpaperService.getWallpapersList(screen.name)
currentWallpaper = WallpaperService.getWallpaper(screen.name)
updateFiltered()
}
function updateFiltered() {
if (!filterText || filterText.trim().length === 0) {
filteredWallpapers = wallpapersList
return
}
// Build objects with basename for ranking
const items = wallpapersList.map(function (p) {
return {
"path": p,
"name": p.split('/').pop()
}
})
const results = FuzzySort.go(filterText.trim(), items, {
"key": 'name',
"limit": 200
})
// Map back to path list
filteredWallpapers = results.map(function (r) {
return r.obj.path
})
}
color: Color.transparent
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginL * scaling
spacing: Style.marginM * scaling
// Header
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM * scaling
NIcon {
icon: "settings-wallpaper-selector"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
NText {
text: "Wallpaper Selector"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.fillWidth: true
}
NIconButton {
icon: "refresh"
tooltipText: "Refresh wallpaper list."
baseSize: Style.baseWidgetSize * 0.8
onClicked: WallpaperService.refreshWallpapersList()
}
NIconButton {
icon: "close"
tooltipText: "Close."
baseSize: Style.baseWidgetSize * 0.8
onClicked: root.close()
}
}
NDivider {
Layout.fillWidth: true
}
NToggle {
label: "Apply to all monitors"
description: "Apply selected wallpaper to all monitors at once."
checked: Settings.data.wallpaper.setWallpaperOnAllMonitors
onToggled: checked => Settings.data.wallpaper.setWallpaperOnAllMonitors = checked
visible: (wallpapersList.length > 0)
Layout.fillWidth: true
}
// Filter input
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM * scaling
NText {
text: "Search:"
color: Color.mOnSurface
font.pointSize: Style.fontSizeM * scaling
Layout.preferredWidth: implicitWidth
}
NTextInput {
id: searchInput
placeholderText: "Type to filter wallpapers..."
text: filterText
onTextChanged: {
filterText = text
updateFiltered()
}
Layout.fillWidth: true
Component.onCompleted: {
if (searchInput.inputItem && searchInput.inputItem.visible) {
searchInput.inputItem.forceActiveFocus()
}
}
}
}
// Scroll container for wallpaper grid only
Flickable {
Layout.fillWidth: true
Layout.fillHeight: true
pressDelay: 200
NScrollView {
id: scrollView
anchors.fill: parent
horizontalPolicy: ScrollBar.AlwaysOff
verticalPolicy: ScrollBar.AsNeeded
padding: Style.marginL * 0 * scaling
clip: true
ColumnLayout {
width: scrollView.availableWidth
spacing: Style.marginM * scaling
// Grid container
Item {
visible: !WallpaperService.scanning
Layout.fillWidth: true
Layout.preferredHeight: Math.ceil(filteredWallpapers.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
GridView {
id: wallpaperGridView
anchors.fill: parent
model: filteredWallpapers
interactive: false
property int columns: 4
property int itemSize: Math.floor((width - leftMargin - rightMargin - (columns * Style.marginS * scaling)) / columns)
cellWidth: Math.floor((width - leftMargin - rightMargin) / columns)
cellHeight: Math.floor(itemSize * 0.7) + Style.marginXS * scaling + Style.fontSizeXS * scaling + Style.marginM * scaling
leftMargin: Style.marginS * scaling
rightMargin: Style.marginS * scaling
topMargin: Style.marginS * scaling
bottomMargin: Style.marginS * scaling
delegate: ColumnLayout {
id: wallpaperItem
property string wallpaperPath: modelData
property bool isSelected: (wallpaperPath === currentWallpaper)
property string filename: wallpaperPath.split('/').pop()
width: wallpaperGridView.itemSize
spacing: Style.marginXS * scaling
Rectangle {
id: imageContainer
Layout.fillWidth: true
Layout.preferredHeight: Math.round(wallpaperGridView.itemSize * 0.67)
color: Color.transparent
NImageCached {
id: img
imagePath: wallpaperPath
anchors.fill: parent
}
Rectangle {
anchors.fill: parent
color: Color.transparent
border.color: isSelected ? Color.mSecondary : Color.mSurface
border.width: Math.max(1, Style.borderL * 1.5 * scaling)
}
Rectangle {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Style.marginS * scaling
width: 28 * scaling
height: 28 * scaling
radius: width / 2
color: Color.mSecondary
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: isSelected
NIcon {
icon: "check"
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
anchors.centerIn: parent
}
}
Rectangle {
anchors.fill: parent
color: Color.mSurface
opacity: (mouseArea.containsMouse || isSelected) ? 0 : 0.3
radius: parent.radius
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onPressed: {
if (Settings.data.wallpaper.setWallpaperOnAllMonitors) {
WallpaperService.changeWallpaper(wallpaperPath, undefined)
} else {
WallpaperService.changeWallpaper(wallpaperPath, Screen.name)
}
}
}
}
NText {
text: filename
color: Color.mOnSurfaceVariant
opacity: 0.5
font.pointSize: Style.fontSizeXS * scaling
Layout.fillWidth: true
Layout.leftMargin: Style.marginS * scaling
Layout.rightMargin: Style.marginS * scaling
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
}
}
}
// Empty / scanning state
Rectangle {
color: Color.mSurface
radius: Style.radiusM * scaling
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: (filteredWallpapers.length === 0 && !WallpaperService.scanning) || WallpaperService.scanning
Layout.fillWidth: true
Layout.preferredHeight: 130 * scaling
ColumnLayout {
anchors.fill: parent
visible: WallpaperService.scanning
NBusyIndicator {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
ColumnLayout {
anchors.fill: parent
visible: filteredWallpapers.length === 0 && !WallpaperService.scanning
Item {
Layout.fillHeight: true
}
NIcon {
icon: "folder-open"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mOnSurface
Layout.alignment: Qt.AlignHCenter
}
NText {
text: (filterText && filterText.length > 0) ? "No match found." : "No wallpaper found."
color: Color.mOnSurface
font.weight: Style.fontWeightBold
Layout.alignment: Qt.AlignHCenter
}
NText {
text: (filterText && filterText.length > 0) ? "Try a different search query." : "Configure your wallpaper directory with images."
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.alignment: Qt.AlignHCenter
}
Item {
Layout.fillHeight: true
}
}
}
}
}
}
}
}
}
+5
View File
@@ -47,6 +47,11 @@ Singleton {
// Generate colors using current wallpaper and settings
function generateFromWallpaper() {
if (!Settings.isLoaded) {
Logger.log("Matugen", "Settings not loaded yet, skipping wallpaper color generation")
return
}
Logger.log("Matugen", "Generating from wallpaper on screen:", Screen.name)
var wp = WallpaperService.getWallpaper(Screen.name).replace(/'/g, "'\\''")
if (wp === "") {
+14
View File
@@ -9,6 +9,20 @@ import qs.Commons
Singleton {
id: root
// Public init to rehydrate cache after Settings load
function init() {
// Rebuild cache from persisted settings
var monitors = Settings.data.wallpaper.monitors || []
currentWallpapers = ({})
for (var i = 0; i < monitors.length; i++) {
if (monitors[i].name && monitors[i].wallpaper) {
currentWallpapers[monitors[i].name] = monitors[i].wallpaper
// Notify listeners so Background updates immediately after settings load
root.wallpaperChanged(monitors[i].name, monitors[i].wallpaper)
}
}
}
Component.onCompleted: {
Logger.log("Wallpaper", "Service started")
+89 -2
View File
@@ -16,6 +16,7 @@ Loader {
property real preferredWidthRatio
property real preferredHeightRatio
property color panelBackgroundColor: Color.mSurface
property bool draggable: false
property bool panelAnchorHorizontalCenter: false
property bool panelAnchorVerticalCenter: false
@@ -215,6 +216,11 @@ Loader {
radius: Style.radiusL * scaling
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
// Dragging support
property bool draggable: root.draggable
property bool isDragged: false
property real manualX: 0
property real manualY: 0
width: {
var w
if (preferredWidthRatio !== undefined) {
@@ -239,8 +245,8 @@ Loader {
scale: root.scaleValue
opacity: root.opacityValue
x: calculatedX
y: calculatedY
x: isDragged ? manualX : calculatedX
y: isDragged ? manualY : calculatedY
// ---------------------------------------------
// Does not account for corners are they are negligible and helps keep the code clean.
@@ -373,6 +379,14 @@ Loader {
root.opacityValue = 1.0
}
// Reset drag position when panel closes
Connections {
target: root
function onClosed() {
panelBackground.isDragged = false
}
}
// Prevent closing when clicking in the panel bg
MouseArea {
anchors.fill: parent
@@ -398,6 +412,79 @@ Loader {
anchors.fill: parent
sourceComponent: root.panelContent
}
// Handle drag move on the whole panel area
DragHandler {
id: dragHandler
target: null
enabled: panelBackground.draggable
property real dragStartX: 0
property real dragStartY: 0
onActiveChanged: {
if (active) {
// Capture current position into manual coordinates BEFORE toggling isDragged
panelBackground.manualX = panelBackground.x
panelBackground.manualY = panelBackground.y
dragStartX = panelBackground.x
dragStartY = panelBackground.y
panelBackground.isDragged = true
if (root.enableBackgroundClick)
root.disableBackgroundClick()
} else {
// Keep isDragged true so we continue using the manual x/y after release
if (root.enableBackgroundClick)
root.enableBackgroundClick()
}
}
onTranslationChanged: {
// Proposed new coordinates from fixed drag origin
var nx = dragStartX + translation.x
var ny = dragStartY + translation.y
// Calculate gaps so we never overlap the bar on any side
var baseGap = Style.marginS * scaling
var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0
var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0
var insetLeft = baseGap + ((barIsVisible && barPosition === "left") ? (Style.barHeight * scaling + floatExtraH) : 0)
var insetRight = baseGap + ((barIsVisible && barPosition === "right") ? (Style.barHeight * scaling + floatExtraH) : 0)
var insetTop = baseGap + ((barIsVisible && barPosition === "top") ? (Style.barHeight * scaling + floatExtraV) : 0)
var insetBottom = baseGap + ((barIsVisible && barPosition === "bottom") ? (Style.barHeight * scaling + floatExtraV) : 0)
// Clamp within screen bounds accounting for insets
var maxX = panelWindow.width - panelBackground.width - insetRight
var minX = insetLeft
var maxY = panelWindow.height - panelBackground.height - insetBottom
var minY = insetTop
panelBackground.manualX = Math.round(Math.max(minX, Math.min(nx, maxX)))
panelBackground.manualY = Math.round(Math.max(minY, Math.min(ny, maxY)))
}
}
// Drag indicator border
Rectangle {
anchors.fill: parent
anchors.margins: 0
color: Color.transparent
border.color: Color.mPrimary
border.width: Math.max(2, Style.borderL * scaling)
radius: parent.radius
visible: panelBackground.isDragged && dragHandler.active
opacity: 0.8
z: 3000
// Subtle glow effect
Rectangle {
anchors.fill: parent
anchors.margins: 0
color: Color.transparent
border.color: Color.mPrimary
border.width: Math.max(1, Style.borderS * scaling)
radius: parent.radius
opacity: 0.3
}
}
}
}
}
+6
View File
@@ -28,6 +28,7 @@ import qs.Modules.PowerPanel
import qs.Modules.SidePanel
import qs.Modules.Toast
import qs.Modules.WiFiPanel
import qs.Modules.WallpaperSelector
import qs.Services
import qs.Widgets
@@ -94,6 +95,11 @@ ShellRoot {
objectName: "bluetoothPanel"
}
WallpaperSelector {
id: wallpaperSelector
objectName: "wallpaperSelector"
}
Component.onCompleted: {
// Save a ref. to our lockScreen so we can access it easily
PanelService.lockScreen = lockScreen