WallpaperPanel: add settings popup for wallhaveb

WallhavenSettingsPopup: move all settings in here
WallhavenService: adjust some things
This commit is contained in:
Ly-sec
2025-11-15 19:48:19 +01:00
parent 8010b32c29
commit 0314d2445e
14 changed files with 973 additions and 259 deletions
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "Mindestens",
"exact": "Exakt",
"label": "Auflösung",
"mode": {
"label": "Modus"
}
},
"search": "Suchen:",
"sorting": {
"date_added": "Hinzugefügt am",
"favorites": "Favoriten",
"label": "Sortieren nach",
"random": "Zufällig",
"relevance": "Relevanz",
"toplist": "Topliste",
"views": "Aufrufe"
},
"order": {
"asc": "Aufsteigend",
"desc": "Absteigend",
"label": "Reihenfolge"
},
"wallhaven-settings": {
"apply": "Anwenden",
"title": "Wallhaven-Einstellungen"
},
"source": {
"label": "Quelle",
"local": "Lokal",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "At least",
"exact": "Exact",
"label": "Resolution",
"mode": {
"label": "Mode"
}
},
"search": "Search",
"sorting": {
"date_added": "Date added",
"favorites": "Favorites",
"label": "Sort by",
"random": "Random",
"relevance": "Relevance",
"toplist": "Toplist",
"views": "Views"
},
"order": {
"asc": "Ascending",
"desc": "Descending",
"label": "Order"
},
"wallhaven-settings": {
"apply": "Apply",
"title": "Wallhaven Settings"
},
"source": {
"label": "Source",
"local": "Local",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "Al menos",
"exact": "Exacto",
"label": "Resolución",
"mode": {
"label": "Modo"
}
},
"search": "Buscar:",
"sorting": {
"date_added": "Fecha de adición",
"favorites": "Favoritos",
"label": "Ordenar por",
"random": "Aleatorio",
"relevance": "Relevancia",
"toplist": "Lista superior",
"views": "Visualizaciones"
},
"order": {
"asc": "Ascendente",
"desc": "Descendente",
"label": "Orden"
},
"wallhaven-settings": {
"apply": "Aplicar",
"title": "Configuración de Wallhaven"
},
"source": {
"label": "Fuente",
"local": "Local",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "Au moins",
"exact": "Exact",
"label": "Résolution",
"mode": {
"label": "Mode"
}
},
"search": "Rechercher :",
"sorting": {
"date_added": "Date d'ajout",
"favorites": "Favoris",
"label": "Trier par",
"random": "Aléatoire",
"relevance": "Pertinence",
"toplist": "Top liste",
"views": "Vues"
},
"order": {
"asc": "Croissant",
"desc": "Décroissant",
"label": "Ordre"
},
"wallhaven-settings": {
"apply": "Appliquer",
"title": "Paramètres Wallhaven"
},
"source": {
"label": "Source",
"local": "Local",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "Ten minste",
"exact": "Exact",
"label": "Resolutie",
"mode": {
"label": "Modus"
}
},
"search": "Zoeken:",
"sorting": {
"date_added": "Datum toegevoegd",
"favorites": "Favorieten",
"label": "Sorteren op",
"random": "Willekeurig",
"relevance": "Relevantie",
"toplist": "Toplijst",
"views": "Weergaven"
},
"order": {
"asc": "Oplopend",
"desc": "Aflopend",
"label": "Volgorde"
},
"wallhaven-settings": {
"apply": "Toepassen",
"title": "Wallhaven-instellingen"
},
"source": {
"label": "Bron",
"local": "Lokaal",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "Pelo menos",
"exact": "Exato",
"label": "Resolução",
"mode": {
"label": "Modo"
}
},
"search": "Pesquisar:",
"sorting": {
"date_added": "Data de adição",
"favorites": "Favoritos",
"label": "Ordenar por",
"random": "Aleatório",
"relevance": "Relevância",
"toplist": "Lista superior",
"views": "Visualizações"
},
"order": {
"asc": "Crescente",
"desc": "Decrescente",
"label": "Ordem"
},
"wallhaven-settings": {
"apply": "Aplicar",
"title": "Configurações do Wallhaven"
},
"source": {
"label": "Fonte",
"local": "Local",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "По крайней мере",
"exact": "Точно",
"label": "Разрешение",
"mode": {
"label": "Режим"
}
},
"search": "Поиск:",
"sorting": {
"date_added": "Дата добавления",
"favorites": "Избранное",
"label": "Сортировать по",
"random": "Случайно",
"relevance": "Релевантность",
"toplist": "Топ-лист",
"views": "Просмотры"
},
"order": {
"asc": "По возрастанию",
"desc": "По убыванию",
"label": "Порядок"
},
"wallhaven-settings": {
"apply": "Применить",
"title": "Настройки Wallhaven"
},
"source": {
"label": "Источник",
"local": "Локальный",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "En az",
"exact": "Tam",
"label": "Çözünürlük",
"mode": {
"label": "Mod"
}
},
"search": "Ara:",
"sorting": {
"date_added": "Eklenme tarihi",
"favorites": "Favoriler",
"label": "Sırala",
"random": "Rastgele",
"relevance": "Alaka",
"toplist": "En iyi liste",
"views": "Görüntülemeler"
},
"order": {
"asc": "Artan",
"desc": "Azalan",
"label": "Sıra"
},
"wallhaven-settings": {
"apply": "Uygula",
"title": "Wallhaven Ayarları"
},
"source": {
"label": "Kaynak",
"local": "Yerel",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "Принаймні",
"exact": "Точно",
"label": "Роздільна здатність",
"mode": {
"label": "Режим"
}
},
"search": "Пошук:",
"sorting": {
"date_added": "Дата додавання",
"favorites": "Обране",
"label": "Сортувати за",
"random": "Випадково",
"relevance": "Релевантність",
"toplist": "Топ-лист",
"views": "Перегляди"
},
"order": {
"asc": "За зростанням",
"desc": "За спаданням",
"label": "Порядок"
},
"wallhaven-settings": {
"apply": "Застосувати",
"title": "Налаштування Wallhaven"
},
"source": {
"label": "Джерело",
"local": "Локальний",
+26
View File
@@ -2053,7 +2053,33 @@
"sfw": "SFW",
"sketchy": "Sketchy"
},
"resolution": {
"atleast": "至少",
"exact": "精确",
"label": "分辨率",
"mode": {
"label": "模式"
}
},
"search": "搜索:",
"sorting": {
"date_added": "添加日期",
"favorites": "收藏",
"label": "排序方式",
"random": "随机",
"relevance": "相关性",
"toplist": "排行榜",
"views": "浏览量"
},
"order": {
"asc": "升序",
"desc": "降序",
"label": "顺序"
},
"wallhaven-settings": {
"apply": "应用",
"title": "Wallhaven 设置"
},
"source": {
"label": "来源",
"local": "本地",
+3
View File
@@ -270,6 +270,9 @@ Singleton {
property string wallhavenOrder: "desc"
property string wallhavenCategories: "111" // general,anime,people
property string wallhavenPurity: "100" // sfw only
property string wallhavenResolutionMode: "atleast" // "atleast" or "exact"
property string wallhavenResolutionWidth: ""
property string wallhavenResolutionHeight: ""
}
// applauncher
@@ -0,0 +1,631 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services.UI
import qs.Widgets
Popup {
id: root
property ShellScreen screen
property Item anchorItem: null
width: 400
height: contentColumn.implicitHeight + (Style.marginL * 2)
padding: Style.marginL
modal: true
dim: false
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
parent: anchorItem ? anchorItem.parent : Overlay.overlay
x: {
if (anchorItem) {
var itemPos = anchorItem.mapToItem(parent, 0, 0)
return itemPos.x - width + anchorItem.width
}
return 0
}
y: {
if (anchorItem) {
var itemPos = anchorItem.mapToItem(parent, 0, 0)
return itemPos.y + anchorItem.height + Style.marginS
}
return 0
}
function showAt(item) {
if (!item) {
return
}
anchorItem = item
open()
Qt.callLater(() => {
// Try to focus the first input if available
if (resolutionWidthInput.inputItem) {
resolutionWidthInput.inputItem.forceActiveFocus()
}
})
}
onOpened: {
Qt.callLater(() => {
if (resolutionWidthInput.inputItem) {
resolutionWidthInput.inputItem.forceActiveFocus()
}
})
}
function hide() {
close()
}
function updateResolution(triggerSearch) {
if (typeof WallhavenService === "undefined") {
return
}
var width = Settings.data.wallpaper.wallhavenResolutionWidth || ""
var height = Settings.data.wallpaper.wallhavenResolutionHeight || ""
var mode = Settings.data.wallpaper.wallhavenResolutionMode || "atleast"
if (width && height) {
var resolution = width + "x" + height
if (mode === "atleast") {
WallhavenService.minResolution = resolution
WallhavenService.resolutions = ""
} else {
WallhavenService.minResolution = ""
WallhavenService.resolutions = resolution
}
} else {
WallhavenService.minResolution = ""
WallhavenService.resolutions = ""
}
// Trigger new search with updated resolution only if requested
if (triggerSearch && Settings.data.wallpaper.useWallhaven) {
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1)
}
}
background: Rectangle {
id: backgroundRect
color: Color.mSurface
radius: Style.radiusL
border.color: Color.mOutline
border.width: Style.borderM
NDropShadows {
source: backgroundRect
}
}
contentItem: ColumnLayout {
id: contentColumn
spacing: Style.marginM
// Header
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
NIcon {
icon: "settings"
pointSize: Style.fontSizeL
color: Color.mPrimary
}
NText {
text: I18n.tr("wallpaper.panel.wallhaven-settings.title")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.fillWidth: true
}
NIconButton {
icon: "close"
tooltipText: I18n.tr("tooltips.close")
baseSize: Style.baseWidgetSize * 0.8
onClicked: root.hide()
}
}
NDivider {
Layout.fillWidth: true
}
// Sorting
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
NText {
text: I18n.tr("wallpaper.panel.sorting.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
NComboBox {
id: sortingComboBox
Layout.fillWidth: true
model: [
{ "key": "date_added", "name": I18n.tr("wallpaper.panel.sorting.date_added") },
{ "key": "relevance", "name": I18n.tr("wallpaper.panel.sorting.relevance") },
{ "key": "random", "name": I18n.tr("wallpaper.panel.sorting.random") },
{ "key": "views", "name": I18n.tr("wallpaper.panel.sorting.views") },
{ "key": "favorites", "name": I18n.tr("wallpaper.panel.sorting.favorites") },
{ "key": "toplist", "name": I18n.tr("wallpaper.panel.sorting.toplist") }
]
currentKey: Settings.data.wallpaper.wallhavenSorting || "date_added"
onSelected: key => {
Settings.data.wallpaper.wallhavenSorting = key
if (typeof WallhavenService !== "undefined") {
WallhavenService.sorting = key
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1)
}
}
}
}
// Order
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
visible: sortingComboBox.currentKey !== "random"
NText {
text: I18n.tr("wallpaper.panel.order.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
NComboBox {
id: orderComboBox
Layout.fillWidth: true
model: [
{ "key": "desc", "name": I18n.tr("wallpaper.panel.order.desc") },
{ "key": "asc", "name": I18n.tr("wallpaper.panel.order.asc") }
]
currentKey: Settings.data.wallpaper.wallhavenOrder || "desc"
onSelected: key => {
Settings.data.wallpaper.wallhavenOrder = key
if (typeof WallhavenService !== "undefined") {
WallhavenService.order = key
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1)
}
}
}
}
// Purity selector
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
NText {
text: I18n.tr("wallpaper.panel.purity.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
NComboBox {
id: purityComboBox
Layout.fillWidth: true
model: [
{ "key": "111", "name": I18n.tr("wallpaper.panel.purity.all") },
{ "key": "100", "name": I18n.tr("wallpaper.panel.purity.sfw") },
{ "key": "010", "name": I18n.tr("wallpaper.panel.purity.sketchy") }
]
currentKey: Settings.data.wallpaper.wallhavenPurity
onSelected: key => {
Settings.data.wallpaper.wallhavenPurity = key
if (typeof WallhavenService !== "undefined") {
WallhavenService.purity = key
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1)
}
}
}
}
// Categories
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
NText {
text: I18n.tr("wallpaper.panel.categories.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
Item {
Layout.fillWidth: true
}
RowLayout {
id: categoriesRow
spacing: Style.marginL
function getCategoryValue(index) {
var cats = Settings.data.wallpaper.wallhavenCategories || "111"
return cats.length > index && cats.charAt(index) === "1"
}
function updateCategories(general, anime, people) {
var categories = (general ? "1" : "0") + (anime ? "1" : "0") + (people ? "1" : "0")
Settings.data.wallpaper.wallhavenCategories = categories
// Update checkboxes immediately
generalToggle.checked = general
animeToggle.checked = anime
peopleToggle.checked = people
if (typeof WallhavenService !== "undefined") {
WallhavenService.categories = categories
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery, 1)
}
}
Connections {
target: Settings.data.wallpaper
function onWallhavenCategoriesChanged() {
generalToggle.checked = categoriesRow.getCategoryValue(0)
animeToggle.checked = categoriesRow.getCategoryValue(1)
peopleToggle.checked = categoriesRow.getCategoryValue(2)
}
}
Component.onCompleted: {
generalToggle.checked = categoriesRow.getCategoryValue(0)
animeToggle.checked = categoriesRow.getCategoryValue(1)
peopleToggle.checked = categoriesRow.getCategoryValue(2)
}
// General checkbox
Item {
Layout.preferredWidth: generalCheckboxRow.implicitWidth
Layout.preferredHeight: generalCheckboxRow.implicitHeight
RowLayout {
id: generalCheckboxRow
anchors.fill: parent
spacing: Style.marginS
NText {
text: I18n.tr("wallpaper.panel.categories.general")
color: Color.mOnSurface
pointSize: Style.fontSizeM
}
Rectangle {
id: generalBox
implicitWidth: Math.round(Style.baseWidgetSize * 0.7)
implicitHeight: Math.round(Style.baseWidgetSize * 0.7)
radius: Style.radiusXS
color: generalToggle.checked ? Color.mPrimary : Color.mSurface
border.color: Color.mOutline
border.width: Style.borderS
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
NIcon {
visible: generalToggle.checked
anchors.centerIn: parent
anchors.horizontalCenterOffset: -1
icon: "check"
color: Color.mOnPrimary
pointSize: Math.max(Style.fontSizeXS, generalBox.width * 0.5)
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: generalToggle.toggled(!generalToggle.checked)
}
}
}
}
// Anime checkbox
Item {
Layout.preferredWidth: animeCheckboxRow.implicitWidth
Layout.preferredHeight: animeCheckboxRow.implicitHeight
RowLayout {
id: animeCheckboxRow
anchors.fill: parent
spacing: Style.marginS
NText {
text: I18n.tr("wallpaper.panel.categories.anime")
color: Color.mOnSurface
pointSize: Style.fontSizeM
}
Rectangle {
id: animeBox
implicitWidth: Math.round(Style.baseWidgetSize * 0.7)
implicitHeight: Math.round(Style.baseWidgetSize * 0.7)
radius: Style.radiusXS
color: animeToggle.checked ? Color.mPrimary : Color.mSurface
border.color: Color.mOutline
border.width: Style.borderS
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
NIcon {
visible: animeToggle.checked
anchors.centerIn: parent
anchors.horizontalCenterOffset: -1
icon: "check"
color: Color.mOnPrimary
pointSize: Math.max(Style.fontSizeXS, animeBox.width * 0.5)
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: animeToggle.toggled(!animeToggle.checked)
}
}
}
}
// People checkbox
Item {
Layout.preferredWidth: peopleCheckboxRow.implicitWidth
Layout.preferredHeight: peopleCheckboxRow.implicitHeight
RowLayout {
id: peopleCheckboxRow
anchors.fill: parent
spacing: Style.marginS
NText {
text: I18n.tr("wallpaper.panel.categories.people")
color: Color.mOnSurface
pointSize: Style.fontSizeM
}
Rectangle {
id: peopleBox
implicitWidth: Math.round(Style.baseWidgetSize * 0.7)
implicitHeight: Math.round(Style.baseWidgetSize * 0.7)
radius: Style.radiusXS
color: peopleToggle.checked ? Color.mPrimary : Color.mSurface
border.color: Color.mOutline
border.width: Style.borderS
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
NIcon {
visible: peopleToggle.checked
anchors.centerIn: parent
anchors.horizontalCenterOffset: -1
icon: "check"
color: Color.mOnPrimary
pointSize: Math.max(Style.fontSizeXS, peopleBox.width * 0.5)
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: peopleToggle.toggled(!peopleToggle.checked)
}
}
}
}
// Invisible checkboxes to maintain the signal handlers
QtObject {
id: generalToggle
property bool checked: false
signal toggled(bool checked)
onToggled: checked => {
categoriesRow.updateCategories(checked, categoriesRow.getCategoryValue(1), categoriesRow.getCategoryValue(2))
}
}
QtObject {
id: animeToggle
property bool checked: false
signal toggled(bool checked)
onToggled: checked => {
categoriesRow.updateCategories(categoriesRow.getCategoryValue(0), checked, categoriesRow.getCategoryValue(2))
}
}
QtObject {
id: peopleToggle
property bool checked: false
signal toggled(bool checked)
onToggled: checked => {
categoriesRow.updateCategories(categoriesRow.getCategoryValue(0), categoriesRow.getCategoryValue(1), checked)
}
}
}
}
// Resolution filter
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginS
NText {
text: I18n.tr("wallpaper.panel.resolution.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
}
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
NText {
text: I18n.tr("wallpaper.panel.resolution.mode.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
NComboBox {
id: resolutionModeComboBox
Layout.fillWidth: true
model: [
{ "key": "atleast", "name": I18n.tr("wallpaper.panel.resolution.atleast") },
{ "key": "exact", "name": I18n.tr("wallpaper.panel.resolution.exact") }
]
currentKey: Settings.data.wallpaper.wallhavenResolutionMode || "atleast"
Connections {
target: Settings.data.wallpaper
function onWallhavenResolutionModeChanged() {
if (resolutionModeComboBox.currentKey !== Settings.data.wallpaper.wallhavenResolutionMode) {
resolutionModeComboBox.currentKey = Settings.data.wallpaper.wallhavenResolutionMode || "atleast"
}
}
}
onSelected: key => {
Settings.data.wallpaper.wallhavenResolutionMode = key
updateResolution(false)
}
}
}
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
NTextInput {
id: resolutionWidthInput
Layout.preferredWidth: 80
placeholderText: "Width"
inputMethodHints: Qt.ImhDigitsOnly
text: Settings.data.wallpaper.wallhavenResolutionWidth || ""
Component.onCompleted: {
if (resolutionWidthInput.inputItem) {
resolutionWidthInput.inputItem.focusPolicy = Qt.StrongFocus
// Ensure the TextField can receive keyboard input
resolutionWidthInput.inputItem.activeFocusOnPress = true
}
}
// Ensure focus when clicked
onActiveFocusChanged: {
if (activeFocus && resolutionWidthInput.inputItem) {
resolutionWidthInput.inputItem.forceActiveFocus()
}
}
Connections {
target: Settings.data.wallpaper
function onWallhavenResolutionWidthChanged() {
if (resolutionWidthInput.text !== Settings.data.wallpaper.wallhavenResolutionWidth) {
resolutionWidthInput.text = Settings.data.wallpaper.wallhavenResolutionWidth || ""
}
}
}
onEditingFinished: {
Settings.data.wallpaper.wallhavenResolutionWidth = text
updateResolution(false)
}
}
NText {
text: "×"
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
NTextInput {
id: resolutionHeightInput
Layout.preferredWidth: 80
placeholderText: "Height"
inputMethodHints: Qt.ImhDigitsOnly
text: Settings.data.wallpaper.wallhavenResolutionHeight || ""
Component.onCompleted: {
if (resolutionHeightInput.inputItem) {
resolutionHeightInput.inputItem.focusPolicy = Qt.StrongFocus
resolutionHeightInput.inputItem.activeFocusOnPress = true
}
}
// Ensure focus when clicked
onActiveFocusChanged: {
if (activeFocus && resolutionHeightInput.inputItem) {
resolutionHeightInput.inputItem.forceActiveFocus()
}
}
Connections {
target: Settings.data.wallpaper
function onWallhavenResolutionHeightChanged() {
if (resolutionHeightInput.text !== Settings.data.wallpaper.wallhavenResolutionHeight) {
resolutionHeightInput.text = Settings.data.wallpaper.wallhavenResolutionHeight || ""
}
}
}
onEditingFinished: {
Settings.data.wallpaper.wallhavenResolutionHeight = text
updateResolution(false)
}
}
}
}
// Apply button
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginM
}
NButton {
Layout.fillWidth: true
text: I18n.tr("wallpaper.panel.wallhaven-settings.apply")
onClicked: {
// Ensure all settings are synced to the service
if (typeof WallhavenService !== "undefined" && Settings.data.wallpaper.useWallhaven) {
// Sync all settings to the service
WallhavenService.categories = Settings.data.wallpaper.wallhavenCategories
WallhavenService.purity = Settings.data.wallpaper.wallhavenPurity
WallhavenService.sorting = Settings.data.wallpaper.wallhavenSorting
WallhavenService.order = Settings.data.wallpaper.wallhavenOrder
// Update resolution settings (without triggering search)
updateResolution(false)
// Refresh the wallpaper search with current settings
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1)
// Close the popup after applying
root.hide()
}
}
}
}
}
+78 -258
View File
@@ -121,8 +121,52 @@ SmartPanel {
root.contentItem = wallpaperPanel
}
// Function to update Wallhaven resolution filter
function updateWallhavenResolution() {
if (typeof WallhavenService === "undefined") {
return
}
var width = Settings.data.wallpaper.wallhavenResolutionWidth || ""
var height = Settings.data.wallpaper.wallhavenResolutionHeight || ""
var mode = Settings.data.wallpaper.wallhavenResolutionMode || "atleast"
if (width && height) {
var resolution = width + "x" + height
if (mode === "atleast") {
WallhavenService.minResolution = resolution
WallhavenService.resolutions = ""
} else {
WallhavenService.minResolution = ""
WallhavenService.resolutions = resolution
}
} else {
WallhavenService.minResolution = ""
WallhavenService.resolutions = ""
}
// Trigger new search with updated resolution
if (Settings.data.wallpaper.useWallhaven) {
if (wallhavenView) {
wallhavenView.loading = true
}
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1)
}
}
color: Color.transparent
// Wallhaven settings popup
Loader {
id: wallhavenSettingsPopup
source: "WallhavenSettingsPopup.qml"
onLoaded: {
if (item) {
item.screen = screen
}
}
}
// Focus management
Connections {
target: root
@@ -364,6 +408,10 @@ SmartPanel {
WallhavenService.purity = Settings.data.wallpaper.wallhavenPurity
WallhavenService.sorting = Settings.data.wallpaper.wallhavenSorting
WallhavenService.order = Settings.data.wallpaper.wallhavenOrder
// Update resolution settings
wallpaperPanel.updateWallhavenResolution()
// If the view is already initialized, trigger a new search when switching to it
if (wallhavenView && wallhavenView.initialized && !WallhavenService.fetching) {
wallhavenView.loading = true
@@ -372,266 +420,20 @@ SmartPanel {
}
}
}
}
// Wallhaven category toggles
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
visible: Settings.data.wallpaper.useWallhaven
NText {
text: I18n.tr("wallpaper.panel.categories.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
Item {
Layout.fillWidth: true
}
RowLayout {
id: categoriesRow
spacing: Style.marginL
function getCategoryValue(index) {
var cats = Settings.data.wallpaper.wallhavenCategories || "111"
return cats.length > index && cats.charAt(index) === "1"
}
function updateCategories(general, anime, people) {
var categories = (general ? "1" : "0") + (anime ? "1" : "0") + (people ? "1" : "0")
Settings.data.wallpaper.wallhavenCategories = categories
// Update checkboxes immediately
generalToggle.checked = general
animeToggle.checked = anime
peopleToggle.checked = people
if (typeof WallhavenService !== "undefined") {
WallhavenService.categories = categories
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery, 1)
// Settings button (only visible for Wallhaven)
NIconButton {
id: wallhavenSettingsButton
icon: "settings"
tooltipText: I18n.tr("wallpaper.panel.wallhaven-settings.title")
baseSize: Style.baseWidgetSize * 0.8
visible: Settings.data.wallpaper.useWallhaven
onClicked: {
if (searchInput.inputItem) {
searchInput.inputItem.focus = false
}
}
Connections {
target: Settings.data.wallpaper
function onWallhavenCategoriesChanged() {
generalToggle.checked = categoriesRow.getCategoryValue(0)
animeToggle.checked = categoriesRow.getCategoryValue(1)
peopleToggle.checked = categoriesRow.getCategoryValue(2)
}
}
Component.onCompleted: {
generalToggle.checked = categoriesRow.getCategoryValue(0)
animeToggle.checked = categoriesRow.getCategoryValue(1)
peopleToggle.checked = categoriesRow.getCategoryValue(2)
}
// General checkbox
Item {
Layout.preferredWidth: generalCheckboxRow.implicitWidth
Layout.preferredHeight: generalCheckboxRow.implicitHeight
RowLayout {
id: generalCheckboxRow
anchors.fill: parent
spacing: Style.marginS
NText {
text: I18n.tr("wallpaper.panel.categories.general")
color: Color.mOnSurface
pointSize: Style.fontSizeM
}
Rectangle {
id: generalBox
implicitWidth: Math.round(Style.baseWidgetSize * 0.7)
implicitHeight: Math.round(Style.baseWidgetSize * 0.7)
radius: Style.radiusXS
color: generalToggle.checked ? Color.mPrimary : Color.mSurface
border.color: Color.mOutline
border.width: Style.borderS
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
NIcon {
visible: generalToggle.checked
anchors.centerIn: parent
anchors.horizontalCenterOffset: -1
icon: "check"
color: Color.mOnPrimary
pointSize: Math.max(Style.fontSizeXS, generalBox.width * 0.5)
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: generalToggle.toggled(!generalToggle.checked)
}
}
}
}
// Anime checkbox
Item {
Layout.preferredWidth: animeCheckboxRow.implicitWidth
Layout.preferredHeight: animeCheckboxRow.implicitHeight
RowLayout {
id: animeCheckboxRow
anchors.fill: parent
spacing: Style.marginS
NText {
text: I18n.tr("wallpaper.panel.categories.anime")
color: Color.mOnSurface
pointSize: Style.fontSizeM
}
Rectangle {
id: animeBox
implicitWidth: Math.round(Style.baseWidgetSize * 0.7)
implicitHeight: Math.round(Style.baseWidgetSize * 0.7)
radius: Style.radiusXS
color: animeToggle.checked ? Color.mPrimary : Color.mSurface
border.color: Color.mOutline
border.width: Style.borderS
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
NIcon {
visible: animeToggle.checked
anchors.centerIn: parent
anchors.horizontalCenterOffset: -1
icon: "check"
color: Color.mOnPrimary
pointSize: Math.max(Style.fontSizeXS, animeBox.width * 0.5)
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: animeToggle.toggled(!animeToggle.checked)
}
}
}
}
// People checkbox
Item {
Layout.preferredWidth: peopleCheckboxRow.implicitWidth
Layout.preferredHeight: peopleCheckboxRow.implicitHeight
RowLayout {
id: peopleCheckboxRow
anchors.fill: parent
spacing: Style.marginS
NText {
text: I18n.tr("wallpaper.panel.categories.people")
color: Color.mOnSurface
pointSize: Style.fontSizeM
}
Rectangle {
id: peopleBox
implicitWidth: Math.round(Style.baseWidgetSize * 0.7)
implicitHeight: Math.round(Style.baseWidgetSize * 0.7)
radius: Style.radiusXS
color: peopleToggle.checked ? Color.mPrimary : Color.mSurface
border.color: Color.mOutline
border.width: Style.borderS
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
NIcon {
visible: peopleToggle.checked
anchors.centerIn: parent
anchors.horizontalCenterOffset: -1
icon: "check"
color: Color.mOnPrimary
pointSize: Math.max(Style.fontSizeXS, peopleBox.width * 0.5)
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: peopleToggle.toggled(!peopleToggle.checked)
}
}
}
}
// Invisible checkboxes to maintain the signal handlers
QtObject {
id: generalToggle
property bool checked: false
signal toggled(bool checked)
onToggled: checked => {
categoriesRow.updateCategories(checked, categoriesRow.getCategoryValue(1), categoriesRow.getCategoryValue(2))
}
}
QtObject {
id: animeToggle
property bool checked: false
signal toggled(bool checked)
onToggled: checked => {
categoriesRow.updateCategories(categoriesRow.getCategoryValue(0), checked, categoriesRow.getCategoryValue(2))
}
}
QtObject {
id: peopleToggle
property bool checked: false
signal toggled(bool checked)
onToggled: checked => {
categoriesRow.updateCategories(categoriesRow.getCategoryValue(0), categoriesRow.getCategoryValue(1), checked)
}
}
}
}
// Wallhaven purity selector
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
visible: Settings.data.wallpaper.useWallhaven
NText {
text: I18n.tr("wallpaper.panel.purity.label")
color: Color.mOnSurface
pointSize: Style.fontSizeM
Layout.preferredWidth: implicitWidth
}
NComboBox {
id: purityComboBox
Layout.fillWidth: true
model: [
{ "key": "111", "name": I18n.tr("wallpaper.panel.purity.all") },
{ "key": "100", "name": I18n.tr("wallpaper.panel.purity.sfw") },
{ "key": "010", "name": I18n.tr("wallpaper.panel.purity.sketchy") }
]
currentKey: Settings.data.wallpaper.wallhavenPurity
onSelected: key => {
Settings.data.wallpaper.wallhavenPurity = key
if (typeof WallhavenService !== "undefined") {
WallhavenService.purity = key
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery, 1)
if (wallhavenSettingsPopup.item) {
wallhavenSettingsPopup.item.showAt(wallhavenSettingsButton)
}
}
}
@@ -1069,6 +871,24 @@ SmartPanel {
WallhavenService.sorting = Settings.data.wallpaper.wallhavenSorting
WallhavenService.order = Settings.data.wallpaper.wallhavenOrder
// Initialize resolution settings
var width = Settings.data.wallpaper.wallhavenResolutionWidth || ""
var height = Settings.data.wallpaper.wallhavenResolutionHeight || ""
var mode = Settings.data.wallpaper.wallhavenResolutionMode || "atleast"
if (width && height) {
var resolution = width + "x" + height
if (mode === "atleast") {
WallhavenService.minResolution = resolution
WallhavenService.resolutions = ""
} else {
WallhavenService.minResolution = ""
WallhavenService.resolutions = resolution
}
} else {
WallhavenService.minResolution = ""
WallhavenService.resolutions = ""
}
// Now check if we can actually search (fetching check is in WallhavenService.search)
loading = true
WallhavenService.search(Settings.data.wallpaper.wallhavenQuery || "", 1)
+1 -1
View File
@@ -129,7 +129,7 @@ Singleton {
} else if (xhr.status === 429) {
var errorMsg = "Rate limit exceeded (45 requests/minute)"
lastError = errorMsg
Logger.e("Wallhaven", errorMsg)
Logger.w("Wallhaven", errorMsg)
searchFailed(errorMsg)
} else {
var errorMsg = "API error: " + xhr.status