forked from Shinonome/dots-hyprland
add gemini powered clock styling
This commit is contained in:
@@ -8,6 +8,7 @@ import qs.modules.common.functions
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
import "./dateIndicator"
|
import "./dateIndicator"
|
||||||
import "./minuteMarks"
|
import "./minuteMarks"
|
||||||
@@ -35,6 +36,54 @@ Item {
|
|||||||
implicitWidth: implicitSize
|
implicitWidth: implicitSize
|
||||||
implicitHeight: implicitSize
|
implicitHeight: implicitSize
|
||||||
|
|
||||||
|
function applyStyle(sides, dialStyle, hourHandStyle, minuteHandStyle, secondHandStyle, dateStyle) {
|
||||||
|
Config.options.background.clock.cookie.sides = sides
|
||||||
|
Config.options.background.clock.cookie.dialNumberStyle = dialStyle
|
||||||
|
Config.options.background.clock.cookie.hourHandStyle = hourHandStyle
|
||||||
|
Config.options.background.clock.cookie.minuteHandStyle = minuteHandStyle
|
||||||
|
Config.options.background.clock.cookie.secondHandStyle = secondHandStyle
|
||||||
|
Config.options.background.clock.cookie.dateStyle = dateStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
function setClockPreset(category) {
|
||||||
|
if (!Config.options.background.clock.cookie.aiStyling) return;
|
||||||
|
if (category === "") return;
|
||||||
|
print("[Cookie clock] Setting clock preset for category: " + category)
|
||||||
|
// "abstract", "anime", "city", "minimalist", "landscape", "plants", "person", "space"
|
||||||
|
if (category == "abstract") {
|
||||||
|
applyStyle(7, "dots", "fill", "medium", "dot", "bubble")
|
||||||
|
} else if (category == "anime") {
|
||||||
|
applyStyle(12, "dots", "fill", "bold", "dot", "bubble")
|
||||||
|
} else if (category == "city" || category == "space") {
|
||||||
|
applyStyle(23, "full", "hollow", "medium", "classic", "bubble")
|
||||||
|
} else if (category == "minimalist") {
|
||||||
|
applyStyle(6, "none", "fill", "bold", "dot", "hide")
|
||||||
|
} else if (category == "landscape") {
|
||||||
|
applyStyle(14, "full", "hollow", "medium", "classic", "bubble")
|
||||||
|
} else if (category == "plants") {
|
||||||
|
applyStyle(9, "dots", "fill", "bold", "dot", "border")
|
||||||
|
} else if (category == "person") {
|
||||||
|
applyStyle(14, "full", "classic", "classic", "classic", "rect")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Config
|
||||||
|
function onReadyChanged() {
|
||||||
|
categoryFileView.path = Directories.generatedWallpaperCategoryPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: categoryFileView
|
||||||
|
path: ""
|
||||||
|
watchChanges: true
|
||||||
|
onFileChanged: reload()
|
||||||
|
onLoaded: {
|
||||||
|
root.setClockPreset(categoryFileView.text().trim())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DropShadow {
|
DropShadow {
|
||||||
source: cookie
|
source: cookie
|
||||||
anchors.fill: source
|
anchors.fill: source
|
||||||
|
|||||||
@@ -40,11 +40,30 @@ Singleton {
|
|||||||
obj[keys[keys.length - 1]] = convertedValue;
|
obj[keys[keys.length - 1]] = convertedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: fileReloadTimer
|
||||||
|
interval: 100
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
configFileView.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: fileWriteTimer
|
||||||
|
interval: 100
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
configFileView.writeAdapter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
|
id: configFileView
|
||||||
path: root.filePath
|
path: root.filePath
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
onFileChanged: reload()
|
onFileChanged: fileReloadTimer.restart()
|
||||||
onAdapterUpdated: writeAdapter()
|
onAdapterUpdated: fileWriteTimer.restart()
|
||||||
onLoaded: root.ready = true
|
onLoaded: root.ready = true
|
||||||
onLoadFailed: error => {
|
onLoadFailed: error => {
|
||||||
if (error == FileViewError.FileNotFound) {
|
if (error == FileViewError.FileNotFound) {
|
||||||
@@ -130,11 +149,12 @@ Singleton {
|
|||||||
property string style: "cookie" // Options: "cookie", "digital"
|
property string style: "cookie" // Options: "cookie", "digital"
|
||||||
property real scale: 1
|
property real scale: 1
|
||||||
property JsonObject cookie: JsonObject {
|
property JsonObject cookie: JsonObject {
|
||||||
|
property bool aiStyling: false
|
||||||
property int sides: 14
|
property int sides: 14
|
||||||
property string dialNumberStyle: "full" // Options: "dots" , "numbers", "full" , "none"
|
property string dialNumberStyle: "full" // Options: "dots" , "numbers", "full" , "none"
|
||||||
property string hourHandStyle: "fill" // Options: "classic", "fill", "hollow", "hide"
|
property string hourHandStyle: "fill" // Options: "classic", "fill", "hollow", "hide"
|
||||||
property string minuteHandStyle: "medium" // Options "classic", "thin", "medium", "bold", "hide"
|
property string minuteHandStyle: "medium" // Options "classic", "thin", "medium", "bold", "hide"
|
||||||
property string secondHandStyle: "dot" // Options: "dot", "line" , "hide"
|
property string secondHandStyle: "dot" // Options: "dot", "line", "classic", "hide"
|
||||||
property string dateStyle: "bubble" // Options: "border", "rect", "bubble" , "hide"
|
property string dateStyle: "bubble" // Options: "border", "rect", "bubble" , "hide"
|
||||||
property bool timeIndicators: true
|
property bool timeIndicators: true
|
||||||
property bool hourMarks: false
|
property bool hourMarks: false
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ Singleton {
|
|||||||
property string todoPath: FileUtils.trimFileProtocol(`${Directories.state}/user/todo.json`)
|
property string todoPath: FileUtils.trimFileProtocol(`${Directories.state}/user/todo.json`)
|
||||||
property string notificationsPath: FileUtils.trimFileProtocol(`${Directories.cache}/notifications/notifications.json`)
|
property string notificationsPath: FileUtils.trimFileProtocol(`${Directories.cache}/notifications/notifications.json`)
|
||||||
property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/colors.json`)
|
property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/colors.json`)
|
||||||
|
property string generatedWallpaperCategoryPath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/wallpaper/category.txt`)
|
||||||
property string cliphistDecode: FileUtils.trimFileProtocol(`/tmp/quickshell/media/cliphist`)
|
property string cliphistDecode: FileUtils.trimFileProtocol(`/tmp/quickshell/media/cliphist`)
|
||||||
property string screenshotTemp: "/tmp/quickshell/media/screenshot"
|
property string screenshotTemp: "/tmp/quickshell/media/screenshot"
|
||||||
property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`)
|
property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`)
|
||||||
|
|||||||
@@ -59,8 +59,20 @@ ContentPage {
|
|||||||
ContentSubsection {
|
ContentSubsection {
|
||||||
visible: Config.options.background.clock.style === "cookie"
|
visible: Config.options.background.clock.style === "cookie"
|
||||||
title: Translation.tr("Cookie clock settings")
|
title: Translation.tr("Cookie clock settings")
|
||||||
|
|
||||||
|
ConfigSwitch {
|
||||||
|
buttonIcon: "wand_stars"
|
||||||
|
text: Translation.tr("Auto styling with Gemini")
|
||||||
|
checked: Config.options.background.clock.cookie.aiStyling
|
||||||
|
onCheckedChanged: {
|
||||||
|
Config.options.background.clock.cookie.aiStyling = checked;
|
||||||
|
}
|
||||||
|
StyledToolTip {
|
||||||
|
text: "Uses Gemini to categorize the wallpaper then picks a preset based on it.\nYou'll need to set Gemini API key on the left sidebar first.\nImages are downscaled for performance, but just to be safe,\ndo not select wallpapers with sensitive information."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
visible: Config.options.background.clock.style === "cookie"
|
|
||||||
icon: "add_triangle"
|
icon: "add_triangle"
|
||||||
text: Translation.tr("Sides")
|
text: Translation.tr("Sides")
|
||||||
value: Config.options.background.clock.cookie.sides
|
value: Config.options.background.clock.cookie.sides
|
||||||
@@ -73,7 +85,6 @@ ContentPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
visible: Config.options.background.clock.style === "cookie"
|
|
||||||
buttonIcon: "autoplay"
|
buttonIcon: "autoplay"
|
||||||
text: Translation.tr("Constantly rotate")
|
text: Translation.tr("Constantly rotate")
|
||||||
checked: Config.options.background.clock.cookie.constantlyRotate
|
checked: Config.options.background.clock.cookie.constantlyRotate
|
||||||
@@ -86,7 +97,6 @@ ContentPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfigRow {
|
ConfigRow {
|
||||||
visible: Config.options.background.clock.style === "cookie"
|
|
||||||
|
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
enabled: Config.options.background.clock.style === "cookie" && Config.options.background.clock.cookie.dialNumberStyle === "dots" || Config.options.background.clock.cookie.dialNumberStyle === "full"
|
enabled: Config.options.background.clock.style === "cookie" && Config.options.background.clock.cookie.dialNumberStyle === "dots" || Config.options.background.clock.cookie.dialNumberStyle === "full"
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [[ -z "$1" ]]; then
|
||||||
|
echo "Usage: $0 <image_path>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOURCE_IMG_PATH="$1"
|
||||||
|
WALLPAPER_NAME="$(basename "$SOURCE_IMG_PATH")"
|
||||||
|
RESIZED_IMG_PATH="/tmp/quickshell/ai/wallpaper.jpg"
|
||||||
|
magick "$SOURCE_IMG_PATH" -resize 200x -quality 50 "$RESIZED_IMG_PATH"
|
||||||
|
API_KEY=$(secret-tool lookup 'application' 'illogical-impulse' | jq -r '.apiKeys.gemini')
|
||||||
|
|
||||||
|
if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then
|
||||||
|
B64FLAGS="--input"
|
||||||
|
else
|
||||||
|
B64FLAGS="-w0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
payload='{
|
||||||
|
"contents": [{
|
||||||
|
"parts":[
|
||||||
|
{
|
||||||
|
"inline_data": {
|
||||||
|
"mime_type":"image/jpeg",
|
||||||
|
"data": "'"$(base64 $B64FLAGS $RESIZED_IMG_PATH)"'"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{"text": "Categorize the wallpaper. Its file name is '"$WALLPAPER_NAME"'"}
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
"generationConfig": {
|
||||||
|
"responseMimeType": "text/x.enum",
|
||||||
|
"responseSchema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [ "abstract", "anime", "city", "minimalist", "landscape", "plants", "person", "space" ]
|
||||||
|
},
|
||||||
|
"temperature": 0,
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
# echo "$payload" | jq
|
||||||
|
response=$(curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent" \
|
||||||
|
-H "x-goog-api-key: $API_KEY" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-X POST \
|
||||||
|
-d "$payload" 2> /dev/null)
|
||||||
|
|
||||||
|
echo "$response" | jq -r '.candidates[0].content.parts[0].text'
|
||||||
@@ -171,6 +171,13 @@ switch() {
|
|||||||
type_flag="$3"
|
type_flag="$3"
|
||||||
color_flag="$4"
|
color_flag="$4"
|
||||||
color="$5"
|
color="$5"
|
||||||
|
|
||||||
|
# Start Gemini auto-categorization if enabled
|
||||||
|
aiStylingEnabled=$(jq -r '.background.clock.cookie.aiStyling' "$SHELL_CONFIG_FILE")
|
||||||
|
if [[ "$aiStylingEnabled" == "true" ]]; then
|
||||||
|
"$SCRIPT_DIR/../ai/gemini-categorize-wallpaper.sh" "$imgpath" > "$STATE_DIR/user/generated/wallpaper/category.txt" &
|
||||||
|
fi
|
||||||
|
|
||||||
read scale screenx screeny screensizey < <(hyprctl monitors -j | jq '.[] | select(.focused) | .scale, .x, .y, .height' | xargs)
|
read scale screenx screeny screensizey < <(hyprctl monitors -j | jq '.[] | select(.focused) | .scale, .x, .y, .height' | xargs)
|
||||||
cursorposx=$(hyprctl cursorpos -j | jq '.x' 2>/dev/null) || cursorposx=960
|
cursorposx=$(hyprctl cursorpos -j | jq '.x' 2>/dev/null) || cursorposx=960
|
||||||
cursorposx=$(bc <<< "scale=0; ($cursorposx - $screenx) * $scale / 1")
|
cursorposx=$(bc <<< "scale=0; ($cursorposx - $screenx) * $scale / 1")
|
||||||
|
|||||||
Reference in New Issue
Block a user