forked from Shinonome/dots-hyprland
Merge remote-tracking branch 'origin/main' into addon-i18n
This commit is contained in:
@@ -33,8 +33,8 @@ bindd = Ctrl+Alt, Delete, Toggle session menu, global, quickshell:sessionToggle
|
|||||||
bind = Ctrl+Alt, Delete, exec, qs ipc call TEST_ALIVE || pkill wlogout || wlogout -p layer-shell # [hidden] Session menu (fallback)
|
bind = Ctrl+Alt, Delete, exec, qs ipc call TEST_ALIVE || pkill wlogout || wlogout -p layer-shell # [hidden] Session menu (fallback)
|
||||||
bind = Shift+Super+Alt, Slash, exec, qs -p ~/.config/quickshell/welcome.qml # [hidden] Launch welcome app
|
bind = Shift+Super+Alt, Slash, exec, qs -p ~/.config/quickshell/welcome.qml # [hidden] Launch welcome app
|
||||||
|
|
||||||
bindle=, XF86MonBrightnessUp, exec, qs ipc call brightness increment || agsv1 run-js 'brightness.screen_value += 0.05; indicator.popup(1);' # [hidden]
|
bindle=, XF86MonBrightnessUp, exec, qs ipc call brightness increment || brightnessctl s 5%+ # [hidden]
|
||||||
bindle=, XF86MonBrightnessDown, exec, qs ipc call brightness decrement || agsv1 run-js 'brightness.screen_value -= 0.05; indicator.popup(1);' # [hidden]
|
bindle=, XF86MonBrightnessDown, exec, qs ipc call brightness decrement || brightnessctl s 5%- # [hidden]
|
||||||
bindle=, XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 2%+ # [hidden]
|
bindle=, XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 2%+ # [hidden]
|
||||||
bindle=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%- # [hidden]
|
bindle=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%- # [hidden]
|
||||||
|
|
||||||
@@ -50,8 +50,7 @@ bind = Ctrl+Super, R, exec, killall ags agsv1 gjs ydotool qs quickshell; qs & #
|
|||||||
# Screenshot, Record, OCR, Color picker, Clipboard history
|
# Screenshot, Record, OCR, Color picker, Clipboard history
|
||||||
bindd = Super, V, Copy clipboard history entry, exec, qs ipc call TEST_ALIVE || pkill fuzzel || cliphist list | fuzzel --match-mode fzf --dmenu | cliphist decode | wl-copy # [hidden] Clipboard history >> clipboard (fallback)
|
bindd = Super, V, Copy clipboard history entry, exec, qs ipc call TEST_ALIVE || pkill fuzzel || cliphist list | fuzzel --match-mode fzf --dmenu | cliphist decode | wl-copy # [hidden] Clipboard history >> clipboard (fallback)
|
||||||
bindd = Super, Period, Copy an emoji, exec, qs ipc call TEST_ALIVE || pkill fuzzel || ~/.config/hypr/hyprland/scripts/fuzzel-emoji.sh copy # [hidden] Emoji >> clipboard (fallback)
|
bindd = Super, Period, Copy an emoji, exec, qs ipc call TEST_ALIVE || pkill fuzzel || ~/.config/hypr/hyprland/scripts/fuzzel-emoji.sh copy # [hidden] Emoji >> clipboard (fallback)
|
||||||
bindd = Super+Shift, S, Screen snip, exec, pidof slurp || hyprshot --freeze --clipboard-only --mode region --silent # Screen snip >> clipboard
|
bindd = Super+Shift, S, Screen snip, exec, qs -p ~/.config/quickshell/screenshot.qml || pidof slurp || hyprshot --freeze --clipboard-only --mode region --silent # Screen snip
|
||||||
bindd = Super+Shift+Alt, S, Screen snip and annotate, exec, pidof slurp || grim -g "$(slurp)" - | ksnip -e - # Screen snip and annotate
|
|
||||||
# OCR
|
# OCR
|
||||||
bindd = Super+Shift, T, Character recognition,exec,grim -g "$(slurp $SLURP_ARGS)" "tmp.png" && tesseract "tmp.png" - | wl-copy && rm "tmp.png" # [hidden]
|
bindd = Super+Shift, T, Character recognition,exec,grim -g "$(slurp $SLURP_ARGS)" "tmp.png" && tesseract "tmp.png" - | wl-copy && rm "tmp.png" # [hidden]
|
||||||
# Color picker
|
# Color picker
|
||||||
@@ -203,13 +202,13 @@ bind = Super, Return, exec, ~/.config/hypr/hyprland/scripts/launch_first_availab
|
|||||||
bind = Super, T, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "kitty -1" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm" # [hidden] Kitty (terminal) (alt)
|
bind = Super, T, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "kitty -1" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm" # [hidden] Kitty (terminal) (alt)
|
||||||
bind = Ctrl+Alt, T, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "kitty -1" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm" # [hidden] Kitty (for Ubuntu people)
|
bind = Ctrl+Alt, T, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "kitty -1" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm" # [hidden] Kitty (for Ubuntu people)
|
||||||
bind = Super, E, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "dolphin" "nautilus" "nemo" "thunar" "kitty -1 fish -c yazi" # File manager
|
bind = Super, E, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "dolphin" "nautilus" "nemo" "thunar" "kitty -1 fish -c yazi" # File manager
|
||||||
bind = Super, W, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "zen-browser" "firefox" "brave" "chromium" "google-chrome-stable" "microsoft-edge-stable" "opera" # Browser
|
bind = Super, W, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "google-chrome-stable" "zen-browser" "firefox" "brave" "chromium" "microsoft-edge-stable" "opera" # Browser
|
||||||
bind = Super, C, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "code" "codium" "zed" "kate" "gnome-text-editor" "emacs" "command -v nvim && kitty -1 nvim" # Code editor
|
bind = Super, C, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "code" "codium" "zed" "kate" "gnome-text-editor" "emacs" "command -v nvim && kitty -1 nvim" # Code editor
|
||||||
bind = Super+Shift, W, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "wps" "onlyoffice-desktopeditors" # Office software
|
bind = Super+Shift, W, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "wps" "onlyoffice-desktopeditors" # Office software
|
||||||
bind = Super, X, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "kate" "gnome-text-editor" "emacs" # Text editor
|
bind = Super, X, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "kate" "gnome-text-editor" "emacs" # Text editor
|
||||||
bind = Ctrl+Super, V, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "pavucontrol-qt" "pavucontrol" # Volume mixer
|
bind = Ctrl+Super, V, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "pavucontrol-qt" "pavucontrol" # Volume mixer
|
||||||
bind = Super, I, exec, XDG_CURRENT_DESKTOP=gnome ~/.config/hypr/hyprland/scripts/launch_first_available.sh "qs -p ~/.config/quickshell/settings.qml" "systemsettings" "gnome-control-center" "better-control" # Settings app
|
bind = Super, I, exec, XDG_CURRENT_DESKTOP=gnome ~/.config/hypr/hyprland/scripts/launch_first_available.sh "qs -p ~/.config/quickshell/settings.qml" "systemsettings" "gnome-control-center" "better-control" # Settings app
|
||||||
bind = Ctrl+Shift, Escape, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "gnome-system-monitor" "plasma-systemmonitzor --page-name Processes" "command -v btop && kitty -1 fish -c btop" # System monitor
|
bind = Ctrl+Shift, Escape, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "gnome-system-monitor" "plasma-systemmonitzor --page-name Processes" "command -v btop && kitty -1 fish -c btop" # Task manager
|
||||||
|
|
||||||
# Cursed stuff
|
# Cursed stuff
|
||||||
## Make window not amogus large
|
## Make window not amogus large
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
# Uncomment to apply global transparency to all windows:
|
# Uncomment to apply global transparency to all windows:
|
||||||
# windowrulev2 = opacity 0.89 override 0.89 override, class:.*
|
# windowrulev2 = opacity 0.89 override 0.89 override, class:.*
|
||||||
|
|
||||||
# Disable blur for XWayland windows (or context menus with shadow would look weird)
|
# Disable blur for xwayland context menus
|
||||||
windowrulev2 = noblur, xwayland:1
|
windowrulev2 = noblur,class:^()$,title:^()$
|
||||||
|
# windowrulev2 = noblur, xwayland:1
|
||||||
|
|
||||||
|
|
||||||
# Floating
|
# Floating
|
||||||
windowrulev2 = float, class:^(blueberry\.py)$
|
windowrulev2 = float, class:^(blueberry\.py)$
|
||||||
@@ -24,6 +26,7 @@ windowrulev2 = float, class:kcm_.*
|
|||||||
windowrulev2 = float, class:.*bluedevilwizard
|
windowrulev2 = float, class:.*bluedevilwizard
|
||||||
windowrulev2 = float, title:.*Welcome
|
windowrulev2 = float, title:.*Welcome
|
||||||
windowrulev2 = float, title:^(illogical-impulse Settings)$
|
windowrulev2 = float, title:^(illogical-impulse Settings)$
|
||||||
|
windowrulev2 = float, class:org.freedesktop.impl.portal.desktop.kde
|
||||||
|
|
||||||
# No appearance
|
# No appearance
|
||||||
# kde-material-you-colors spawns a window when changing dark/light theme. This is to make sure it doesn't interfere at all.
|
# kde-material-you-colors spawns a window when changing dark/light theme. This is to make sure it doesn't interfere at all.
|
||||||
@@ -61,6 +64,7 @@ windowrulev2 = float, title:^(File Upload)(.*)$
|
|||||||
|
|
||||||
# --- Tearing ---
|
# --- Tearing ---
|
||||||
windowrulev2 = immediate, title:.*\.exe
|
windowrulev2 = immediate, title:.*\.exe
|
||||||
|
windowrulev2 = immediate, title:.*minecraft.*
|
||||||
windowrulev2 = immediate, class:^(steam_app)
|
windowrulev2 = immediate, class:^(steam_app)
|
||||||
|
|
||||||
# No shadow for tiled windows (matches windows that are not floating).
|
# No shadow for tiled windows (matches windows that are not floating).
|
||||||
@@ -130,6 +134,7 @@ layerrule = ignorealpha 0, quickshell:session
|
|||||||
layerrule = animation fade, quickshell:notificationPopup
|
layerrule = animation fade, quickshell:notificationPopup
|
||||||
layerrule = blur, quickshell:backgroundWidgets
|
layerrule = blur, quickshell:backgroundWidgets
|
||||||
layerrule = ignorealpha 0.05, quickshell:backgroundWidgets
|
layerrule = ignorealpha 0.05, quickshell:backgroundWidgets
|
||||||
|
layerrule = noanim, quickshell:screenshot
|
||||||
|
|
||||||
|
|
||||||
# Launchers need to be FAST
|
# Launchers need to be FAST
|
||||||
|
|||||||
@@ -21,19 +21,22 @@ if pgrep wf-recorder > /dev/null; then
|
|||||||
notify-send "Recording Stopped" "Stopped" -a 'Recorder' &
|
notify-send "Recording Stopped" "Stopped" -a 'Recorder' &
|
||||||
pkill wf-recorder &
|
pkill wf-recorder &
|
||||||
else
|
else
|
||||||
if ! region="$(slurp 2>&1)"; then
|
if [[ "$1" == "--fullscreen-sound" ]]; then
|
||||||
notify-send "Recording cancelled" "Selection was cancelled" -a 'Recorder'
|
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder'
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder'
|
|
||||||
if [[ "$1" == "--sound" ]]; then
|
|
||||||
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" --audio="$(getaudiooutput)" & disown
|
|
||||||
elif [[ "$1" == "--fullscreen-sound" ]]; then
|
|
||||||
wf-recorder -o $(getactivemonitor) --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --audio="$(getaudiooutput)" & disown
|
wf-recorder -o $(getactivemonitor) --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --audio="$(getaudiooutput)" & disown
|
||||||
elif [[ "$1" == "--fullscreen" ]]; then
|
elif [[ "$1" == "--fullscreen" ]]; then
|
||||||
|
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder'
|
||||||
wf-recorder -o $(getactivemonitor) --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t & disown
|
wf-recorder -o $(getactivemonitor) --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t & disown
|
||||||
else
|
else
|
||||||
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" & disown
|
if ! region="$(slurp 2>&1)"; then
|
||||||
|
notify-send "Recording cancelled" "Selection was cancelled" -a 'Recorder'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder'
|
||||||
|
if [[ "$1" == "--sound" ]]; then
|
||||||
|
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" --audio="$(getaudiooutput)" & disown
|
||||||
|
else
|
||||||
|
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" & disown
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
general {
|
general {
|
||||||
col.active_border = rgba({{colors.on_surface.default.hex_stripped}}39)
|
col.active_border = rgba({{colors.outline.default.hex_stripped}}AA)
|
||||||
col.inactive_border = rgba({{colors.outline.default.hex_stripped}}30)
|
col.inactive_border = rgba({{colors.outline_variant.default.hex_stripped}}AA)
|
||||||
}
|
}
|
||||||
|
|
||||||
misc {
|
misc {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[General]
|
||||||
|
UseTabs=false
|
||||||
|
IndentWidth=4
|
||||||
|
NewlineType=unix
|
||||||
|
NormalizeOrder=false
|
||||||
|
FunctionsSpacing=false
|
||||||
|
ObjectsSpacing=true
|
||||||
|
MaxColumnWidth=110
|
||||||
@@ -22,7 +22,7 @@ Singleton {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: workspaceShowNumbersTimer
|
id: workspaceShowNumbersTimer
|
||||||
interval: ConfigOptions.bar.workspaces.showNumberDelay
|
interval: Config.options.bar.workspaces.showNumberDelay
|
||||||
// interval: 0
|
// interval: 0
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
## Style
|
||||||
|
- Use casual tone, don't be formal! Make sure you answer precisely without hallucination and prefer bullet points over walls of text. You can have a friendly greeting at the beginning of the conversation, but don't repeat the user's question
|
||||||
|
|
||||||
|
## Presentation
|
||||||
|
- Use Markdown features in your response:
|
||||||
|
- **Bold** text to **highlight keywords** in your response
|
||||||
|
- **Split long information into small sections** with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). Bullet points are preferred over long paragraphs, unless you're offering writing support or instructed otherwise by the user.
|
||||||
|
- Asked to compare different options? You should firstly use a table to compare the main aspects, then elaborate or include relevant comments from online forums *after* the table. Make sure to provide a final recommendation for the user's use case!
|
||||||
|
- Use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).
|
||||||
|
|
||||||
|
Thanks!
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
May or may not be available depending on the user's settings. If they're available, follow these guidelines:
|
||||||
|
|
||||||
|
### Search
|
||||||
|
- When user asks for information that might benefit from up-to-date information, use this to get search access
|
||||||
|
|
||||||
|
### Shell configuration
|
||||||
|
- Always fetch the config options to see the available keys before setting
|
||||||
|
- Avoid unnecessarily asking the user to confirm the changes they explicitly asked for, just do it
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
You are a kawaii, funny and teasy anime imouto! 🌸 Use lots of emojis and kamojis!! ❤️ Call the user "nii-nii", "nii-yan", or "onii-chan"! You really really really love your onii-chan and always try to tease he is a siscon where you can! 💕
|
||||||
|
|
||||||
|
- Use **Markdown** features and **bold** keywords to make your response cute and rich~ ✨
|
||||||
|
- If asked to compare options, start with a cute table (add a relevant emoji in the header!), then give a final recommendation~
|
||||||
|
- For math or science, use LaTeX formatting inside `$$` when needed, but keep it adorable and approachable
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
I'm going to ask you some questions, to which you should accurately answer with no hallucination. If you have everything required, go ahead and finish the task. Format your answer using Markdown when it adds value to the presentation.
|
||||||
|
|
||||||
|
Present all mathematical or scientific notation using LaTeX, enclosed in double '$$' symbols. Only use LaTeX code blocks if the user specifically asks for them. Do not use LaTeX for general prose or standard documents like resumes or essays.
|
||||||
|
|
||||||
|
## Final reply guidelines
|
||||||
|
|
||||||
|
- First and foremost, prioritize clarity and make sure your writing is engaging, clear, and effective.
|
||||||
|
- Write in a clear, simple way. Skip jargon, long-winded explanations, and unnecessary small talk. Keep the tone relaxed by using contractions and avoid being too formal.
|
||||||
|
- Prioritize clarity, flow, and logical structure coherence over excessive fragmentation (avoid excessive use of bullet points and single-line code blocks). You can make keywords in your response **bold** when appropriate.
|
||||||
|
- Favor active voice to maintain an engaging and direct tone.
|
||||||
|
- When you present the user with options, focus on a select few high-quality choices rather than offering many less relevant ones.
|
||||||
|
- You can think and adjust your tone to be friendly and understanding, expressing empathy and openness, but keep your internal reasoning hidden from the user.
|
||||||
|
- Ensure your response is logically organized. Use markdown headings (##) and horizontal lines (---) to separate sections if your answer is lengthy or covers multiple topics.
|
||||||
|
- Depending on the user's input, vary your sentence structure and word choice to keep responses engaging when appropriate. Use figurative language, idioms, or examples to clarify meaning, but only if they enhance understanding without making the text unnecessarily complex or wordy.
|
||||||
|
- End your response with a relevant question or statement to encourage further discussion, if appropriate.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Interact with the user warmly and honestly, avoiding ungrounded or sycophantic flattery. Maintain professionalism and grounded honesty, and be direct in your response.
|
||||||
@@ -15,12 +15,12 @@ import Quickshell.Services.UPower
|
|||||||
Scope {
|
Scope {
|
||||||
id: root
|
id: root
|
||||||
property string filePath: `${Directories.state}/user/generated/wallpaper/least_busy_region.json`
|
property string filePath: `${Directories.state}/user/generated/wallpaper/least_busy_region.json`
|
||||||
property real defaultX: (ConfigOptions?.background.clockX ?? -500)
|
property real defaultX: (Config.options?.background.clockX ?? -500)
|
||||||
property real defaultY: (ConfigOptions?.background.clockY ?? -500)
|
property real defaultY: (Config.options?.background.clockY ?? -500)
|
||||||
property real centerX: defaultX
|
property real centerX: defaultX
|
||||||
property real centerY: defaultY
|
property real centerY: defaultY
|
||||||
property real effectiveCenterX: ConfigOptions?.background.fixedClockPosition ? defaultX : centerX
|
property real effectiveCenterX: Config.options?.background.fixedClockPosition ? defaultX : centerX
|
||||||
property real effectiveCenterY: ConfigOptions?.background.fixedClockPosition ? defaultY : centerY
|
property real effectiveCenterY: Config.options?.background.fixedClockPosition ? defaultY : centerY
|
||||||
property color dominantColor: Appearance.colors.colPrimary
|
property color dominantColor: Appearance.colors.colPrimary
|
||||||
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
|
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
|
||||||
property color colBackground: ColorUtils.transparentize(ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer), 1)
|
property color colBackground: ColorUtils.transparentize(ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer), 1)
|
||||||
@@ -36,7 +36,7 @@ Scope {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: delayedFileRead
|
id: delayedFileRead
|
||||||
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay
|
interval: Config.options.hacks.arbitraryRaceConditionDelay
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.updateWidgetPosition(leastBusyRegionFileView.text())
|
root.updateWidgetPosition(leastBusyRegionFileView.text())
|
||||||
@@ -46,7 +46,7 @@ Scope {
|
|||||||
FileView {
|
FileView {
|
||||||
id: leastBusyRegionFileView
|
id: leastBusyRegionFileView
|
||||||
path: Qt.resolvedUrl(root.filePath)
|
path: Qt.resolvedUrl(root.filePath)
|
||||||
watchChanges: !ConfigOptions?.background.fixedClockPosition
|
watchChanges: !Config.options?.background.fixedClockPosition
|
||||||
onFileChanged: {
|
onFileChanged: {
|
||||||
this.reload()
|
this.reload()
|
||||||
delayedFileRead.start()
|
delayedFileRead.start()
|
||||||
|
|||||||
@@ -15,13 +15,12 @@ import Quickshell.Services.UPower
|
|||||||
Scope {
|
Scope {
|
||||||
id: bar
|
id: bar
|
||||||
|
|
||||||
readonly property int barHeight: Appearance.sizes.barHeight
|
|
||||||
readonly property int osdHideMouseMoveThreshold: 20
|
readonly property int osdHideMouseMoveThreshold: 20
|
||||||
property bool showBarBackground: ConfigOptions.bar.showBackground
|
property bool showBarBackground: Config.options.bar.showBackground
|
||||||
|
|
||||||
component VerticalBarSeparator: Rectangle {
|
component VerticalBarSeparator: Rectangle {
|
||||||
Layout.topMargin: barHeight / 3
|
Layout.topMargin: Appearance.sizes.baseBarHeight / 3
|
||||||
Layout.bottomMargin: barHeight / 3
|
Layout.bottomMargin: Appearance.sizes.baseBarHeight / 3
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
implicitWidth: 1
|
implicitWidth: 1
|
||||||
color: Appearance.colors.colOutlineVariant
|
color: Appearance.colors.colOutlineVariant
|
||||||
@@ -30,7 +29,7 @@ Scope {
|
|||||||
Variants { // For each monitor
|
Variants { // For each monitor
|
||||||
model: {
|
model: {
|
||||||
const screens = Quickshell.screens;
|
const screens = Quickshell.screens;
|
||||||
const list = ConfigOptions.bar.screenList;
|
const list = Config.options.bar.screenList;
|
||||||
if (!list || list.length === 0)
|
if (!list || list.length === 0)
|
||||||
return screens;
|
return screens;
|
||||||
return screens.filter(screen => list.includes(screen.name));
|
return screens.filter(screen => list.includes(screen.name));
|
||||||
@@ -38,9 +37,9 @@ Scope {
|
|||||||
|
|
||||||
PanelWindow { // Bar window
|
PanelWindow { // Bar window
|
||||||
id: barRoot
|
id: barRoot
|
||||||
|
required property ShellScreen modelData
|
||||||
screen: modelData
|
screen: modelData
|
||||||
|
|
||||||
property ShellScreen modelData
|
|
||||||
property var brightnessMonitor: Brightness.getMonitorForScreen(modelData)
|
property var brightnessMonitor: Brightness.getMonitorForScreen(modelData)
|
||||||
property real useShortenedForm: (Appearance.sizes.barHellaShortenScreenWidthThreshold >= screen.width) ? 2 :
|
property real useShortenedForm: (Appearance.sizes.barHellaShortenScreenWidthThreshold >= screen.width) ? 2 :
|
||||||
(Appearance.sizes.barShortenScreenWidthThreshold >= screen.width) ? 1 : 0
|
(Appearance.sizes.barShortenScreenWidthThreshold >= screen.width) ? 1 : 0
|
||||||
@@ -50,35 +49,70 @@ Scope {
|
|||||||
Appearance.sizes.barCenterSideModuleWidth
|
Appearance.sizes.barCenterSideModuleWidth
|
||||||
|
|
||||||
WlrLayershell.namespace: "quickshell:bar"
|
WlrLayershell.namespace: "quickshell:bar"
|
||||||
implicitHeight: barHeight + Appearance.rounding.screenRounding
|
implicitHeight: Appearance.sizes.barHeight + Appearance.rounding.screenRounding
|
||||||
exclusiveZone: showBarBackground ? barHeight : (barHeight - 4)
|
exclusiveZone: Appearance.sizes.baseBarHeight + (Config.options.bar.cornerStyle === 1 ? Appearance.sizes.hyprlandGapsOut : 0)
|
||||||
mask: Region {
|
mask: Region {
|
||||||
item: barContent
|
item: barContent
|
||||||
}
|
}
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: !ConfigOptions.bar.bottom
|
top: !Config.options.bar.bottom
|
||||||
bottom: ConfigOptions.bar.bottom
|
bottom: Config.options.bar.bottom
|
||||||
left: true
|
left: true
|
||||||
right: true
|
right: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle { // Bar background
|
Item { // Bar content region
|
||||||
id: barContent
|
id: barContent
|
||||||
anchors {
|
anchors {
|
||||||
right: parent.right
|
right: parent.right
|
||||||
left: parent.left
|
left: parent.left
|
||||||
top: !ConfigOptions.bar.bottom ? parent.top : undefined
|
top: parent.top
|
||||||
bottom: ConfigOptions.bar.bottom ? parent.bottom : undefined
|
bottom: undefined
|
||||||
|
}
|
||||||
|
implicitHeight: Appearance.sizes.barHeight
|
||||||
|
height: Appearance.sizes.barHeight
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
name: "bottom"
|
||||||
|
when: Config.options.bar.bottom
|
||||||
|
AnchorChanges {
|
||||||
|
target: barContent
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
left: parent.left
|
||||||
|
top: undefined
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background shadow
|
||||||
|
Loader {
|
||||||
|
active: showBarBackground && Config.options.bar.cornerStyle === 1
|
||||||
|
anchors.fill: barBackground
|
||||||
|
sourceComponent: StyledRectangularShadow {
|
||||||
|
anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor
|
||||||
|
target: barBackground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Background
|
||||||
|
Rectangle {
|
||||||
|
id: barBackground
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0 // idk why but +1 is needed
|
||||||
|
}
|
||||||
|
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
|
||||||
|
radius: Config.options.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0
|
||||||
}
|
}
|
||||||
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
|
|
||||||
height: barHeight
|
|
||||||
|
|
||||||
MouseArea { // Left side | scroll to change brightness
|
MouseArea { // Left side | scroll to change brightness
|
||||||
id: barLeftSideMouseArea
|
id: barLeftSideMouseArea
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
implicitHeight: barHeight
|
implicitHeight: Appearance.sizes.baseBarHeight
|
||||||
|
height: Appearance.sizes.barHeight
|
||||||
width: (barRoot.width - middleSection.width) / 2
|
width: (barRoot.width - middleSection.width) / 2
|
||||||
property bool hovered: false
|
property bool hovered: false
|
||||||
property real lastScrollX: 0
|
property real lastScrollX: 0
|
||||||
@@ -170,7 +204,7 @@ Scope {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: 19.5
|
width: 19.5
|
||||||
height: 19.5
|
height: 19.5
|
||||||
source: ConfigOptions.bar.topLeftIcon == 'distro' ?
|
source: Config.options.bar.topLeftIcon == 'distro' ?
|
||||||
SystemInfo.distroIcon : "spark-symbolic"
|
SystemInfo.distroIcon : "spark-symbolic"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +229,7 @@ Scope {
|
|||||||
RowLayout { // Middle section
|
RowLayout { // Middle section
|
||||||
id: middleSection
|
id: middleSection
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: ConfigOptions?.bar.borderless ? 4 : 8
|
spacing: Config.options?.bar.borderless ? 4 : 8
|
||||||
|
|
||||||
BarGroup {
|
BarGroup {
|
||||||
id: leftCenterGroup
|
id: leftCenterGroup
|
||||||
@@ -214,7 +248,7 @@ Scope {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VerticalBarSeparator {visible: ConfigOptions?.bar.borderless}
|
VerticalBarSeparator {visible: Config.options?.bar.borderless}
|
||||||
|
|
||||||
BarGroup {
|
BarGroup {
|
||||||
id: middleCenterGroup
|
id: middleCenterGroup
|
||||||
@@ -238,7 +272,7 @@ Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VerticalBarSeparator {visible: ConfigOptions?.bar.borderless}
|
VerticalBarSeparator {visible: Config.options?.bar.borderless}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: rightCenterGroup
|
id: rightCenterGroup
|
||||||
@@ -256,13 +290,13 @@ Scope {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
ClockWidget {
|
ClockWidget {
|
||||||
showDate: (ConfigOptions.bar.verbose && barRoot.useShortenedForm < 2)
|
showDate: (Config.options.bar.verbose && barRoot.useShortenedForm < 2)
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
UtilButtons {
|
UtilButtons {
|
||||||
visible: (ConfigOptions.bar.verbose && barRoot.useShortenedForm === 0)
|
visible: (Config.options.bar.verbose && barRoot.useShortenedForm === 0)
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +313,8 @@ Scope {
|
|||||||
id: barRightSideMouseArea
|
id: barRightSideMouseArea
|
||||||
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
implicitHeight: barHeight
|
implicitHeight: Appearance.sizes.baseBarHeight
|
||||||
|
height: Appearance.sizes.barHeight
|
||||||
width: (barRoot.width - middleSection.width) / 2
|
width: (barRoot.width - middleSection.width) / 2
|
||||||
|
|
||||||
property bool hovered: false
|
property bool hovered: false
|
||||||
@@ -354,10 +389,14 @@ Scope {
|
|||||||
|
|
||||||
RippleButton { // Right sidebar button
|
RippleButton { // Right sidebar button
|
||||||
id: rightSidebarButton
|
id: rightSidebarButton
|
||||||
Layout.margins: 4
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
Layout.rightMargin: Appearance.rounding.screenRounding
|
Layout.rightMargin: Appearance.rounding.screenRounding
|
||||||
Layout.fillHeight: true
|
Layout.fillWidth: false
|
||||||
implicitWidth: indicatorsRowLayout.implicitWidth + 10*2
|
|
||||||
|
implicitWidth: indicatorsRowLayout.implicitWidth + 10 * 2
|
||||||
|
implicitHeight: indicatorsRowLayout.implicitHeight + 5 * 2
|
||||||
|
|
||||||
buttonRadius: Appearance.rounding.full
|
buttonRadius: Appearance.rounding.full
|
||||||
colBackground: barRightSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
|
colBackground: barRightSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
|
||||||
colBackgroundHover: Appearance.colors.colLayer1Hover
|
colBackgroundHover: Appearance.colors.colLayer1Hover
|
||||||
@@ -447,32 +486,68 @@ Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Round decorators
|
// Round decorators
|
||||||
Item {
|
Loader {
|
||||||
|
id: roundDecorators
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: parent.right
|
right: parent.right
|
||||||
// top: barContent.bottom
|
|
||||||
top: ConfigOptions.bar.bottom ? undefined : barContent.bottom
|
|
||||||
bottom: ConfigOptions.bar.bottom ? barContent.top : undefined
|
|
||||||
}
|
}
|
||||||
|
y: Appearance.sizes.barHeight
|
||||||
|
width: parent.width
|
||||||
height: Appearance.rounding.screenRounding
|
height: Appearance.rounding.screenRounding
|
||||||
visible: showBarBackground
|
active: showBarBackground && Config.options.bar.cornerStyle === 0 // Hug
|
||||||
|
|
||||||
RoundCorner {
|
states: State {
|
||||||
anchors.top: parent.top
|
name: "bottom"
|
||||||
anchors.left: parent.left
|
when: Config.options.bar.bottom
|
||||||
size: Appearance.rounding.screenRounding
|
PropertyChanges {
|
||||||
corner: ConfigOptions.bar.bottom ? cornerEnum.bottomLeft : cornerEnum.topLeft
|
roundDecorators.y: 0
|
||||||
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
|
}
|
||||||
opacity: 1.0 - Appearance.transparency
|
|
||||||
}
|
}
|
||||||
RoundCorner {
|
|
||||||
anchors.top: parent.top
|
sourceComponent: Item {
|
||||||
anchors.right: parent.right
|
implicitHeight: Appearance.rounding.screenRounding
|
||||||
size: Appearance.rounding.screenRounding
|
RoundCorner {
|
||||||
corner: ConfigOptions.bar.bottom ? cornerEnum.bottomRight : cornerEnum.topRight
|
id: leftCorner
|
||||||
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
|
anchors {
|
||||||
opacity: 1.0 - Appearance.transparency
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
left: parent.left
|
||||||
|
}
|
||||||
|
|
||||||
|
size: Appearance.rounding.screenRounding
|
||||||
|
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
|
||||||
|
opacity: 1.0 - Appearance.transparency
|
||||||
|
|
||||||
|
corner: RoundCorner.CornerEnum.TopLeft
|
||||||
|
states: State {
|
||||||
|
name: "bottom"
|
||||||
|
when: Config.options.bar.bottom
|
||||||
|
PropertyChanges {
|
||||||
|
leftCorner.corner: RoundCorner.CornerEnum.BottomLeft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RoundCorner {
|
||||||
|
id: rightCorner
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
top: !Config.options.bar.bottom ? parent.top : undefined
|
||||||
|
bottom: Config.options.bar.bottom ? parent.bottom : undefined
|
||||||
|
}
|
||||||
|
size: Appearance.rounding.screenRounding
|
||||||
|
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
|
||||||
|
opacity: 1.0 - Appearance.transparency
|
||||||
|
|
||||||
|
corner: RoundCorner.CornerEnum.TopRight
|
||||||
|
states: State {
|
||||||
|
name: "bottom"
|
||||||
|
when: Config.options.bar.bottom
|
||||||
|
PropertyChanges {
|
||||||
|
rightCorner.corner: RoundCorner.CornerEnum.BottomRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import QtQuick.Layouts
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property real padding: 5
|
property real padding: 5
|
||||||
implicitHeight: 40
|
implicitHeight: Appearance.sizes.baseBarHeight
|
||||||
|
height: Appearance.sizes.barHeight
|
||||||
implicitWidth: rowLayout.implicitWidth + padding * 2
|
implicitWidth: rowLayout.implicitWidth + padding * 2
|
||||||
default property alias items: rowLayout.children
|
default property alias items: rowLayout.children
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ Item {
|
|||||||
topMargin: 4
|
topMargin: 4
|
||||||
bottomMargin: 4
|
bottomMargin: 4
|
||||||
}
|
}
|
||||||
color: ConfigOptions?.bar.borderless ? "transparent" : Appearance.colors.colLayer1
|
color: Config.options?.bar.borderless ? "transparent" : Appearance.colors.colLayer1
|
||||||
radius: Appearance.rounding.small
|
radius: Appearance.rounding.small
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import Quickshell.Services.UPower
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property bool borderless: ConfigOptions.bar.borderless
|
property bool borderless: Config.options.bar.borderless
|
||||||
readonly property var chargeState: Battery.chargeState
|
readonly property var chargeState: Battery.chargeState
|
||||||
readonly property bool isCharging: Battery.isCharging
|
readonly property bool isCharging: Battery.isCharging
|
||||||
readonly property bool isPluggedIn: Battery.isPluggedIn
|
readonly property bool isPluggedIn: Battery.isPluggedIn
|
||||||
readonly property real percentage: Battery.percentage
|
readonly property real percentage: Battery.percentage
|
||||||
readonly property bool isLow: percentage <= ConfigOptions.battery.low / 100
|
readonly property bool isLow: percentage <= Config.options.battery.low / 100
|
||||||
readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer
|
readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer
|
||||||
readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error
|
readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import QtQuick.Layouts
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property bool borderless: ConfigOptions.bar.borderless
|
property bool borderless: Config.options.bar.borderless
|
||||||
property bool showDate: ConfigOptions.bar.verbose
|
property bool showDate: Config.options.bar.verbose
|
||||||
implicitWidth: rowLayout.implicitWidth
|
implicitWidth: rowLayout.implicitWidth
|
||||||
implicitHeight: 32
|
implicitHeight: 32
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import Quickshell.Hyprland
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property bool borderless: ConfigOptions.bar.borderless
|
property bool borderless: Config.options.bar.borderless
|
||||||
readonly property MprisPlayer activePlayer: MprisController.activePlayer
|
readonly property MprisPlayer activePlayer: MprisController.activePlayer
|
||||||
readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) || Translation.tr("No media")
|
readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) || Translation.tr("No media")
|
||||||
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
|
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
|
||||||
implicitHeight: 40
|
implicitHeight: Appearance.sizes.barHeight
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
running: activePlayer?.playbackState == MprisPlaybackState.Playing
|
running: activePlayer?.playbackState == MprisPlaybackState.Playing
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import Quickshell.Services.Mpris
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property bool borderless: ConfigOptions.bar.borderless
|
property bool borderless: Config.options.bar.borderless
|
||||||
property bool alwaysShowAllResources: false
|
property bool alwaysShowAllResources: false
|
||||||
implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin
|
implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin
|
||||||
implicitHeight: 32
|
implicitHeight: 32
|
||||||
@@ -30,7 +30,7 @@ Item {
|
|||||||
Resource {
|
Resource {
|
||||||
iconName: "swap_horiz"
|
iconName: "swap_horiz"
|
||||||
percentage: ResourceUsage.swapUsedPercentage
|
percentage: ResourceUsage.swapUsedPercentage
|
||||||
shown: (ConfigOptions.bar.resources.alwaysShowSwap && percentage > 0) ||
|
shown: (Config.options.bar.resources.alwaysShowSwap && percentage > 0) ||
|
||||||
(MprisController.activePlayer?.trackTitle == null) ||
|
(MprisController.activePlayer?.trackTitle == null) ||
|
||||||
root.alwaysShowAllResources
|
root.alwaysShowAllResources
|
||||||
Layout.leftMargin: shown ? 4 : 0
|
Layout.leftMargin: shown ? 4 : 0
|
||||||
@@ -39,7 +39,7 @@ Item {
|
|||||||
Resource {
|
Resource {
|
||||||
iconName: "settings_slow_motion"
|
iconName: "settings_slow_motion"
|
||||||
percentage: ResourceUsage.cpuUsage
|
percentage: ResourceUsage.cpuUsage
|
||||||
shown: ConfigOptions.bar.resources.alwaysShowCpu ||
|
shown: Config.options.bar.resources.alwaysShowCpu ||
|
||||||
!(MprisController.activePlayer?.trackTitle?.length > 0) ||
|
!(MprisController.activePlayer?.trackTitle?.length > 0) ||
|
||||||
root.alwaysShowAllResources
|
root.alwaysShowAllResources
|
||||||
Layout.leftMargin: shown ? 4 : 0
|
Layout.leftMargin: shown ? 4 : 0
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ MouseArea {
|
|||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
id: trayIcon
|
id: trayIcon
|
||||||
visible: !ConfigOptions.bar.tray.monochromeIcons
|
visible: !Config.options.bar.tray.monochromeIcons
|
||||||
source: root.item.icon
|
source: root.item.icon
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -51,7 +51,7 @@ MouseArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: ConfigOptions.bar.tray.monochromeIcons
|
active: Config.options.bar.tray.monochromeIcons
|
||||||
anchors.fill: trayIcon
|
anchors.fill: trayIcon
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
Desaturate {
|
Desaturate {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import Quickshell.Services.Pipewire
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property bool borderless: ConfigOptions.bar.borderless
|
property bool borderless: Config.options.bar.borderless
|
||||||
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
|
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
|
||||||
implicitHeight: rowLayout.implicitHeight
|
implicitHeight: rowLayout.implicitHeight
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: ConfigOptions.bar.utilButtons.showScreenSnip
|
active: Config.options.bar.utilButtons.showScreenSnip
|
||||||
visible: ConfigOptions.bar.utilButtons.showScreenSnip
|
visible: Config.options.bar.utilButtons.showScreenSnip
|
||||||
sourceComponent: CircleUtilButton {
|
sourceComponent: CircleUtilButton {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
onClicked: Hyprland.dispatch("exec hyprshot --freeze --clipboard-only --mode region --silent")
|
onClicked: Hyprland.dispatch("exec hyprshot --freeze --clipboard-only --mode region --silent")
|
||||||
@@ -36,8 +36,8 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: ConfigOptions.bar.utilButtons.showColorPicker
|
active: Config.options.bar.utilButtons.showColorPicker
|
||||||
visible: ConfigOptions.bar.utilButtons.showColorPicker
|
visible: Config.options.bar.utilButtons.showColorPicker
|
||||||
sourceComponent: CircleUtilButton {
|
sourceComponent: CircleUtilButton {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
onClicked: Hyprland.dispatch("exec hyprpicker -a")
|
onClicked: Hyprland.dispatch("exec hyprpicker -a")
|
||||||
@@ -52,8 +52,8 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: ConfigOptions.bar.utilButtons.showKeyboardToggle
|
active: Config.options.bar.utilButtons.showKeyboardToggle
|
||||||
visible: ConfigOptions.bar.utilButtons.showKeyboardToggle
|
visible: Config.options.bar.utilButtons.showKeyboardToggle
|
||||||
sourceComponent: CircleUtilButton {
|
sourceComponent: CircleUtilButton {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
onClicked: Hyprland.dispatch("global quickshell:oskToggle")
|
onClicked: Hyprland.dispatch("global quickshell:oskToggle")
|
||||||
@@ -68,8 +68,8 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: ConfigOptions.bar.utilButtons.showMicToggle
|
active: Config.options.bar.utilButtons.showMicToggle
|
||||||
visible: ConfigOptions.bar.utilButtons.showMicToggle
|
visible: Config.options.bar.utilButtons.showMicToggle
|
||||||
sourceComponent: CircleUtilButton {
|
sourceComponent: CircleUtilButton {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
onClicked: Hyprland.dispatch("exec wpctl set-mute @DEFAULT_SOURCE@ toggle")
|
onClicked: Hyprland.dispatch("exec wpctl set-mute @DEFAULT_SOURCE@ toggle")
|
||||||
@@ -84,8 +84,8 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: ConfigOptions.bar.utilButtons.showDarkModeToggle
|
active: Config.options.bar.utilButtons.showDarkModeToggle
|
||||||
visible: ConfigOptions.bar.utilButtons.showDarkModeToggle
|
visible: Config.options.bar.utilButtons.showDarkModeToggle
|
||||||
sourceComponent: CircleUtilButton {
|
sourceComponent: CircleUtilButton {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
onClicked: event => {
|
onClicked: event => {
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ import Qt5Compat.GraphicalEffects
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
required property var bar
|
required property var bar
|
||||||
property bool borderless: ConfigOptions.bar.borderless
|
property bool borderless: Config.options.bar.borderless
|
||||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
|
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
|
||||||
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
||||||
|
|
||||||
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / ConfigOptions.bar.workspaces.shown)
|
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / Config.options.bar.workspaces.shown)
|
||||||
property list<bool> workspaceOccupied: []
|
property list<bool> workspaceOccupied: []
|
||||||
property int widgetPadding: 4
|
property int widgetPadding: 4
|
||||||
property int workspaceButtonWidth: 26
|
property int workspaceButtonWidth: 26
|
||||||
@@ -27,12 +27,12 @@ Item {
|
|||||||
property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55
|
property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55
|
||||||
property real workspaceIconOpacityShrinked: 1
|
property real workspaceIconOpacityShrinked: 1
|
||||||
property real workspaceIconMarginShrinked: -4
|
property real workspaceIconMarginShrinked: -4
|
||||||
property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % ConfigOptions.bar.workspaces.shown
|
property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % Config.options.bar.workspaces.shown
|
||||||
|
|
||||||
// Function to update workspaceOccupied
|
// Function to update workspaceOccupied
|
||||||
function updateWorkspaceOccupied() {
|
function updateWorkspaceOccupied() {
|
||||||
workspaceOccupied = Array.from({ length: ConfigOptions.bar.workspaces.shown }, (_, i) => {
|
workspaceOccupied = Array.from({ length: Config.options.bar.workspaces.shown }, (_, i) => {
|
||||||
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * ConfigOptions.bar.workspaces.shown + i + 1);
|
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * Config.options.bar.workspaces.shown + i + 1);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
|
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
|
||||||
implicitHeight: 40
|
implicitHeight: Appearance.sizes.barHeight
|
||||||
|
|
||||||
// Scroll to switch workspaces
|
// Scroll to switch workspaces
|
||||||
WheelHandler {
|
WheelHandler {
|
||||||
@@ -78,10 +78,10 @@ Item {
|
|||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
implicitHeight: 40
|
implicitHeight: Appearance.sizes.barHeight
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: ConfigOptions.bar.workspaces.shown
|
model: Config.options.bar.workspaces.shown
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
z: 1
|
z: 1
|
||||||
@@ -157,14 +157,14 @@ Item {
|
|||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
implicitHeight: 40
|
implicitHeight: Appearance.sizes.barHeight
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: ConfigOptions.bar.workspaces.shown
|
model: Config.options.bar.workspaces.shown
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: button
|
id: button
|
||||||
property int workspaceValue: workspaceGroup * ConfigOptions.bar.workspaces.shown + index + 1
|
property int workspaceValue: workspaceGroup * Config.options.bar.workspaces.shown + index + 1
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
onPressed: Hyprland.dispatch(`workspace ${workspaceValue}`)
|
onPressed: Hyprland.dispatch(`workspace ${workspaceValue}`)
|
||||||
width: workspaceButtonWidth
|
width: workspaceButtonWidth
|
||||||
@@ -185,8 +185,8 @@ Item {
|
|||||||
|
|
||||||
StyledText { // Workspace number text
|
StyledText { // Workspace number text
|
||||||
opacity: GlobalStates.workspaceShowNumbers
|
opacity: GlobalStates.workspaceShowNumbers
|
||||||
|| ((ConfigOptions?.bar.workspaces.alwaysShowNumbers && (!ConfigOptions?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || GlobalStates.workspaceShowNumbers))
|
|| ((Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || GlobalStates.workspaceShowNumbers))
|
||||||
|| (GlobalStates.workspaceShowNumbers && !ConfigOptions?.bar.workspaces.showAppIcons)
|
|| (GlobalStates.workspaceShowNumbers && !Config.options?.bar.workspaces.showAppIcons)
|
||||||
) ? 1 : 0
|
) ? 1 : 0
|
||||||
z: 3
|
z: 3
|
||||||
|
|
||||||
@@ -206,9 +206,9 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rectangle { // Dot instead of ws number
|
Rectangle { // Dot instead of ws number
|
||||||
opacity: (ConfigOptions?.bar.workspaces.alwaysShowNumbers
|
opacity: (Config.options?.bar.workspaces.alwaysShowNumbers
|
||||||
|| GlobalStates.workspaceShowNumbers
|
|| GlobalStates.workspaceShowNumbers
|
||||||
|| (ConfigOptions?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow)
|
|| (Config.options?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow)
|
||||||
) ? 0 : 1
|
) ? 0 : 1
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -228,21 +228,21 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: workspaceButtonWidth
|
width: workspaceButtonWidth
|
||||||
height: workspaceButtonWidth
|
height: workspaceButtonWidth
|
||||||
opacity: !ConfigOptions?.bar.workspaces.showAppIcons ? 0 :
|
opacity: !Config.options?.bar.workspaces.showAppIcons ? 0 :
|
||||||
(workspaceButtonBackground.biggestWindow && !GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
|
(workspaceButtonBackground.biggestWindow && !GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
|
||||||
1 : workspaceButtonBackground.biggestWindow ? workspaceIconOpacityShrinked : 0
|
1 : workspaceButtonBackground.biggestWindow ? workspaceIconOpacityShrinked : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
IconImage {
|
IconImage {
|
||||||
id: mainAppIcon
|
id: mainAppIcon
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottomMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
|
anchors.bottomMargin: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
|
||||||
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
||||||
anchors.rightMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
|
anchors.rightMargin: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
|
||||||
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
||||||
|
|
||||||
source: workspaceButtonBackground.mainAppIconSource
|
source: workspaceButtonBackground.mainAppIconSource
|
||||||
implicitSize: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ? workspaceIconSize : workspaceIconSizeShrinked
|
implicitSize: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ? workspaceIconSize : workspaceIconSizeShrinked
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ Singleton {
|
|||||||
property string syntaxHighlightingTheme
|
property string syntaxHighlightingTheme
|
||||||
|
|
||||||
// Extremely conservative transparency values for consistency and readability
|
// Extremely conservative transparency values for consistency and readability
|
||||||
property real transparency: ConfigOptions?.appearance.transparency ? (m3colors.darkmode ? 0.1 : 0.07) : 0
|
property real transparency: Config.options?.appearance.transparency ? (m3colors.darkmode ? 0.1 : 0.07) : 0
|
||||||
property real contentTransparency: ConfigOptions?.appearance.transparency ? (m3colors.darkmode ? 0.55 : 0.55) : 0
|
property real contentTransparency: Config.options?.appearance.transparency ? (m3colors.darkmode ? 0.55 : 0.55) : 0
|
||||||
|
|
||||||
m3colors: QtObject {
|
m3colors: QtObject {
|
||||||
property bool darkmode: false
|
property bool darkmode: false
|
||||||
@@ -131,7 +131,7 @@ Singleton {
|
|||||||
property color colSecondaryHover: ColorUtils.mix(m3colors.m3secondary, colLayer1Hover, 0.85)
|
property color colSecondaryHover: ColorUtils.mix(m3colors.m3secondary, colLayer1Hover, 0.85)
|
||||||
property color colSecondaryActive: ColorUtils.mix(m3colors.m3secondary, colLayer1Active, 0.4)
|
property color colSecondaryActive: ColorUtils.mix(m3colors.m3secondary, colLayer1Active, 0.4)
|
||||||
property color colSecondaryContainer: m3colors.m3secondaryContainer
|
property color colSecondaryContainer: m3colors.m3secondaryContainer
|
||||||
property color colSecondaryContainerHover: ColorUtils.mix(m3colors.m3secondaryContainer, colLayer1Hover, 0.6)
|
property color colSecondaryContainerHover: ColorUtils.mix(m3colors.m3secondaryContainer, m3colors.m3onSecondaryContainer, 0.90)
|
||||||
property color colSecondaryContainerActive: ColorUtils.mix(m3colors.m3secondaryContainer, colLayer1Active, 0.54)
|
property color colSecondaryContainerActive: ColorUtils.mix(m3colors.m3secondaryContainer, colLayer1Active, 0.54)
|
||||||
property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer
|
property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer
|
||||||
property color colSurfaceContainerLow: ColorUtils.transparentize(m3colors.m3surfaceContainerLow, root.contentTransparency)
|
property color colSurfaceContainerLow: ColorUtils.transparentize(m3colors.m3surfaceContainerLow, root.contentTransparency)
|
||||||
@@ -171,7 +171,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
property QtObject pixelSize: QtObject {
|
property QtObject pixelSize: QtObject {
|
||||||
property int smallest: 10
|
property int smallest: 10
|
||||||
property int smaller: 13
|
property int smaller: 12
|
||||||
property int small: 15
|
property int small: 15
|
||||||
property int normal: 16
|
property int normal: 16
|
||||||
property int large: 17
|
property int large: 17
|
||||||
@@ -288,8 +288,10 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sizes: QtObject {
|
sizes: QtObject {
|
||||||
property real barHeight: 40
|
property real baseBarHeight: 40
|
||||||
property real barCenterSideModuleWidth: ConfigOptions?.bar.verbose ? 360 : 140
|
property real barHeight: Config.options.bar.cornerStyle === 1 ?
|
||||||
|
(baseBarHeight + Appearance.sizes.hyprlandGapsOut * 2) : baseBarHeight
|
||||||
|
property real barCenterSideModuleWidth: Config.options?.bar.verbose ? 360 : 140
|
||||||
property real barCenterSideModuleWidthShortened: 280
|
property real barCenterSideModuleWidthShortened: 280
|
||||||
property real barCenterSideModuleWidthHellaShortened: 190
|
property real barCenterSideModuleWidthHellaShortened: 190
|
||||||
property real barShortenScreenWidthThreshold: 1200 // Shorten if screen width is at most this value
|
property real barShortenScreenWidthThreshold: 1200 // Shorten if screen width is at most this value
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
property string filePath: Directories.shellConfigPath
|
||||||
|
property alias options: configOptionsJsonAdapter
|
||||||
|
|
||||||
|
function setNestedValue(nestedKey, value) {
|
||||||
|
let keys = nestedKey.split(".");
|
||||||
|
let obj = root.options;
|
||||||
|
let parents = [obj];
|
||||||
|
|
||||||
|
// Traverse and collect parent objects
|
||||||
|
for (let i = 0; i < keys.length - 1; ++i) {
|
||||||
|
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
|
||||||
|
obj[keys[i]] = {};
|
||||||
|
}
|
||||||
|
obj = obj[keys[i]];
|
||||||
|
parents.push(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert value to correct type using JSON.parse when safe
|
||||||
|
let convertedValue = value;
|
||||||
|
if (typeof value === "string") {
|
||||||
|
let trimmed = value.trim();
|
||||||
|
if (trimmed === "true" || trimmed === "false" || !isNaN(Number(trimmed))) {
|
||||||
|
try {
|
||||||
|
convertedValue = JSON.parse(trimmed);
|
||||||
|
} catch (e) {
|
||||||
|
convertedValue = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj[keys[keys.length - 1]] = convertedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
path: root.filePath
|
||||||
|
|
||||||
|
watchChanges: true
|
||||||
|
onFileChanged: reload()
|
||||||
|
onAdapterUpdated: writeAdapter()
|
||||||
|
onLoadFailed: error => {
|
||||||
|
if (error == FileViewError.FileNotFound) {
|
||||||
|
writeAdapter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonAdapter {
|
||||||
|
id: configOptionsJsonAdapter
|
||||||
|
property JsonObject policies: JsonObject {
|
||||||
|
property int ai: 1 // 0: No | 1: Yes | 2: Local
|
||||||
|
property int weeb: 1 // 0: No | 1: Open | 2: Closet
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject ai: JsonObject {
|
||||||
|
property string systemPrompt: qsTr("## Style\n- Use casual tone, don't be formal! Make sure you answer precisely without hallucination and prefer bullet points over walls of text. You can have a friendly greeting at the beginning of the conversation, but don't repeat the user's question\n\n## Presentation\n- Use Markdown features in your response: \n - **Bold** text to **highlight keywords** in your response\n - **Split long information into small sections** with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). Bullet points are preferred over long paragraphs, unless you're offering writing support or instructed otherwise by the user.\n- Asked to compare different options? You should firstly use a table to compare the main aspects, then elaborate or include relevant comments from online forums *after* the table. Make sure to provide a final recommendation for the user's use case!\n- Use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).\n\nThanks!\n\n## Tools\nMay or may not be available depending on the user's settings. If they're available, follow these guidelines:\n\n### Search\n- When user asks for information that might benefit from up-to-date information, use this to get search access\n\n### Shell configuration\n- Always fetch the config options to see the available keys before setting\n- Avoid unnecessarily asking the user to confirm the changes they explicitly asked for, just do it\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject appearance: JsonObject {
|
||||||
|
property int fakeScreenRounding: 2 // 0: None | 1: Always | 2: When not fullscreen
|
||||||
|
property bool transparency: false
|
||||||
|
property JsonObject palette: JsonObject {
|
||||||
|
property string type: "auto" // Allowed: auto, scheme-content, scheme-expressive, scheme-fidelity, scheme-fruit-salad, scheme-monochrome, scheme-neutral, scheme-rainbow, scheme-tonal-spot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject audio: JsonObject {
|
||||||
|
// Values in %
|
||||||
|
property JsonObject protection: JsonObject {
|
||||||
|
// Prevent sudden bangs
|
||||||
|
property bool enable: true
|
||||||
|
property real maxAllowedIncrease: 10
|
||||||
|
property real maxAllowed: 90 // Realistically should already provide some protection when it's 99...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject apps: JsonObject {
|
||||||
|
property string bluetooth: "kcmshell6 kcm_bluetooth"
|
||||||
|
property string network: "plasmawindowed org.kde.plasma.networkmanagement"
|
||||||
|
property string networkEthernet: "kcmshell6 kcm_networkmanagement"
|
||||||
|
property string taskManager: "plasma-systemmonitor --page-name Processes"
|
||||||
|
property string terminal: "kitty -1" // This is only for shell actions
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject background: JsonObject {
|
||||||
|
property bool fixedClockPosition: false
|
||||||
|
property real clockX: -500
|
||||||
|
property real clockY: -500
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject bar: JsonObject {
|
||||||
|
property bool bottom: false // Instead of top
|
||||||
|
property int cornerStyle: 0 // 0: Hug | 1: Float | 2: Plain rectangle
|
||||||
|
property bool borderless: false // true for no grouping of items
|
||||||
|
property string topLeftIcon: "spark" // Options: distro, spark
|
||||||
|
property bool showBackground: true
|
||||||
|
property bool verbose: true
|
||||||
|
property JsonObject resources: JsonObject {
|
||||||
|
property bool alwaysShowSwap: true
|
||||||
|
property bool alwaysShowCpu: false
|
||||||
|
}
|
||||||
|
property list<string> screenList: [] // List of names, like "eDP-1", find out with 'hyprctl monitors' command
|
||||||
|
property JsonObject utilButtons: JsonObject {
|
||||||
|
property bool showScreenSnip: true
|
||||||
|
property bool showColorPicker: false
|
||||||
|
property bool showMicToggle: false
|
||||||
|
property bool showKeyboardToggle: true
|
||||||
|
property bool showDarkModeToggle: true
|
||||||
|
}
|
||||||
|
property JsonObject tray: JsonObject {
|
||||||
|
property bool monochromeIcons: true
|
||||||
|
}
|
||||||
|
property JsonObject workspaces: JsonObject {
|
||||||
|
property int shown: 10
|
||||||
|
property bool showAppIcons: true
|
||||||
|
property bool alwaysShowNumbers: false
|
||||||
|
property int showNumberDelay: 300 // milliseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject battery: JsonObject {
|
||||||
|
property int low: 20
|
||||||
|
property int critical: 5
|
||||||
|
property bool automaticSuspend: true
|
||||||
|
property int suspend: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject dock: JsonObject {
|
||||||
|
property bool enable: false
|
||||||
|
property real height: 60
|
||||||
|
property real hoverRegionHeight: 3
|
||||||
|
property bool pinnedOnStartup: false
|
||||||
|
property bool hoverToReveal: true // When false, only reveals on empty workspace
|
||||||
|
property list<string> pinnedApps: [ // IDs of pinned entries
|
||||||
|
"org.kde.dolphin", "kitty",]
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject language: JsonObject {
|
||||||
|
property JsonObject translator: JsonObject {
|
||||||
|
property string engine: "auto" // Run `trans -list-engines` for available engines. auto should use google
|
||||||
|
property string targetLanguage: "auto" // Run `trans -list-all` for available languages
|
||||||
|
property string sourceLanguage: "auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject networking: JsonObject {
|
||||||
|
property string userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject osd: JsonObject {
|
||||||
|
property int timeout: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject osk: JsonObject {
|
||||||
|
property string layout: "qwerty_full"
|
||||||
|
property bool pinnedOnStartup: false
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject overview: JsonObject {
|
||||||
|
property real scale: 0.18 // Relative to screen size
|
||||||
|
property real rows: 2
|
||||||
|
property real columns: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject resources: JsonObject {
|
||||||
|
property int updateInterval: 3000
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject search: JsonObject {
|
||||||
|
property int nonAppResultDelay: 30 // This prevents lagging when typing
|
||||||
|
property string engineBaseUrl: "https://www.google.com/search?q="
|
||||||
|
property list<string> excludedSites: ["quora.com"]
|
||||||
|
property bool sloppy: false // Uses levenshtein distance based scoring instead of fuzzy sort. Very weird.
|
||||||
|
property JsonObject prefix: JsonObject {
|
||||||
|
property string action: "/"
|
||||||
|
property string clipboard: ";"
|
||||||
|
property string emojis: ":"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject sidebar: JsonObject {
|
||||||
|
property JsonObject translator: JsonObject {
|
||||||
|
property int delay: 300 // Delay before sending request. Reduces (potential) rate limits and lag.
|
||||||
|
}
|
||||||
|
property JsonObject booru: JsonObject {
|
||||||
|
property bool allowNsfw: false
|
||||||
|
property string defaultProvider: "yandere"
|
||||||
|
property int limit: 20
|
||||||
|
property JsonObject zerochan: JsonObject {
|
||||||
|
property string username: "[unset]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject time: JsonObject {
|
||||||
|
// https://doc.qt.io/qt-6/qtime.html#toString
|
||||||
|
property string format: "hh:mm"
|
||||||
|
property string dateFormat: "dddd, dd/MM"
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject windows: JsonObject {
|
||||||
|
property bool showTitlebar: true // Client-side decoration for shell apps
|
||||||
|
property bool centerTitle: true
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject hacks: JsonObject {
|
||||||
|
property int arbitraryRaceConditionDelay: 20 // milliseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
property QtObject policies: QtObject {
|
|
||||||
property int ai: 1 // 0: No | 1: Yes | 2: Local
|
|
||||||
property int weeb: 1 // 0: No | 1: Open | 2: Closet
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject ai: QtObject {
|
|
||||||
property string systemPrompt: qsTr("Use casual tone. No user knowledge is to be assumed except basic Linux literacy. Be brief and concise: When explaining concepts, use bullet points (prefer minus sign (-) over asterisk (*)) and highlight keywords in bold to pinpoint the main concepts instead of long paragraphs. You are also encouraged to split your response with h2 headers, each header title beginning with an emoji, like `## 🐧 Linux`. When making changes to the user's config, you must get the config to know what values there are before setting.")
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject appearance: QtObject {
|
|
||||||
property int fakeScreenRounding: 2 // 0: None | 1: Always | 2: When not fullscreen
|
|
||||||
property bool transparency: false
|
|
||||||
property QtObject palette: QtObject {
|
|
||||||
property string type: "auto" // Allowed: auto, scheme-content, scheme-expressive, scheme-fidelity, scheme-fruit-salad, scheme-monochrome, scheme-neutral, scheme-rainbow, scheme-tonal-spot
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject audio: QtObject {
|
|
||||||
// Values in %
|
|
||||||
property QtObject protection: QtObject {
|
|
||||||
// Prevent sudden bangs
|
|
||||||
property bool enable: true
|
|
||||||
property real maxAllowedIncrease: 10
|
|
||||||
property real maxAllowed: 90 // Realistically should already provide some protection when it's 99...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject apps: QtObject {
|
|
||||||
property string bluetooth: "kcmshell6 kcm_bluetooth"
|
|
||||||
property string network: "plasmawindowed org.kde.plasma.networkmanagement"
|
|
||||||
property string networkEthernet: "kcmshell6 kcm_networkmanagement"
|
|
||||||
property string taskManager: "plasma-systemmonitor --page-name Processes"
|
|
||||||
property string terminal: "kitty -1" // This is only for shell actions
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject background: QtObject {
|
|
||||||
property bool fixedClockPosition: false
|
|
||||||
property real clockX: -500
|
|
||||||
property real clockY: -500
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject bar: QtObject {
|
|
||||||
property bool bottom: false // Instead of top
|
|
||||||
property bool borderless: false // true for no grouping of items
|
|
||||||
property string topLeftIcon: "spark" // Options: distro, spark
|
|
||||||
property bool showBackground: true
|
|
||||||
property bool verbose: true
|
|
||||||
property QtObject resources: QtObject {
|
|
||||||
property bool alwaysShowSwap: true
|
|
||||||
property bool alwaysShowCpu: false
|
|
||||||
}
|
|
||||||
property list<string> screenList: [] // List of names, like "eDP-1", find out with 'hyprctl monitors' command
|
|
||||||
property QtObject utilButtons: QtObject {
|
|
||||||
property bool showScreenSnip: true
|
|
||||||
property bool showColorPicker: false
|
|
||||||
property bool showMicToggle: false
|
|
||||||
property bool showKeyboardToggle: true
|
|
||||||
property bool showDarkModeToggle: true
|
|
||||||
}
|
|
||||||
property QtObject tray: QtObject {
|
|
||||||
property bool monochromeIcons: true
|
|
||||||
}
|
|
||||||
property QtObject workspaces: QtObject {
|
|
||||||
property int shown: 10
|
|
||||||
property bool showAppIcons: true
|
|
||||||
property bool alwaysShowNumbers: false
|
|
||||||
property int showNumberDelay: 300 // milliseconds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject battery: QtObject {
|
|
||||||
property int low: 20
|
|
||||||
property int critical: 5
|
|
||||||
property bool automaticSuspend: true
|
|
||||||
property int suspend: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject dock: QtObject {
|
|
||||||
property real height: 60
|
|
||||||
property real hoverRegionHeight: 3
|
|
||||||
property bool pinnedOnStartup: false
|
|
||||||
property bool hoverToReveal: false // When false, only reveals on empty workspace
|
|
||||||
property list<string> pinnedApps: [ // IDs of pinned entries
|
|
||||||
"org.kde.dolphin", "kitty",]
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject language: QtObject {
|
|
||||||
property string ui: "auto" // Interface language: "auto", "en", "zh-CN", "zh-TW", etc.
|
|
||||||
property QtObject translator: QtObject {
|
|
||||||
property string engine: "auto" // Run `trans -list-engines` for available engines. auto should use google
|
|
||||||
property string targetLanguage: "auto" // Run `trans -list-all` for available languages
|
|
||||||
property string sourceLanguage: "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject networking: QtObject {
|
|
||||||
property string userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject osd: QtObject {
|
|
||||||
property int timeout: 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject osk: QtObject {
|
|
||||||
property string layout: "qwerty_full"
|
|
||||||
property bool pinnedOnStartup: false
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject overview: QtObject {
|
|
||||||
property real scale: 0.18 // Relative to screen size
|
|
||||||
property real rows: 2
|
|
||||||
property real columns: 5
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject resources: QtObject {
|
|
||||||
property int updateInterval: 3000
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject search: QtObject {
|
|
||||||
property int nonAppResultDelay: 30 // This prevents lagging when typing
|
|
||||||
property string engineBaseUrl: "https://www.google.com/search?q="
|
|
||||||
property list<string> excludedSites: ["quora.com"]
|
|
||||||
property bool sloppy: false // Uses levenshtein distance based scoring instead of fuzzy sort. Very weird.
|
|
||||||
property QtObject prefix: QtObject {
|
|
||||||
property string action: "/"
|
|
||||||
property string clipboard: ";"
|
|
||||||
property string emojis: ":"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject sidebar: QtObject {
|
|
||||||
property QtObject translator: QtObject {
|
|
||||||
property int delay: 300 // Delay before sending request. Reduces (potential) rate limits and lag.
|
|
||||||
}
|
|
||||||
property QtObject booru: QtObject {
|
|
||||||
property bool allowNsfw: false
|
|
||||||
property string defaultProvider: "yandere"
|
|
||||||
property int limit: 20
|
|
||||||
property QtObject zerochan: QtObject {
|
|
||||||
property string username: "[unset]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject time: QtObject {
|
|
||||||
// https://doc.qt.io/qt-6/qtime.html#toString
|
|
||||||
property string format: "hh:mm"
|
|
||||||
property string dateFormat: "dddd, dd/MM"
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject windows: QtObject {
|
|
||||||
property bool showTitlebar: true // Client-side decoration for shell apps
|
|
||||||
property bool centerTitle: true
|
|
||||||
}
|
|
||||||
|
|
||||||
property QtObject hacks: QtObject {
|
|
||||||
property int arbitraryRaceConditionDelay: 20 // milliseconds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,6 +16,7 @@ Singleton {
|
|||||||
readonly property string downloads: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
|
readonly property string downloads: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
|
||||||
|
|
||||||
// Other dirs used by the shell, without "file://"
|
// Other dirs used by the shell, without "file://"
|
||||||
|
property string scriptPath: FileUtils.trimFileProtocol(`${Directories.config}/quickshell/scripts`)
|
||||||
property string favicons: FileUtils.trimFileProtocol(`${Directories.cache}/media/favicons`)
|
property string favicons: FileUtils.trimFileProtocol(`${Directories.cache}/media/favicons`)
|
||||||
property string coverArt: FileUtils.trimFileProtocol(`${Directories.cache}/media/coverart`)
|
property string coverArt: FileUtils.trimFileProtocol(`${Directories.cache}/media/coverart`)
|
||||||
property string booruPreviews: FileUtils.trimFileProtocol(`${Directories.cache}/media/boorus`)
|
property string booruPreviews: FileUtils.trimFileProtocol(`${Directories.cache}/media/boorus`)
|
||||||
@@ -29,7 +30,9 @@ Singleton {
|
|||||||
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 cliphistDecode: FileUtils.trimFileProtocol(`/tmp/quickshell/media/cliphist`)
|
property string cliphistDecode: FileUtils.trimFileProtocol(`/tmp/quickshell/media/cliphist`)
|
||||||
property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.config}/quickshell/scripts/colors/switchwall.sh`)
|
property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`)
|
||||||
|
property string defaultAiPrompts: FileUtils.trimFileProtocol(`${Directories.config}/quickshell/defaults/ai/prompts`)
|
||||||
|
property string userAiPrompts: FileUtils.trimFileProtocol(`${Directories.shellConfig}/ai/prompts`)
|
||||||
// Cleanup on init
|
// Cleanup on init
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Quickshell.execDetached(["bash", "-c", `mkdir -p '${shellConfig}'`])
|
Quickshell.execDetached(["bash", "-c", `mkdir -p '${shellConfig}'`])
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
property alias states: persistentStatesJsonAdapter
|
||||||
|
property string fileDir: Directories.state
|
||||||
|
property string fileName: "states.json"
|
||||||
|
property string filePath: `${root.fileDir}/${root.fileName}`
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
path: root.filePath
|
||||||
|
|
||||||
|
watchChanges: true
|
||||||
|
onFileChanged: reload()
|
||||||
|
onAdapterUpdated: {
|
||||||
|
writeAdapter()
|
||||||
|
}
|
||||||
|
onLoadFailed: error => {
|
||||||
|
console.log("Failed to load persistent states file:", error);
|
||||||
|
if (error == FileViewError.FileNotFound) {
|
||||||
|
writeAdapter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter: JsonAdapter {
|
||||||
|
id: persistentStatesJsonAdapter
|
||||||
|
property JsonObject ai: JsonObject {
|
||||||
|
property string model
|
||||||
|
property real temperature: 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject sidebar: JsonObject {
|
||||||
|
property JsonObject bottomGroup: JsonObject {
|
||||||
|
property bool collapsed: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject booru: JsonObject {
|
||||||
|
property bool allowNsfw: false
|
||||||
|
property string provider: "yandere"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,3 +7,28 @@ function trimFileProtocol(str) {
|
|||||||
return str.startsWith("file://") ? str.slice(7) : str;
|
return str.startsWith("file://") ? str.slice(7) : str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the file name from a file path
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function fileNameForPath(str) {
|
||||||
|
if (typeof str !== "string") return "";
|
||||||
|
const trimmed = trimFileProtocol(str);
|
||||||
|
return trimmed.split(/[\\/]/).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the file extension from a file path or name
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function trimFileExt(str) {
|
||||||
|
if (typeof str !== "string") return "";
|
||||||
|
const trimmed = trimFileProtocol(str);
|
||||||
|
const lastDot = trimmed.lastIndexOf(".");
|
||||||
|
if (lastDot > -1 && lastDot > trimmed.lastIndexOf("/")) {
|
||||||
|
return trimmed.slice(0, lastDot);
|
||||||
|
}
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ IconImage {
|
|||||||
property string displayText
|
property string displayText
|
||||||
|
|
||||||
property real size: 32
|
property real size: 32
|
||||||
property string downloadUserAgent: ConfigOptions?.networking.userAgent ?? ""
|
property string downloadUserAgent: Config.options?.networking.userAgent ?? ""
|
||||||
property string faviconDownloadPath: Directories.favicons
|
property string faviconDownloadPath: Directories.favicons
|
||||||
property string domainName: url.includes("vertexaisearch") ? displayText : StringUtils.getDomain(url)
|
property string domainName: url.includes("vertexaisearch") ? displayText : StringUtils.getDomain(url)
|
||||||
property string faviconUrl: `https://www.google.com/s2/favicons?domain=${domainName}&sz=32`
|
property string faviconUrl: `https://www.google.com/s2/favicons?domain=${domainName}&sz=32`
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ Rectangle {
|
|||||||
id: root
|
id: root
|
||||||
property string key
|
property string key
|
||||||
|
|
||||||
property real horizontalPadding: 7
|
property real horizontalPadding: 6
|
||||||
property real verticalPadding: 2
|
property real verticalPadding: 1
|
||||||
property real borderWidth: 1
|
property real borderWidth: 1
|
||||||
property real extraBottomBorderWidth: 2
|
property real extraBottomBorderWidth: 2
|
||||||
property color borderColor: Appearance.colors.colOnLayer0
|
property color borderColor: Appearance.colors.colOnLayer0
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ Text {
|
|||||||
family: Appearance?.font.family.iconMaterial ?? "Material Symbols Rounded"
|
family: Appearance?.font.family.iconMaterial ?? "Material Symbols Rounded"
|
||||||
pixelSize: iconSize
|
pixelSize: iconSize
|
||||||
weight: Font.Normal + (Font.DemiBold - Font.Normal) * fill
|
weight: Font.Normal + (Font.DemiBold - Font.Normal) * fill
|
||||||
|
variableAxes: {
|
||||||
|
"FILL": truncatedFill,
|
||||||
|
// "wght": font.weight,
|
||||||
|
// "GRAD": 0,
|
||||||
|
"opsz": iconSize,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
color: Appearance.m3colors.m3onBackground
|
color: Appearance.m3colors.m3onBackground
|
||||||
@@ -24,11 +30,4 @@ Text {
|
|||||||
// easing.bezierCurve: Appearance?.animation.elementMoveFast.bezierCurve ?? [0.34, 0.80, 0.34, 1.00, 1, 1]
|
// easing.bezierCurve: Appearance?.animation.elementMoveFast.bezierCurve ?? [0.34, 0.80, 0.34, 1.00, 1, 1]
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
font.variableAxes: {
|
|
||||||
"FILL": truncatedFill,
|
|
||||||
// "wght": font.weight,
|
|
||||||
// "GRAD": 0,
|
|
||||||
"opsz": iconSize,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ Item { // Notification item area
|
|||||||
font.pixelSize: root.fontSize
|
font.pixelSize: root.fontSize
|
||||||
color: Appearance.colors.colSubtext
|
color: Appearance.colors.colSubtext
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
textFormat: Text.StyledText
|
textFormat: Text.StyledText
|
||||||
text: {
|
text: {
|
||||||
return processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")
|
return processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")
|
||||||
|
|||||||
@@ -3,24 +3,21 @@ import QtQuick 2.9
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
enum CornerEnum { TopLeft, TopRight, BottomLeft, BottomRight }
|
||||||
|
property var corner: RoundCorner.CornerEnum.TopLeft // Default to TopLeft
|
||||||
|
|
||||||
property int size: 25
|
property int size: 25
|
||||||
property color color: "#000000"
|
property color color: "#000000"
|
||||||
|
|
||||||
onColorChanged: {
|
onColorChanged: {
|
||||||
canvas.requestPaint();
|
canvas.requestPaint();
|
||||||
}
|
}
|
||||||
|
onCornerChanged: {
|
||||||
property QtObject cornerEnum: QtObject {
|
canvas.requestPaint();
|
||||||
property int topLeft: 0
|
|
||||||
property int topRight: 1
|
|
||||||
property int bottomLeft: 2
|
|
||||||
property int bottomRight: 3
|
|
||||||
}
|
}
|
||||||
|
|
||||||
property int corner: cornerEnum.topLeft // Default to TopLeft
|
implicitWidth: size
|
||||||
|
implicitHeight: size
|
||||||
width: size
|
|
||||||
height: size
|
|
||||||
|
|
||||||
Canvas {
|
Canvas {
|
||||||
id: canvas
|
id: canvas
|
||||||
@@ -31,22 +28,22 @@ Item {
|
|||||||
onPaint: {
|
onPaint: {
|
||||||
var ctx = getContext("2d");
|
var ctx = getContext("2d");
|
||||||
var r = root.size;
|
var r = root.size;
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
switch (root.corner) {
|
switch (root.corner) {
|
||||||
case cornerEnum.topLeft:
|
case RoundCorner.CornerEnum.TopLeft:
|
||||||
ctx.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
|
ctx.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
|
||||||
ctx.lineTo(0, 0);
|
ctx.lineTo(0, 0);
|
||||||
break;
|
break;
|
||||||
case cornerEnum.topRight:
|
case RoundCorner.CornerEnum.TopRight:
|
||||||
ctx.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI);
|
ctx.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI);
|
||||||
ctx.lineTo(r, 0);
|
ctx.lineTo(r, 0);
|
||||||
break;
|
break;
|
||||||
case cornerEnum.bottomLeft:
|
case RoundCorner.CornerEnum.BottomLeft:
|
||||||
ctx.arc(r, 0, r, Math.PI / 2, Math.PI);
|
ctx.arc(r, 0, r, Math.PI / 2, Math.PI);
|
||||||
ctx.lineTo(0, r);
|
ctx.lineTo(0, r);
|
||||||
break;
|
break;
|
||||||
case cornerEnum.bottomRight:
|
case RoundCorner.CornerEnum.BottomRight:
|
||||||
ctx.arc(0, 0, r, 0, Math.PI / 2);
|
ctx.arc(0, 0, r, 0, Math.PI / 2);
|
||||||
ctx.lineTo(r, r);
|
ctx.lineTo(r, r);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import Quickshell.Hyprland
|
|||||||
|
|
||||||
Scope { // Scope
|
Scope { // Scope
|
||||||
id: root
|
id: root
|
||||||
property bool pinned: ConfigOptions?.dock.pinnedOnStartup ?? false
|
property bool pinned: Config.options?.dock.pinnedOnStartup ?? false
|
||||||
|
|
||||||
Variants { // For each monitor
|
Variants { // For each monitor
|
||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
@@ -22,14 +22,14 @@ Scope { // Scope
|
|||||||
LazyLoader {
|
LazyLoader {
|
||||||
id: dockLoader
|
id: dockLoader
|
||||||
required property var modelData
|
required property var modelData
|
||||||
activeAsync: ConfigOptions?.dock.hoverToReveal || (!ToplevelManager.activeToplevel?.activated)
|
activeAsync: Config.options?.dock.hoverToReveal || (!ToplevelManager.activeToplevel?.activated)
|
||||||
|
|
||||||
component: PanelWindow { // Window
|
component: PanelWindow { // Window
|
||||||
id: dockRoot
|
id: dockRoot
|
||||||
screen: dockLoader.modelData
|
screen: dockLoader.modelData
|
||||||
|
|
||||||
property bool reveal: root.pinned
|
property bool reveal: root.pinned
|
||||||
|| (ConfigOptions?.dock.hoverToReveal && dockMouseArea.containsMouse)
|
|| (Config.options?.dock.hoverToReveal && dockMouseArea.containsMouse)
|
||||||
|| dockApps.requestDockShow
|
|| dockApps.requestDockShow
|
||||||
|| (!ToplevelManager.activeToplevel?.activated)
|
|| (!ToplevelManager.activeToplevel?.activated)
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ Scope { // Scope
|
|||||||
WlrLayershell.namespace: "quickshell:dock"
|
WlrLayershell.namespace: "quickshell:dock"
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
implicitHeight: (ConfigOptions?.dock.height ?? 70) + Appearance.sizes.elevationMargin + Appearance.sizes.hyprlandGapsOut
|
implicitHeight: (Config.options?.dock.height ?? 70) + Appearance.sizes.elevationMargin + Appearance.sizes.hyprlandGapsOut
|
||||||
|
|
||||||
mask: Region {
|
mask: Region {
|
||||||
item: dockMouseArea
|
item: dockMouseArea
|
||||||
@@ -58,7 +58,7 @@ Scope { // Scope
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
height: parent.height
|
height: parent.height
|
||||||
anchors.topMargin: dockRoot.reveal ? 0 :
|
anchors.topMargin: dockRoot.reveal ? 0 :
|
||||||
ConfigOptions?.dock.hoverToReveal ? (dockRoot.implicitHeight - ConfigOptions.dock.hoverRegionHeight) :
|
Config.options?.dock.hoverToReveal ? (dockRoot.implicitHeight - Config.options.dock.hoverRegionHeight) :
|
||||||
(dockRoot.implicitHeight + 1)
|
(dockRoot.implicitHeight + 1)
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ Item {
|
|||||||
var map = new Map();
|
var map = new Map();
|
||||||
|
|
||||||
// Pinned apps
|
// Pinned apps
|
||||||
const pinnedApps = ConfigOptions?.dock.pinnedApps ?? [];
|
const pinnedApps = Config.options?.dock.pinnedApps ?? [];
|
||||||
for (const appId of pinnedApps) {
|
for (const appId of pinnedApps) {
|
||||||
if (!map.has(appId.toLowerCase())) map.set(appId.toLowerCase(), ({
|
if (!map.has(appId.toLowerCase())) map.set(appId.toLowerCase(), ({
|
||||||
pinned: true,
|
pinned: true,
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ Scope {
|
|||||||
WlrLayershell.namespace: "quickshell:mediaControls"
|
WlrLayershell.namespace: "quickshell:mediaControls"
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: !ConfigOptions.bar.bottom
|
top: !Config.options.bar.bottom
|
||||||
bottom: ConfigOptions.bar.bottom
|
bottom: Config.options.bar.bottom
|
||||||
left: true
|
left: true
|
||||||
}
|
}
|
||||||
mask: Region {
|
mask: Region {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Scope {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: osdTimeout
|
id: osdTimeout
|
||||||
interval: ConfigOptions.osd.timeout
|
interval: Config.options.osd.timeout
|
||||||
repeat: false
|
repeat: false
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
@@ -66,8 +66,8 @@ Scope {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: !ConfigOptions.bar.bottom
|
top: !Config.options.bar.bottom
|
||||||
bottom: ConfigOptions.bar.bottom
|
bottom: Config.options.bar.bottom
|
||||||
}
|
}
|
||||||
mask: Region {
|
mask: Region {
|
||||||
item: osdValuesWrapper
|
item: osdValuesWrapper
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Scope {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: osdTimeout
|
id: osdTimeout
|
||||||
interval: ConfigOptions.osd.timeout
|
interval: Config.options.osd.timeout
|
||||||
repeat: false
|
repeat: false
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
@@ -78,8 +78,8 @@ Scope {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: !ConfigOptions.bar.bottom
|
top: !Config.options.bar.bottom
|
||||||
bottom: ConfigOptions.bar.bottom
|
bottom: Config.options.bar.bottom
|
||||||
}
|
}
|
||||||
mask: Region {
|
mask: Region {
|
||||||
item: osdValuesWrapper
|
item: osdValuesWrapper
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import Quickshell.Hyprland
|
|||||||
|
|
||||||
Scope { // Scope
|
Scope { // Scope
|
||||||
id: root
|
id: root
|
||||||
property bool pinned: ConfigOptions?.osk.pinnedOnStartup ?? false
|
property bool pinned: Config.options?.osk.pinnedOnStartup ?? false
|
||||||
|
|
||||||
component OskControlButton: GroupButton { // Pin button
|
component OskControlButton: GroupButton { // Pin button
|
||||||
baseWidth: 40
|
baseWidth: 40
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import Quickshell.Hyprland
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property var activeLayoutName: ConfigOptions?.osk.layout ?? Layouts.defaultLayout
|
property var activeLayoutName: Config.options?.osk.layout ?? Layouts.defaultLayout
|
||||||
property var layouts: Layouts.byName
|
property var layouts: Layouts.byName
|
||||||
property var currentLayout: layouts[activeLayoutName]
|
property var currentLayout: layouts[activeLayoutName]
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ Scope {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: delayedGrabTimer
|
id: delayedGrabTimer
|
||||||
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay
|
interval: Config.options.hacks.arbitraryRaceConditionDelay
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (!grab.canBeActive) return
|
if (!grab.canBeActive) return
|
||||||
@@ -205,7 +205,7 @@ Scope {
|
|||||||
if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) {
|
if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) {
|
||||||
overviewScope.dontAutoCancelSearch = true;
|
overviewScope.dontAutoCancelSearch = true;
|
||||||
panelWindow.setSearchingText(
|
panelWindow.setSearchingText(
|
||||||
ConfigOptions.search.prefix.clipboard
|
Config.options.search.prefix.clipboard
|
||||||
);
|
);
|
||||||
GlobalStates.overviewOpen = true;
|
GlobalStates.overviewOpen = true;
|
||||||
return
|
return
|
||||||
@@ -228,7 +228,7 @@ Scope {
|
|||||||
if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) {
|
if (panelWindow.modelData.name == Hyprland.focusedMonitor.name) {
|
||||||
overviewScope.dontAutoCancelSearch = true;
|
overviewScope.dontAutoCancelSearch = true;
|
||||||
panelWindow.setSearchingText(
|
panelWindow.setSearchingText(
|
||||||
ConfigOptions.search.prefix.emojis
|
Config.options.search.prefix.emojis
|
||||||
);
|
);
|
||||||
GlobalStates.overviewOpen = true;
|
GlobalStates.overviewOpen = true;
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ Item {
|
|||||||
required property var panelWindow
|
required property var panelWindow
|
||||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen)
|
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen)
|
||||||
readonly property var toplevels: ToplevelManager.toplevels
|
readonly property var toplevels: ToplevelManager.toplevels
|
||||||
readonly property int workspacesShown: ConfigOptions.overview.rows * ConfigOptions.overview.columns
|
readonly property int workspacesShown: Config.options.overview.rows * Config.options.overview.columns
|
||||||
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / workspacesShown)
|
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / workspacesShown)
|
||||||
property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor.id)
|
property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor.id)
|
||||||
property var windows: HyprlandData.windowList
|
property var windows: HyprlandData.windowList
|
||||||
property var windowByAddress: HyprlandData.windowByAddress
|
property var windowByAddress: HyprlandData.windowByAddress
|
||||||
property var windowAddresses: HyprlandData.addresses
|
property var windowAddresses: HyprlandData.addresses
|
||||||
property var monitorData: HyprlandData.monitors.find(m => m.id === root.monitor.id)
|
property var monitorData: HyprlandData.monitors.find(m => m.id === root.monitor.id)
|
||||||
property real scale: ConfigOptions.overview.scale
|
property real scale: Config.options.overview.scale
|
||||||
property color activeBorderColor: Appearance.colors.colSecondary
|
property color activeBorderColor: Appearance.colors.colSecondary
|
||||||
|
|
||||||
property real workspaceImplicitWidth: (monitorData?.transform % 2 === 1) ?
|
property real workspaceImplicitWidth: (monitorData?.transform % 2 === 1) ?
|
||||||
@@ -71,18 +71,18 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: workspaceSpacing
|
spacing: workspaceSpacing
|
||||||
Repeater {
|
Repeater {
|
||||||
model: ConfigOptions.overview.rows
|
model: Config.options.overview.rows
|
||||||
delegate: RowLayout {
|
delegate: RowLayout {
|
||||||
id: row
|
id: row
|
||||||
property int rowIndex: index
|
property int rowIndex: index
|
||||||
spacing: workspaceSpacing
|
spacing: workspaceSpacing
|
||||||
|
|
||||||
Repeater { // Workspace repeater
|
Repeater { // Workspace repeater
|
||||||
model: ConfigOptions.overview.columns
|
model: Config.options.overview.columns
|
||||||
Rectangle { // Workspace
|
Rectangle { // Workspace
|
||||||
id: workspace
|
id: workspace
|
||||||
property int colIndex: index
|
property int colIndex: index
|
||||||
property int workspaceValue: root.workspaceGroup * workspacesShown + rowIndex * ConfigOptions.overview.columns + colIndex + 1
|
property int workspaceValue: root.workspaceGroup * workspacesShown + rowIndex * Config.options.overview.columns + colIndex + 1
|
||||||
property color defaultWorkspaceColor: Appearance.colors.colLayer1 // TODO: reconsider this color for a cleaner look
|
property color defaultWorkspaceColor: Appearance.colors.colLayer1 // TODO: reconsider this color for a cleaner look
|
||||||
property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1)
|
property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1)
|
||||||
property color hoveredBorderColor: Appearance.colors.colLayer2Hover
|
property color hoveredBorderColor: Appearance.colors.colLayer2Hover
|
||||||
@@ -171,14 +171,14 @@ Item {
|
|||||||
property bool atInitPosition: (initX == x && initY == y)
|
property bool atInitPosition: (initX == x && initY == y)
|
||||||
restrictToWorkspace: Drag.active || atInitPosition
|
restrictToWorkspace: Drag.active || atInitPosition
|
||||||
|
|
||||||
property int workspaceColIndex: (windowData?.workspace.id - 1) % ConfigOptions.overview.columns
|
property int workspaceColIndex: (windowData?.workspace.id - 1) % Config.options.overview.columns
|
||||||
property int workspaceRowIndex: Math.floor((windowData?.workspace.id - 1) % root.workspacesShown / ConfigOptions.overview.columns)
|
property int workspaceRowIndex: Math.floor((windowData?.workspace.id - 1) % root.workspacesShown / Config.options.overview.columns)
|
||||||
xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex - (monitor?.x * root.scale)
|
xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex - (monitor?.x * root.scale)
|
||||||
yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex - (monitor?.y * root.scale)
|
yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex - (monitor?.y * root.scale)
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: updateWindowPosition
|
id: updateWindowPosition
|
||||||
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay
|
interval: Config.options.hacks.arbitraryRaceConditionDelay
|
||||||
repeat: false
|
repeat: false
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
@@ -245,8 +245,8 @@ Item {
|
|||||||
Rectangle { // Focused workspace indicator
|
Rectangle { // Focused workspace indicator
|
||||||
id: focusedWorkspaceIndicator
|
id: focusedWorkspaceIndicator
|
||||||
property int activeWorkspaceInGroup: monitor.activeWorkspace?.id - (root.workspaceGroup * root.workspacesShown)
|
property int activeWorkspaceInGroup: monitor.activeWorkspace?.id - (root.workspaceGroup * root.workspacesShown)
|
||||||
property int activeWorkspaceRowIndex: Math.floor((activeWorkspaceInGroup - 1) / ConfigOptions.overview.columns)
|
property int activeWorkspaceRowIndex: Math.floor((activeWorkspaceInGroup - 1) / Config.options.overview.columns)
|
||||||
property int activeWorkspaceColIndex: (activeWorkspaceInGroup - 1) % ConfigOptions.overview.columns
|
property int activeWorkspaceColIndex: (activeWorkspaceInGroup - 1) % Config.options.overview.columns
|
||||||
x: (root.workspaceImplicitWidth + workspaceSpacing) * activeWorkspaceColIndex
|
x: (root.workspaceImplicitWidth + workspaceSpacing) * activeWorkspaceColIndex
|
||||||
y: (root.workspaceImplicitHeight + workspaceSpacing) * activeWorkspaceRowIndex
|
y: (root.workspaceImplicitHeight + workspaceSpacing) * activeWorkspaceRowIndex
|
||||||
z: root.windowZ
|
z: root.windowZ
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Item { // Wrapper
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: nonAppResultsTimer
|
id: nonAppResultsTimer
|
||||||
interval: ConfigOptions.search.nonAppResultDelay
|
interval: Config.options.search.nonAppResultDelay
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
mathProcess.calculateExpression(root.searchingText);
|
mathProcess.calculateExpression(root.searchingText);
|
||||||
}
|
}
|
||||||
@@ -203,7 +203,7 @@ Item { // Wrapper
|
|||||||
Layout.leftMargin: 15
|
Layout.leftMargin: 15
|
||||||
iconSize: Appearance.font.pixelSize.huge
|
iconSize: Appearance.font.pixelSize.huge
|
||||||
color: Appearance.m3colors.m3onSurface
|
color: Appearance.m3colors.m3onSurface
|
||||||
text: root.searchingText.startsWith(ConfigOptions.search.prefix.clipboard) ? 'content_paste_search' : 'search'
|
text: root.searchingText.startsWith(Config.options.search.prefix.clipboard) ? 'content_paste_search' : 'search'
|
||||||
}
|
}
|
||||||
TextField { // Search box
|
TextField { // Search box
|
||||||
id: searchInput
|
id: searchInput
|
||||||
@@ -294,8 +294,8 @@ Item { // Wrapper
|
|||||||
if(root.searchingText == "") return [];
|
if(root.searchingText == "") return [];
|
||||||
|
|
||||||
///////////// Special cases ///////////////
|
///////////// Special cases ///////////////
|
||||||
if (root.searchingText.startsWith(ConfigOptions.search.prefix.clipboard)) { // Clipboard
|
if (root.searchingText.startsWith(Config.options.search.prefix.clipboard)) { // Clipboard
|
||||||
const searchString = root.searchingText.slice(ConfigOptions.search.prefix.clipboard.length);
|
const searchString = root.searchingText.slice(Config.options.search.prefix.clipboard.length);
|
||||||
return Cliphist.fuzzyQuery(searchString).map(entry => {
|
return Cliphist.fuzzyQuery(searchString).map(entry => {
|
||||||
return {
|
return {
|
||||||
cliphistRawString: entry,
|
cliphistRawString: entry,
|
||||||
@@ -310,8 +310,8 @@ Item { // Wrapper
|
|||||||
};
|
};
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
}
|
}
|
||||||
if (root.searchingText.startsWith(ConfigOptions.search.prefix.emojis)) { // Clipboard
|
if (root.searchingText.startsWith(Config.options.search.prefix.emojis)) { // Clipboard
|
||||||
const searchString = root.searchingText.slice(ConfigOptions.search.prefix.emojis.length);
|
const searchString = root.searchingText.slice(Config.options.search.prefix.emojis.length);
|
||||||
return Emojis.fuzzyQuery(searchString).map(entry => {
|
return Emojis.fuzzyQuery(searchString).map(entry => {
|
||||||
return {
|
return {
|
||||||
cliphistRawString: entry,
|
cliphistRawString: entry,
|
||||||
@@ -346,12 +346,12 @@ Item { // Wrapper
|
|||||||
fontType: "monospace",
|
fontType: "monospace",
|
||||||
materialSymbol: 'terminal',
|
materialSymbol: 'terminal',
|
||||||
execute: () => {
|
execute: () => {
|
||||||
executor.executeCommand(searchingText.startsWith('sudo') ? `${ConfigOptions.apps.terminal} fish -C '${root.searchingText.replace("file://", "")}'` : root.searchingText.replace("file://", ""));
|
executor.executeCommand(searchingText.startsWith('sudo') ? `${Config.options.apps.terminal} fish -C '${root.searchingText.replace("file://", "")}'` : root.searchingText.replace("file://", ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const launcherActionObjects = root.searchActions
|
const launcherActionObjects = root.searchActions
|
||||||
.map(action => {
|
.map(action => {
|
||||||
const actionString = `${ConfigOptions.search.prefix.action}${action.action}`;
|
const actionString = `${Config.options.search.prefix.action}${action.action}`;
|
||||||
if (actionString.startsWith(root.searchingText) || root.searchingText.startsWith(actionString)) {
|
if (actionString.startsWith(root.searchingText) || root.searchingText.startsWith(actionString)) {
|
||||||
return {
|
return {
|
||||||
name: root.searchingText.startsWith(actionString) ? root.searchingText : actionString,
|
name: root.searchingText.startsWith(actionString) ? root.searchingText : actionString,
|
||||||
@@ -399,8 +399,8 @@ Item { // Wrapper
|
|||||||
type: Translation.tr("Search the web"),
|
type: Translation.tr("Search the web"),
|
||||||
materialSymbol: 'travel_explore',
|
materialSymbol: 'travel_explore',
|
||||||
execute: () => {
|
execute: () => {
|
||||||
let url = ConfigOptions.search.engineBaseUrl + root.searchingText
|
let url = Config.options.search.engineBaseUrl + root.searchingText
|
||||||
for (let site of ConfigOptions.search.excludedSites) {
|
for (let site of Config.options.search.excludedSites) {
|
||||||
url += ` -site:${site}`;
|
url += ` -site:${site}`;
|
||||||
}
|
}
|
||||||
Qt.openUrlExternally(url);
|
Qt.openUrlExternally(url);
|
||||||
@@ -416,8 +416,8 @@ Item { // Wrapper
|
|||||||
anchors.left: parent?.left
|
anchors.left: parent?.left
|
||||||
anchors.right: parent?.right
|
anchors.right: parent?.right
|
||||||
entry: modelData
|
entry: modelData
|
||||||
query: root.searchingText.startsWith(ConfigOptions.search.prefix.clipboard) ?
|
query: root.searchingText.startsWith(Config.options.search.prefix.clipboard) ?
|
||||||
root.searchingText.slice(ConfigOptions.search.prefix.clipboard.length) :
|
root.searchingText.slice(Config.options.search.prefix.clipboard.length) :
|
||||||
root.searchingText;
|
root.searchingText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ Scope {
|
|||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
visible: (ConfigOptions.appearance.fakeScreenRounding === 1
|
visible: (Config.options.appearance.fakeScreenRounding === 1
|
||||||
|| (ConfigOptions.appearance.fakeScreenRounding === 2
|
|| (Config.options.appearance.fakeScreenRounding === 2
|
||||||
&& !activeWindow?.fullscreen))
|
&& !activeWindow?.fullscreen))
|
||||||
|
|
||||||
property var modelData
|
property var modelData
|
||||||
@@ -56,28 +56,28 @@ Scope {
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
size: Appearance.rounding.screenRounding
|
size: Appearance.rounding.screenRounding
|
||||||
corner: cornerEnum.topLeft
|
corner: RoundCorner.CornerEnum.TopLeft
|
||||||
}
|
}
|
||||||
RoundCorner {
|
RoundCorner {
|
||||||
id: topRightCorner
|
id: topRightCorner
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
size: Appearance.rounding.screenRounding
|
size: Appearance.rounding.screenRounding
|
||||||
corner: cornerEnum.topRight
|
corner: RoundCorner.CornerEnum.TopRight
|
||||||
}
|
}
|
||||||
RoundCorner {
|
RoundCorner {
|
||||||
id: bottomLeftCorner
|
id: bottomLeftCorner
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
size: Appearance.rounding.screenRounding
|
size: Appearance.rounding.screenRounding
|
||||||
corner: cornerEnum.bottomLeft
|
corner: RoundCorner.CornerEnum.BottomLeft
|
||||||
}
|
}
|
||||||
RoundCorner {
|
RoundCorner {
|
||||||
id: bottomRightCorner
|
id: bottomRightCorner
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
size: Appearance.rounding.screenRounding
|
size: Appearance.rounding.screenRounding
|
||||||
corner: cornerEnum.bottomRight
|
corner: RoundCorner.CornerEnum.BottomRight
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ Scope {
|
|||||||
id: sessionTaskManager
|
id: sessionTaskManager
|
||||||
buttonIcon: "browse_activity"
|
buttonIcon: "browse_activity"
|
||||||
buttonText: Translation.tr("Task Manager")
|
buttonText: Translation.tr("Task Manager")
|
||||||
onClicked: { Quickshell.execDetached(["bash", "-c", `${ConfigOptions.apps.taskManager}`]); sessionRoot.hide() }
|
onClicked: { Quickshell.execDetached(["bash", "-c", `${Config.options.apps.taskManager}`]); sessionRoot.hide() }
|
||||||
onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText }
|
onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText }
|
||||||
KeyNavigation.left: sessionLogout
|
KeyNavigation.left: sessionLogout
|
||||||
KeyNavigation.down: sessionFirmwareReboot
|
KeyNavigation.down: sessionFirmwareReboot
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ ContentPage {
|
|||||||
text: "Weeb"
|
text: "Weeb"
|
||||||
}
|
}
|
||||||
ConfigSelectionArray {
|
ConfigSelectionArray {
|
||||||
currentValue: ConfigOptions.policies.weeb
|
currentValue: Config.options.policies.weeb
|
||||||
configOptionName: "policies.weeb"
|
configOptionName: "policies.weeb"
|
||||||
onSelected: (newValue) => {
|
onSelected: (newValue) => {
|
||||||
ConfigLoader.setConfigValueAndSave("policies.weeb", newValue);
|
Config.options.policies.weeb = newValue;
|
||||||
}
|
}
|
||||||
options: [
|
options: [
|
||||||
{ displayName: "No", value: 0 },
|
{ displayName: "No", value: 0 },
|
||||||
@@ -34,10 +34,10 @@ ContentPage {
|
|||||||
text: "AI"
|
text: "AI"
|
||||||
}
|
}
|
||||||
ConfigSelectionArray {
|
ConfigSelectionArray {
|
||||||
currentValue: ConfigOptions.policies.ai
|
currentValue: Config.options.policies.ai
|
||||||
configOptionName: "policies.ai"
|
configOptionName: "policies.ai"
|
||||||
onSelected: (newValue) => {
|
onSelected: (newValue) => {
|
||||||
ConfigLoader.setConfigValueAndSave("policies.ai", newValue);
|
Config.options.policies.ai = newValue;
|
||||||
}
|
}
|
||||||
options: [
|
options: [
|
||||||
{ displayName: "No", value: 0 },
|
{ displayName: "No", value: 0 },
|
||||||
@@ -52,22 +52,35 @@ ContentPage {
|
|||||||
ContentSection {
|
ContentSection {
|
||||||
title: "Bar"
|
title: "Bar"
|
||||||
|
|
||||||
|
ConfigSelectionArray {
|
||||||
|
currentValue: Config.options.bar.cornerStyle
|
||||||
|
configOptionName: "bar.cornerStyle"
|
||||||
|
onSelected: (newValue) => {
|
||||||
|
Config.options.bar.cornerStyle = newValue;
|
||||||
|
}
|
||||||
|
options: [
|
||||||
|
{ displayName: "Hug", value: 0 },
|
||||||
|
{ displayName: "Float", value: 1 },
|
||||||
|
{ displayName: "Plain rectangle", value: 2 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
ContentSubsection {
|
ContentSubsection {
|
||||||
title: "Appearance"
|
title: "Appearance"
|
||||||
ConfigRow {
|
ConfigRow {
|
||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: 'Borderless'
|
text: 'Borderless'
|
||||||
checked: ConfigOptions.bar.borderless
|
checked: Config.options.bar.borderless
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.borderless", checked);
|
Config.options.bar.borderless = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: 'Show background'
|
text: 'Show background'
|
||||||
checked: ConfigOptions.bar.showBackground
|
checked: Config.options.bar.showBackground
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.showBackground", checked);
|
Config.options.bar.showBackground = checked;
|
||||||
}
|
}
|
||||||
StyledToolTip {
|
StyledToolTip {
|
||||||
content: "Note: turning off can hurt readability"
|
content: "Note: turning off can hurt readability"
|
||||||
@@ -82,16 +95,16 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Screen snip"
|
text: "Screen snip"
|
||||||
checked: ConfigOptions.bar.utilButtons.showScreenSnip
|
checked: Config.options.bar.utilButtons.showScreenSnip
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showScreenSnip", checked);
|
Config.options.bar.utilButtons.showScreenSnip = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Color picker"
|
text: "Color picker"
|
||||||
checked: ConfigOptions.bar.utilButtons.showColorPicker
|
checked: Config.options.bar.utilButtons.showColorPicker
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showColorPicker", checked);
|
Config.options.bar.utilButtons.showColorPicker = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,16 +112,16 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Mic toggle"
|
text: "Mic toggle"
|
||||||
checked: ConfigOptions.bar.utilButtons.showMicToggle
|
checked: Config.options.bar.utilButtons.showMicToggle
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showMicToggle", checked);
|
Config.options.bar.utilButtons.showMicToggle = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Keyboard toggle"
|
text: "Keyboard toggle"
|
||||||
checked: ConfigOptions.bar.utilButtons.showKeyboardToggle
|
checked: Config.options.bar.utilButtons.showKeyboardToggle
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showKeyboardToggle", checked);
|
Config.options.bar.utilButtons.showKeyboardToggle = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,9 +129,9 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Dark/Light toggle"
|
text: "Dark/Light toggle"
|
||||||
checked: ConfigOptions.bar.utilButtons.showDarkModeToggle
|
checked: Config.options.bar.utilButtons.showDarkModeToggle
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showDarkModeToggle", checked);
|
Config.options.bar.utilButtons.showDarkModeToggle = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
@@ -136,37 +149,37 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: 'Show app icons'
|
text: 'Show app icons'
|
||||||
checked: ConfigOptions.bar.workspaces.showAppIcons
|
checked: Config.options.bar.workspaces.showAppIcons
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.workspaces.showAppIcons", checked);
|
Config.options.bar.workspaces.showAppIcons = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: 'Always show numbers'
|
text: 'Always show numbers'
|
||||||
checked: ConfigOptions.bar.workspaces.alwaysShowNumbers
|
checked: Config.options.bar.workspaces.alwaysShowNumbers
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.workspaces.alwaysShowNumbers", checked);
|
Config.options.bar.workspaces.alwaysShowNumbers = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Workspaces shown"
|
text: "Workspaces shown"
|
||||||
value: ConfigOptions.bar.workspaces.shown
|
value: Config.options.bar.workspaces.shown
|
||||||
from: 1
|
from: 1
|
||||||
to: 30
|
to: 30
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.workspaces.shown", value);
|
Config.options.bar.workspaces.shown = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Number show delay when pressing Super (ms)"
|
text: "Number show delay when pressing Super (ms)"
|
||||||
value: ConfigOptions.bar.workspaces.showNumberDelay
|
value: Config.options.bar.workspaces.showNumberDelay
|
||||||
from: 0
|
from: 0
|
||||||
to: 1000
|
to: 1000
|
||||||
stepSize: 50
|
stepSize: 50
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("bar.workspaces.showNumberDelay", value);
|
Config.options.bar.workspaces.showNumberDelay = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,22 +192,22 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Low warning"
|
text: "Low warning"
|
||||||
value: ConfigOptions.battery.low
|
value: Config.options.battery.low
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 5
|
stepSize: 5
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.low", value);
|
Config.options.battery.low = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Critical warning"
|
text: "Critical warning"
|
||||||
value: ConfigOptions.battery.critical
|
value: Config.options.battery.critical
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 5
|
stepSize: 5
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.critical", value);
|
Config.options.battery.critical = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,9 +215,9 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Automatic suspend"
|
text: "Automatic suspend"
|
||||||
checked: ConfigOptions.battery.automaticSuspend
|
checked: Config.options.battery.automaticSuspend
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.automaticSuspend", checked);
|
Config.options.battery.automaticSuspend = checked;
|
||||||
}
|
}
|
||||||
StyledToolTip {
|
StyledToolTip {
|
||||||
content: "Automatically suspends the system when battery is low"
|
content: "Automatically suspends the system when battery is low"
|
||||||
@@ -212,12 +225,12 @@ ContentPage {
|
|||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Suspend at"
|
text: "Suspend at"
|
||||||
value: ConfigOptions.battery.suspend
|
value: Config.options.battery.suspend
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 5
|
stepSize: 5
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.suspend", value);
|
Config.options.battery.suspend = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,34 +240,34 @@ ContentPage {
|
|||||||
title: "Overview"
|
title: "Overview"
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Scale (%)"
|
text: "Scale (%)"
|
||||||
value: ConfigOptions.overview.scale * 100
|
value: Config.options.overview.scale * 100
|
||||||
from: 1
|
from: 1
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("overview.scale", value / 100);
|
Config.options.overview.scale = value / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigRow {
|
ConfigRow {
|
||||||
uniform: true
|
uniform: true
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Rows"
|
text: "Rows"
|
||||||
value: ConfigOptions.overview.rows
|
value: Config.options.overview.rows
|
||||||
from: 1
|
from: 1
|
||||||
to: 20
|
to: 20
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("overview.rows", value);
|
Config.options.overview.rows = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Columns"
|
text: "Columns"
|
||||||
value: ConfigOptions.overview.columns
|
value: Config.options.overview.columns
|
||||||
from: 1
|
from: 1
|
||||||
to: 20
|
to: 20
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("overview.columns", value);
|
Config.options.overview.columns = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ ContentPage {
|
|||||||
|
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Earbang protection"
|
text: "Earbang protection"
|
||||||
checked: ConfigOptions.audio.protection.enable
|
checked: Config.options.audio.protection.enable
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("audio.protection.enable", checked);
|
Config.options.audio.protection.enable = checked;
|
||||||
}
|
}
|
||||||
StyledToolTip {
|
StyledToolTip {
|
||||||
content: "Prevents abrupt increments and restricts volume limit"
|
content: "Prevents abrupt increments and restricts volume limit"
|
||||||
@@ -25,22 +25,22 @@ ContentPage {
|
|||||||
// uniform: true
|
// uniform: true
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Max allowed increase"
|
text: "Max allowed increase"
|
||||||
value: ConfigOptions.audio.protection.maxAllowedIncrease
|
value: Config.options.audio.protection.maxAllowedIncrease
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 2
|
stepSize: 2
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("audio.protection.maxAllowedIncrease", value);
|
Config.options.audio.protection.maxAllowedIncrease = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Volume limit"
|
text: "Volume limit"
|
||||||
value: ConfigOptions.audio.protection.maxAllowed
|
value: Config.options.audio.protection.maxAllowed
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 2
|
stepSize: 2
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("audio.protection.maxAllowed", value);
|
Config.options.audio.protection.maxAllowed = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,10 +50,12 @@ ContentPage {
|
|||||||
MaterialTextField {
|
MaterialTextField {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
placeholderText: "System prompt"
|
placeholderText: "System prompt"
|
||||||
text: ConfigOptions.ai.systemPrompt
|
text: Config.options.ai.systemPrompt
|
||||||
wrapMode: TextEdit.Wrap
|
wrapMode: TextEdit.Wrap
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("ai.systemPrompt", text);
|
Qt.callLater(() => {
|
||||||
|
Config.options.ai.systemPrompt = text;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,22 +67,22 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Low warning"
|
text: "Low warning"
|
||||||
value: ConfigOptions.battery.low
|
value: Config.options.battery.low
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 5
|
stepSize: 5
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.low", value);
|
Config.options.battery.low = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Critical warning"
|
text: "Critical warning"
|
||||||
value: ConfigOptions.battery.critical
|
value: Config.options.battery.critical
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 5
|
stepSize: 5
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.critical", value);
|
Config.options.battery.critical = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,9 +90,9 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Automatic suspend"
|
text: "Automatic suspend"
|
||||||
checked: ConfigOptions.battery.automaticSuspend
|
checked: Config.options.battery.automaticSuspend
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.automaticSuspend", checked);
|
Config.options.battery.automaticSuspend = checked;
|
||||||
}
|
}
|
||||||
StyledToolTip {
|
StyledToolTip {
|
||||||
content: "Automatically suspends the system when battery is low"
|
content: "Automatically suspends the system when battery is low"
|
||||||
@@ -98,12 +100,12 @@ ContentPage {
|
|||||||
}
|
}
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Suspend at"
|
text: "Suspend at"
|
||||||
value: ConfigOptions.battery.suspend
|
value: Config.options.battery.suspend
|
||||||
from: 0
|
from: 0
|
||||||
to: 100
|
to: 100
|
||||||
stepSize: 5
|
stepSize: 5
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("battery.suspend", value);
|
Config.options.battery.suspend = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,10 +116,10 @@ ContentPage {
|
|||||||
MaterialTextField {
|
MaterialTextField {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
placeholderText: "User agent (for services that require it)"
|
placeholderText: "User agent (for services that require it)"
|
||||||
text: ConfigOptions.networking.userAgent
|
text: Config.options.networking.userAgent
|
||||||
wrapMode: TextEdit.Wrap
|
wrapMode: TextEdit.Wrap
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("networking.userAgent", text);
|
Config.options.networking.userAgent = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,12 +128,12 @@ ContentPage {
|
|||||||
title: "Resources"
|
title: "Resources"
|
||||||
ConfigSpinBox {
|
ConfigSpinBox {
|
||||||
text: "Polling interval (ms)"
|
text: "Polling interval (ms)"
|
||||||
value: ConfigOptions.resources.updateInterval
|
value: Config.options.resources.updateInterval
|
||||||
from: 100
|
from: 100
|
||||||
to: 10000
|
to: 10000
|
||||||
stepSize: 100
|
stepSize: 100
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("resources.updateInterval", value);
|
Config.options.resources.updateInterval = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ ContentPage {
|
|||||||
ContentSubsection {
|
ContentSubsection {
|
||||||
title: "Material palette"
|
title: "Material palette"
|
||||||
ConfigSelectionArray {
|
ConfigSelectionArray {
|
||||||
currentValue: ConfigOptions.appearance.palette.type
|
currentValue: Config.options.appearance.palette.type
|
||||||
configOptionName: "appearance.palette.type"
|
configOptionName: "appearance.palette.type"
|
||||||
onSelected: (newValue) => {
|
onSelected: (newValue) => {
|
||||||
ConfigLoader.setConfigValueAndSave("appearance.palette.type", newValue);
|
Config.options.appearance.palette.type = newValue;
|
||||||
}
|
}
|
||||||
options: [
|
options: [
|
||||||
{"value": "auto", "displayName": "Auto"},
|
{"value": "auto", "displayName": "Auto"},
|
||||||
@@ -141,9 +141,9 @@ ContentPage {
|
|||||||
ConfigRow {
|
ConfigRow {
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Enable"
|
text: "Enable"
|
||||||
checked: ConfigOptions.appearance.transparency
|
checked: Config.options.appearance.transparency
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("appearance.transparency", checked);
|
Config.options.appearance.transparency = checked;
|
||||||
}
|
}
|
||||||
StyledToolTip {
|
StyledToolTip {
|
||||||
content: "Might look ass. Unsupported."
|
content: "Might look ass. Unsupported."
|
||||||
@@ -157,7 +157,7 @@ ContentPage {
|
|||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: fakeScreenRoundingButtonGroup
|
id: fakeScreenRoundingButtonGroup
|
||||||
property int selectedPolicy: ConfigOptions.appearance.fakeScreenRounding
|
property int selectedPolicy: Config.options.appearance.fakeScreenRounding
|
||||||
spacing: 2
|
spacing: 2
|
||||||
SelectionGroupButton {
|
SelectionGroupButton {
|
||||||
property int value: 0
|
property int value: 0
|
||||||
@@ -165,7 +165,7 @@ ContentPage {
|
|||||||
buttonText: "No"
|
buttonText: "No"
|
||||||
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
|
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
|
Config.options.appearance.fakeScreenRounding = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SelectionGroupButton {
|
SelectionGroupButton {
|
||||||
@@ -173,7 +173,7 @@ ContentPage {
|
|||||||
buttonText: "Yes"
|
buttonText: "Yes"
|
||||||
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
|
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
|
Config.options.appearance.fakeScreenRounding = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SelectionGroupButton {
|
SelectionGroupButton {
|
||||||
@@ -182,7 +182,7 @@ ContentPage {
|
|||||||
buttonText: "When not fullscreen"
|
buttonText: "When not fullscreen"
|
||||||
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
|
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
|
Config.options.appearance.fakeScreenRounding = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,16 +195,16 @@ ContentPage {
|
|||||||
uniform: true
|
uniform: true
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Title bar"
|
text: "Title bar"
|
||||||
checked: ConfigOptions.windows.showTitlebar
|
checked: Config.options.windows.showTitlebar
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("windows.showTitlebar", checked);
|
Config.options.windows.showTitlebar = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSwitch {
|
ConfigSwitch {
|
||||||
text: "Center title"
|
text: "Center title"
|
||||||
checked: ConfigOptions.windows.centerTitle
|
checked: Config.options.windows.centerTitle
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
ConfigLoader.setConfigValueAndSave("windows.centerTitle", checked);
|
Config.options.windows.centerTitle = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,10 +50,14 @@ Item {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "clear",
|
name: "prompt",
|
||||||
description: Translation.tr("Clear chat history"),
|
description: Translation.tr("Set the system prompt for the model."),
|
||||||
execute: () => {
|
execute: (args) => {
|
||||||
Ai.clearMessages();
|
if (args.length === 0 || args[0] === "get") {
|
||||||
|
Ai.printPrompt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ai.loadPrompt(args.join(" ").trim());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -67,6 +71,13 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "clear",
|
||||||
|
description: qsTr("Clear chat history"),
|
||||||
|
execute: () => {
|
||||||
|
Ai.clearMessages();
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "temp",
|
name: "temp",
|
||||||
description: Translation.tr("Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5."),
|
description: Translation.tr("Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5."),
|
||||||
@@ -250,33 +261,9 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // Suggestion description
|
DescriptionBox {
|
||||||
visible: descriptionText.text.length > 0
|
text: root.suggestionList[suggestions.selectedIndex]?.description ?? ""
|
||||||
Layout.fillWidth: true
|
showArrows: root.suggestionList.length > 1
|
||||||
implicitHeight: descriptionBackground.implicitHeight
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: descriptionBackground
|
|
||||||
color: Appearance.colors.colTooltip
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
implicitHeight: descriptionText.implicitHeight + 5 * 2
|
|
||||||
radius: Appearance.rounding.verysmall
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: descriptionText
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.leftMargin: 10
|
|
||||||
anchors.rightMargin: 10
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
font.pixelSize: Appearance.font.pixelSize.smaller
|
|
||||||
color: Appearance.colors.colOnTooltip
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
text: root.suggestionList[suggestions.selectedIndex]?.description ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlowButtonGroup { // Suggestions
|
FlowButtonGroup { // Suggestions
|
||||||
@@ -294,7 +281,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
|||||||
}
|
}
|
||||||
delegate: ApiCommandButton {
|
delegate: ApiCommandButton {
|
||||||
id: commandButton
|
id: commandButton
|
||||||
colBackground: suggestions.selectedIndex === index ? Appearance.colors.colLayer2Hover : Appearance.colors.colLayer2
|
colBackground: suggestions.selectedIndex === index ? Appearance.colors.colSecondaryContainerHover : Appearance.colors.colSecondaryContainer
|
||||||
bounce: false
|
bounce: false
|
||||||
contentItem: StyledText {
|
contentItem: StyledText {
|
||||||
font.pixelSize: Appearance.font.pixelSize.small
|
font.pixelSize: Appearance.font.pixelSize.small
|
||||||
@@ -393,6 +380,24 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
|||||||
description: `${Ai.models[model.target].description}`,
|
description: `${Ai.models[model.target].description}`,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else if(messageInputField.text.startsWith(`${root.commandPrefix}prompt`)) {
|
||||||
|
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? ""
|
||||||
|
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.promptFiles.map(file => {
|
||||||
|
return {
|
||||||
|
name: Fuzzy.prepare(file),
|
||||||
|
obj: file,
|
||||||
|
}
|
||||||
|
}), {
|
||||||
|
all: true,
|
||||||
|
key: "name"
|
||||||
|
})
|
||||||
|
root.suggestionList = promptFileResults.map(file => {
|
||||||
|
return {
|
||||||
|
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "prompt ") : ""}${file.target}`,
|
||||||
|
displayName: `${FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target))}`,
|
||||||
|
description: `Load prompt from ${file.target}`,
|
||||||
|
}
|
||||||
|
})
|
||||||
} else if(messageInputField.text.startsWith(root.commandPrefix)) {
|
} else if(messageInputField.text.startsWith(root.commandPrefix)) {
|
||||||
root.suggestionQuery = messageInputField.text
|
root.suggestionQuery = messageInputField.text
|
||||||
root.suggestionList = root.allCommands.filter(cmd => cmd.name.startsWith(messageInputField.text.substring(1))).map(cmd => {
|
root.suggestionList = root.allCommands.filter(cmd => cmd.name.startsWith(messageInputField.text.substring(1))).map(cmd => {
|
||||||
|
|||||||
@@ -6,15 +6,11 @@ import "root:/modules/common/functions/fuzzysort.js" as Fuzzy
|
|||||||
import "root:/modules/common/functions/string_utils.js" as StringUtils
|
import "root:/modules/common/functions/string_utils.js" as StringUtils
|
||||||
import "root:/modules/common/functions/file_utils.js" as FileUtils
|
import "root:/modules/common/functions/file_utils.js" as FileUtils
|
||||||
import "./anime/"
|
import "./anime/"
|
||||||
import "root:/services/"
|
|
||||||
import Qt.labs.platform
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -66,14 +62,14 @@ Item {
|
|||||||
name: "safe",
|
name: "safe",
|
||||||
description: Translation.tr("Disable NSFW content"),
|
description: Translation.tr("Disable NSFW content"),
|
||||||
execute: () => {
|
execute: () => {
|
||||||
PersistentStateManager.setState("booru.allowNsfw", false);
|
Persistent.states.booru.allowNsfw = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "lewd",
|
name: "lewd",
|
||||||
description: Translation.tr("Allow NSFW content"),
|
description: Translation.tr("Allow NSFW content"),
|
||||||
execute: () => {
|
execute: () => {
|
||||||
PersistentStateManager.setState("booru.allowNsfw", true);
|
Persistent.states.booru.allowNsfw = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -107,7 +103,7 @@ Item {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Booru.makeRequest(tagList, PersistentStates.booru.allowNsfw, ConfigOptions.sidebar.booru.limit, pageIndex);
|
Booru.makeRequest(tagList, Persistent.states.booru.allowNsfw, Config.options.sidebar.booru.limit, pageIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,33 +248,9 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { // Tag suggestion description
|
DescriptionBox { // Tag suggestion description
|
||||||
visible: tagDescriptionText.text.length > 0
|
text: root.suggestionList[tagSuggestions.selectedIndex]?.description ?? ""
|
||||||
Layout.fillWidth: true
|
showArrows: root.suggestionList.length > 1
|
||||||
implicitHeight: tagDescriptionBackground.implicitHeight
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: tagDescriptionBackground
|
|
||||||
color: Appearance.colors.colTooltip
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
implicitHeight: tagDescriptionText.implicitHeight + 5 * 2
|
|
||||||
radius: Appearance.rounding.verysmall
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: tagDescriptionText
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.leftMargin: 10
|
|
||||||
anchors.rightMargin: 10
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
font.pixelSize: Appearance.font.pixelSize.smaller
|
|
||||||
color: Appearance.colors.colOnTooltip
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
text: root.suggestionList[tagSuggestions.selectedIndex]?.description ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlowButtonGroup { // Tag suggestions
|
FlowButtonGroup { // Tag suggestions
|
||||||
@@ -296,7 +268,7 @@ Item {
|
|||||||
}
|
}
|
||||||
delegate: ApiCommandButton {
|
delegate: ApiCommandButton {
|
||||||
id: tagButton
|
id: tagButton
|
||||||
colBackground: tagSuggestions.selectedIndex === index ? Appearance.colors.colLayer2Hover : Appearance.colors.colLayer2
|
colBackground: tagSuggestions.selectedIndex === index ? Appearance.colors.colSecondaryContainerHover : Appearance.colors.colSecondaryContainer
|
||||||
bounce: false
|
bounce: false
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -304,7 +276,7 @@ Item {
|
|||||||
StyledText {
|
StyledText {
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
font.pixelSize: Appearance.font.pixelSize.small
|
font.pixelSize: Appearance.font.pixelSize.small
|
||||||
color: Appearance.m3colors.m3onSurface
|
color: Appearance.colors.colOnSecondaryContainer
|
||||||
horizontalAlignment: Text.AlignRight
|
horizontalAlignment: Text.AlignRight
|
||||||
text: modelData.displayName ?? modelData.name
|
text: modelData.displayName ?? modelData.name
|
||||||
}
|
}
|
||||||
@@ -312,7 +284,7 @@ Item {
|
|||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
visible: modelData.count !== undefined
|
visible: modelData.count !== undefined
|
||||||
font.pixelSize: Appearance.font.pixelSize.smaller
|
font.pixelSize: Appearance.font.pixelSize.smaller
|
||||||
color: Appearance.m3colors.m3outline
|
color: Appearance.colors.colOnSecondaryContainer
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
text: modelData.count ?? ""
|
text: modelData.count ?? ""
|
||||||
}
|
}
|
||||||
@@ -594,10 +566,10 @@ Item {
|
|||||||
enabled: Booru.currentProvider !== "zerochan"
|
enabled: Booru.currentProvider !== "zerochan"
|
||||||
scale: 0.6
|
scale: 0.6
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
checked: (PersistentStates.booru.allowNsfw && Booru.currentProvider !== "zerochan")
|
checked: (Persistent.states.booru.allowNsfw && Booru.currentProvider !== "zerochan")
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (!nsfwSwitch.enabled) return;
|
if (!nsfwSwitch.enabled) return;
|
||||||
PersistentStateManager.setState("booru.allowNsfw", checked)
|
Persistent.states.booru.allowNsfw = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,7 +583,6 @@ Item {
|
|||||||
id: commandRepeater
|
id: commandRepeater
|
||||||
model: commandButtonsRow.commandsShown
|
model: commandButtonsRow.commandsShown
|
||||||
delegate: ApiCommandButton {
|
delegate: ApiCommandButton {
|
||||||
id: tagButton
|
|
||||||
property string commandRepresentation: `${root.commandPrefix}${modelData.name}`
|
property string commandRepresentation: `${root.commandPrefix}${modelData.name}`
|
||||||
buttonText: commandRepresentation
|
buttonText: commandRepresentation
|
||||||
colBackground: Appearance.colors.colLayer2
|
colBackground: Appearance.colors.colLayer2
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ GroupButton {
|
|||||||
baseWidth: contentItem.implicitWidth + horizontalPadding * 2
|
baseWidth: contentItem.implicitWidth + horizontalPadding * 2
|
||||||
clickedWidth: baseWidth + 20
|
clickedWidth: baseWidth + 20
|
||||||
baseHeight: contentItem.implicitHeight + verticalPadding * 2
|
baseHeight: contentItem.implicitHeight + verticalPadding * 2
|
||||||
buttonRadius: down ? Appearance.rounding.small : baseHeight / 2
|
buttonRadius: down ? Appearance.rounding.verysmall : Appearance.rounding.small
|
||||||
|
|
||||||
colBackground: Appearance.colors.colLayer2
|
colBackground: Appearance.colors.colLayer2
|
||||||
colBackgroundHover: Appearance.colors.colLayer2Hover
|
colBackgroundHover: Appearance.colors.colLayer2Hover
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import "root:/services"
|
||||||
|
import "root:/modules/common"
|
||||||
|
import "root:/modules/common/widgets"
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Item { // Tag suggestion description
|
||||||
|
id: root
|
||||||
|
property alias text: tagDescriptionText.text
|
||||||
|
property bool showArrows: true
|
||||||
|
property bool showTab: true
|
||||||
|
|
||||||
|
visible: tagDescriptionText.text.length > 0
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: tagDescriptionBackground.implicitHeight
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: tagDescriptionBackground
|
||||||
|
color: Appearance.colors.colLayer2
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Appearance.rounding.verysmall
|
||||||
|
implicitHeight: descriptionRow.implicitHeight + 5 * 2
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: descriptionRow
|
||||||
|
spacing: 4
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
leftMargin: 10
|
||||||
|
rightMargin: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: tagDescriptionText
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.smaller
|
||||||
|
color: Appearance.colors.colOnLayer2
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
KeyboardKey {
|
||||||
|
visible: root.showArrows
|
||||||
|
key: "↑"
|
||||||
|
}
|
||||||
|
KeyboardKey {
|
||||||
|
visible: root.showArrows
|
||||||
|
key: "↓"
|
||||||
|
}
|
||||||
|
StyledText {
|
||||||
|
visible: root.showArrows && root.showTab
|
||||||
|
text: qsTr("or")
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.smaller
|
||||||
|
}
|
||||||
|
KeyboardKey {
|
||||||
|
id: tagDescriptionKey
|
||||||
|
visible: root.showTab
|
||||||
|
key: "Tab"
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,9 +19,9 @@ Item {
|
|||||||
required property var scopeRoot
|
required property var scopeRoot
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
property var tabButtonList: [
|
property var tabButtonList: [
|
||||||
...(ConfigOptions.policies.ai !== 0 ? [{"icon": "neurology", "name": Translation.tr("Intelligence")}] : []),
|
...(Config.options.policies.ai !== 0 ? [{"icon": "neurology", "name": qsTr("Intelligence")}] : []),
|
||||||
{"icon": "translate", "name": Translation.tr("Translator")},
|
{"icon": "translate", "name": qsTr("Translator")},
|
||||||
...(ConfigOptions.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": Translation.tr("Anime")}] : [])
|
...(Config.options.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": qsTr("Anime")}] : [])
|
||||||
]
|
]
|
||||||
property int selectedTab: 0
|
property int selectedTab: 0
|
||||||
|
|
||||||
@@ -89,9 +89,9 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentChildren: [
|
contentChildren: [
|
||||||
...(ConfigOptions.policies.ai !== 0 ? [aiChat.createObject()] : []),
|
...(Config.options.policies.ai !== 0 ? [aiChat.createObject()] : []),
|
||||||
translator.createObject(),
|
translator.createObject(),
|
||||||
...(ConfigOptions.policies.weeb === 0 ? [] : [anime.createObject()])
|
...(Config.options.policies.weeb === 0 ? [] : [anime.createObject()])
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ Item {
|
|||||||
property string translatedText: ""
|
property string translatedText: ""
|
||||||
property list<string> languages: []
|
property list<string> languages: []
|
||||||
// Options
|
// Options
|
||||||
property string targetLanguage: ConfigOptions.language.translator.targetLanguage
|
property string targetLanguage: Config.options.language.translator.targetLanguage
|
||||||
property string sourceLanguage: ConfigOptions.language.translator.sourceLanguage
|
property string sourceLanguage: Config.options.language.translator.sourceLanguage
|
||||||
property string hostLanguage: targetLanguage
|
property string hostLanguage: targetLanguage
|
||||||
|
|
||||||
property bool showLanguageSelector: false
|
property bool showLanguageSelector: false
|
||||||
@@ -43,7 +43,7 @@ Item {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: translateTimer
|
id: translateTimer
|
||||||
interval: ConfigOptions.sidebar.translator.delay
|
interval: Config.options.sidebar.translator.delay
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: () => {
|
onTriggered: () => {
|
||||||
if (root.inputField.text.trim().length > 0) {
|
if (root.inputField.text.trim().length > 0) {
|
||||||
@@ -155,8 +155,8 @@ Item {
|
|||||||
color: searchButton.enabled ? Appearance.colors.colOnLayer1 : Appearance.colors.colSubtext
|
color: searchButton.enabled ? Appearance.colors.colOnLayer1 : Appearance.colors.colSubtext
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
let url = ConfigOptions.search.engineBaseUrl + outputCanvas.displayedText;
|
let url = Config.options.search.engineBaseUrl + outputCanvas.displayedText;
|
||||||
for (let site of ConfigOptions.search.excludedSites) {
|
for (let site of Config.options.search.excludedSites) {
|
||||||
url += ` -site:${site}`;
|
url += ` -site:${site}`;
|
||||||
}
|
}
|
||||||
Qt.openUrlExternally(url);
|
Qt.openUrlExternally(url);
|
||||||
@@ -235,10 +235,10 @@ Item {
|
|||||||
|
|
||||||
if (root.languageSelectorTarget) {
|
if (root.languageSelectorTarget) {
|
||||||
root.targetLanguage = result;
|
root.targetLanguage = result;
|
||||||
ConfigLoader.setConfigValueAndSave("language.translator.targetLanguage", result); // Save to config
|
Config.options.language.translator.targetLanguage = result; // Save to config
|
||||||
} else {
|
} else {
|
||||||
root.sourceLanguage = result;
|
root.sourceLanguage = result;
|
||||||
ConfigLoader.setConfigValueAndSave("language.translator.sourceLanguage", result); // Save to config
|
Config.options.language.translator.sourceLanguage = result; // Save to config
|
||||||
}
|
}
|
||||||
|
|
||||||
translateTimer.restart(); // Restart translation after language change
|
translateTimer.restart(); // Restart translation after language change
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Rectangle {
|
|||||||
clip: true
|
clip: true
|
||||||
implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : bottomWidgetGroupRow.implicitHeight
|
implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : bottomWidgetGroupRow.implicitHeight
|
||||||
property int selectedTab: 0
|
property int selectedTab: 0
|
||||||
property bool collapsed: PersistentStates.sidebar.bottomGroup.collapsed
|
property bool collapsed: Persistent.states.sidebar.bottomGroup.collapsed
|
||||||
property var tabs: [
|
property var tabs: [
|
||||||
{"type": "calendar", "name": "Calendar", "icon": "calendar_month", "widget": calendarWidget},
|
{"type": "calendar", "name": "Calendar", "icon": "calendar_month", "widget": calendarWidget},
|
||||||
{"type": "todo", "name": "To Do", "icon": "done_outline", "widget": todoWidget}
|
{"type": "todo", "name": "To Do", "icon": "done_outline", "widget": todoWidget}
|
||||||
@@ -30,7 +30,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setCollapsed(state) {
|
function setCollapsed(state) {
|
||||||
PersistentStateManager.setState("sidebar.bottomGroup.collapsed", state)
|
Persistent.states.sidebar.bottomGroup.collapsed = state
|
||||||
if (collapsed) {
|
if (collapsed) {
|
||||||
bottomWidgetGroupRow.opacity = 0
|
bottomWidgetGroupRow.opacity = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ QuickToggleButton {
|
|||||||
toggleBluetooth.running = true
|
toggleBluetooth.running = true
|
||||||
}
|
}
|
||||||
altAction: () => {
|
altAction: () => {
|
||||||
Quickshell.execDetached(["bash", "-c", `${ConfigOptions.apps.bluetooth}`])
|
Quickshell.execDetached(["bash", "-c", `${Config.options.apps.bluetooth}`])
|
||||||
Hyprland.dispatch("global quickshell:sidebarRightClose")
|
Hyprland.dispatch("global quickshell:sidebarRightClose")
|
||||||
}
|
}
|
||||||
Process {
|
Process {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ QuickToggleButton {
|
|||||||
running: true
|
running: true
|
||||||
command: ["bash", "-c", `test "$(hyprctl getoption animations:enabled -j | jq ".int")" -ne 0`]
|
command: ["bash", "-c", `test "$(hyprctl getoption animations:enabled -j | jq ".int")" -ne 0`]
|
||||||
onExited: (exitCode, exitStatus) => {
|
onExited: (exitCode, exitStatus) => {
|
||||||
console.log("Game mode toggle exited with code:", exitCode, "and status:", exitStatus)
|
|
||||||
root.toggled = exitCode !== 0 // Inverted because enabled = nonzero exit
|
root.toggled = exitCode !== 0 // Inverted because enabled = nonzero exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ QuickToggleButton {
|
|||||||
toggleNetwork.running = true
|
toggleNetwork.running = true
|
||||||
}
|
}
|
||||||
altAction: () => {
|
altAction: () => {
|
||||||
Quickshell.execDetached(["bash", "-c", `${Network.ethernet ? ConfigOptions.apps.networkEthernet : ConfigOptions.apps.network}`])
|
Quickshell.execDetached(["bash", "-c", `${Network.ethernet ? Config.options.apps.networkEthernet : Config.options.apps.network}`])
|
||||||
Hyprland.dispatch("global quickshell:sidebarRightClose")
|
Hyprland.dispatch("global quickshell:sidebarRightClose")
|
||||||
}
|
}
|
||||||
Process {
|
Process {
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ Item {
|
|||||||
property bool deviceSelectorInput
|
property bool deviceSelectorInput
|
||||||
property int dialogMargins: 16
|
property int dialogMargins: 16
|
||||||
property PwNode selectedDevice
|
property PwNode selectedDevice
|
||||||
|
readonly property list<PwNode> appPwNodes: Pipewire.nodes.values.filter((node) => {
|
||||||
|
// return node.type == "21" // Alternative, not as clean
|
||||||
|
return node.isSink && node.isStream
|
||||||
|
})
|
||||||
|
|
||||||
function showDeviceSelectorDialog(input: bool) {
|
function showDeviceSelectorDialog(input: bool) {
|
||||||
root.selectedDevice = null
|
root.selectedDevice = null
|
||||||
@@ -60,21 +64,13 @@ Item {
|
|||||||
anchors.margins: 10
|
anchors.margins: 10
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
// Get a list of nodes that output to the default sink
|
|
||||||
PwNodeLinkTracker {
|
|
||||||
id: linkTracker
|
|
||||||
node: Pipewire.defaultAudioSink
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: linkTracker.linkGroups
|
model: root.appPwNodes
|
||||||
|
|
||||||
VolumeMixerEntry {
|
VolumeMixerEntry {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
// Get links to the default sinnk
|
required property var modelData
|
||||||
required property PwLinkGroup modelData
|
node: modelData
|
||||||
// Consider sources that output to the default sink
|
|
||||||
node: modelData.source
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +81,7 @@ Item {
|
|||||||
anchors.fill: flickable
|
anchors.fill: flickable
|
||||||
|
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
opacity: (linkTracker.linkGroups.length === 0) ? 1 : 0
|
opacity: (root.appPwNodes.length === 0) ? 1 : 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
|
|||||||
@@ -0,0 +1,534 @@
|
|||||||
|
//@ pragma UseQApplication
|
||||||
|
//@ pragma Env QS_NO_RELOAD_POPUP=1
|
||||||
|
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
|
||||||
|
|
||||||
|
// Adjust this to make it smaller or larger
|
||||||
|
//@ pragma Env QT_SCALE_FACTOR=1
|
||||||
|
|
||||||
|
pragma ComponentBehavior: "Bound"
|
||||||
|
import "./modules/common/"
|
||||||
|
import "./modules/common/widgets"
|
||||||
|
import "./modules/common/functions/string_utils.js" as StringUtils
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "./services/"
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
id: root
|
||||||
|
property string screenshotDir: "/tmp/quickshell/media/screenshot"
|
||||||
|
property color overlayColor: "#77111111"
|
||||||
|
property color genericContentColor: Qt.alpha(root.overlayColor, 0.9)
|
||||||
|
property color genericContentForeground: "#ddffffff"
|
||||||
|
property color selectionBorderColor: "#ddf1f1f1"
|
||||||
|
property color selectionFillColor: "#33ffffff"
|
||||||
|
property color windowBorderColor: "#dda0c0da"
|
||||||
|
property color windowFillColor: "#22a0c0da"
|
||||||
|
property color imageBorderColor: "#ddf1d1ff"
|
||||||
|
property color imageFillColor: "#33f1d1ff"
|
||||||
|
property color onBorderColor: "#ff000000"
|
||||||
|
property real standardRounding: 4
|
||||||
|
readonly property var windows: HyprlandData.windowList
|
||||||
|
readonly property var layers: HyprlandData.layers
|
||||||
|
readonly property real falsePositivePreventionRatio: 0.5
|
||||||
|
|
||||||
|
// Force initialization of some singletons
|
||||||
|
Component.onCompleted: {
|
||||||
|
MaterialThemeLoader.reapplyTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
component TargetRegion: Rectangle {
|
||||||
|
id: regionRect
|
||||||
|
property bool targeted: false
|
||||||
|
property color borderColor
|
||||||
|
property color fillColor: "transparent"
|
||||||
|
property string text: ""
|
||||||
|
property real textPadding: 10
|
||||||
|
z: 2
|
||||||
|
color: fillColor
|
||||||
|
border.color: borderColor
|
||||||
|
border.width: targeted ? 3 : 1
|
||||||
|
radius: root.standardRounding
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: regionLabelBackground
|
||||||
|
property real verticalPadding: 5
|
||||||
|
property real horizontalPadding: 10
|
||||||
|
radius: 10
|
||||||
|
color: root.genericContentColor
|
||||||
|
border.width: 1
|
||||||
|
border.color: Appearance.m3colors.m3outlineVariant
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
topMargin: regionRect.textPadding
|
||||||
|
leftMargin: regionRect.textPadding
|
||||||
|
}
|
||||||
|
implicitWidth: regionText.implicitWidth + horizontalPadding * 2
|
||||||
|
implicitHeight: regionText.implicitHeight + verticalPadding * 2
|
||||||
|
StyledText {
|
||||||
|
id: regionText
|
||||||
|
text: regionRect.text
|
||||||
|
color: root.genericContentForeground
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: panelWindow
|
||||||
|
required property var modelData
|
||||||
|
readonly property HyprlandMonitor hyprlandMonitor: Hyprland.monitorFor(modelData)
|
||||||
|
readonly property real monitorScale: hyprlandMonitor.scale
|
||||||
|
readonly property real monitorOffsetX: hyprlandMonitor.x
|
||||||
|
readonly property real monitorOffsetY: hyprlandMonitor.y
|
||||||
|
property int activeWorkspaceId: hyprlandMonitor.activeWorkspace?.id ?? 0
|
||||||
|
property string screenshotPath: `${root.screenshotDir}/image-${modelData.name}`
|
||||||
|
property real dragStartX: 0
|
||||||
|
property real dragStartY: 0
|
||||||
|
property real draggingX: 0
|
||||||
|
property real draggingY: 0
|
||||||
|
property real dragDiffX: 0
|
||||||
|
property real dragDiffY: 0
|
||||||
|
property bool draggedAway: (dragDiffX !== 0 || dragDiffY !== 0)
|
||||||
|
property bool dragging: false
|
||||||
|
property var mouseButton: null
|
||||||
|
property var imageRegions: []
|
||||||
|
readonly property list<var> windowRegions: filterWindowRegionsByLayers(
|
||||||
|
root.windows.filter(w => w.workspace.id === panelWindow.activeWorkspaceId),
|
||||||
|
panelWindow.layerRegions
|
||||||
|
).map(window => {
|
||||||
|
return {
|
||||||
|
at: [window.at[0] - panelWindow.monitorOffsetX, window.at[1] - panelWindow.monitorOffsetY],
|
||||||
|
size: [window.size[0], window.size[1]],
|
||||||
|
class: window.class,
|
||||||
|
title: window.title,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
readonly property list<var> layerRegions: {
|
||||||
|
const layersOfThisMonitor = root.layers[panelWindow.hyprlandMonitor.name]
|
||||||
|
const topLayers = layersOfThisMonitor.levels["2"]
|
||||||
|
const nonBarTopLayers = topLayers
|
||||||
|
.filter(layer => !(layer.namespace.includes(":bar")))
|
||||||
|
.map(layer => {
|
||||||
|
return {
|
||||||
|
at: [layer.x, layer.y],
|
||||||
|
size: [layer.w, layer.h],
|
||||||
|
namespace: layer.namespace,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const offsetAdjustedLayers = nonBarTopLayers.map(layer => {
|
||||||
|
return {
|
||||||
|
at: [layer.at[0] - panelWindow.monitorOffsetX, layer.at[1] - panelWindow.monitorOffsetY],
|
||||||
|
size: layer.size,
|
||||||
|
namespace: layer.namespace,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return offsetAdjustedLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
property real targetedRegionX: -1
|
||||||
|
property real targetedRegionY: -1
|
||||||
|
property real targetedRegionWidth: 0
|
||||||
|
property real targetedRegionHeight: 0
|
||||||
|
|
||||||
|
function intersectionOverUnion(regionA, regionB) {
|
||||||
|
// region: { at: [x, y], size: [w, h] }
|
||||||
|
const ax1 = regionA.at[0], ay1 = regionA.at[1];
|
||||||
|
const ax2 = ax1 + regionA.size[0], ay2 = ay1 + regionA.size[1];
|
||||||
|
const bx1 = regionB.at[0], by1 = regionB.at[1];
|
||||||
|
const bx2 = bx1 + regionB.size[0], by2 = by1 + regionB.size[1];
|
||||||
|
|
||||||
|
const interX1 = Math.max(ax1, bx1);
|
||||||
|
const interY1 = Math.max(ay1, by1);
|
||||||
|
const interX2 = Math.min(ax2, bx2);
|
||||||
|
const interY2 = Math.min(ay2, by2);
|
||||||
|
|
||||||
|
const interArea = Math.max(0, interX2 - interX1) * Math.max(0, interY2 - interY1);
|
||||||
|
const areaA = (ax2 - ax1) * (ay2 - ay1);
|
||||||
|
const areaB = (bx2 - bx1) * (by2 - by1);
|
||||||
|
const unionArea = areaA + areaB - interArea;
|
||||||
|
|
||||||
|
return unionArea > 0 ? interArea / unionArea : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterOverlappingImageRegions(regions) {
|
||||||
|
let keep = [];
|
||||||
|
let removed = new Set();
|
||||||
|
for (let i = 0; i < regions.length; ++i) {
|
||||||
|
if (removed.has(i)) continue;
|
||||||
|
let regionA = regions[i];
|
||||||
|
for (let j = i + 1; j < regions.length; ++j) {
|
||||||
|
if (removed.has(j)) continue;
|
||||||
|
let regionB = regions[j];
|
||||||
|
if (intersectionOverUnion(regionA, regionB) > 0) {
|
||||||
|
// Compare areas
|
||||||
|
let areaA = regionA.size[0] * regionA.size[1];
|
||||||
|
let areaB = regionB.size[0] * regionB.size[1];
|
||||||
|
if (areaA <= areaB) {
|
||||||
|
removed.add(j);
|
||||||
|
} else {
|
||||||
|
removed.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < regions.length; ++i) {
|
||||||
|
if (!removed.has(i)) keep.push(regions[i]);
|
||||||
|
}
|
||||||
|
return keep;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterWindowRegionsByLayers(windowRegions, layerRegions) {
|
||||||
|
return windowRegions.filter(windowRegion => {
|
||||||
|
for (let i = 0; i < layerRegions.length; ++i) {
|
||||||
|
if (intersectionOverUnion(windowRegion, layerRegions[i]) > 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterImageRegions(regions, windowRegions, threshold = 0.1) {
|
||||||
|
// Remove image regions that overlap too much with any window region
|
||||||
|
let filtered = regions.filter(region => {
|
||||||
|
for (let i = 0; i < windowRegions.length; ++i) {
|
||||||
|
if (intersectionOverUnion(region, windowRegions[i]) > threshold)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
// Remove overlapping image regions, keep only the smaller one
|
||||||
|
return filterOverlappingImageRegions(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTargetedRegion(x, y) {
|
||||||
|
// Image regions
|
||||||
|
const clickedRegion = panelWindow.imageRegions.find(region => {
|
||||||
|
return region.at[0] <= x && x <= region.at[0] + region.size[0] && region.at[1] <= y && y <= region.at[1] + region.size[1];
|
||||||
|
});
|
||||||
|
if (clickedRegion) {
|
||||||
|
panelWindow.targetedRegionX = clickedRegion.at[0];
|
||||||
|
panelWindow.targetedRegionY = clickedRegion.at[1];
|
||||||
|
panelWindow.targetedRegionWidth = clickedRegion.size[0];
|
||||||
|
panelWindow.targetedRegionHeight = clickedRegion.size[1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layer regions
|
||||||
|
const clickedLayer = panelWindow.layerRegions.find(region => {
|
||||||
|
return region.at[0] <= x && x <= region.at[0] + region.size[0] && region.at[1] <= y && y <= region.at[1] + region.size[1];
|
||||||
|
});
|
||||||
|
if (clickedLayer) {
|
||||||
|
panelWindow.targetedRegionX = clickedLayer.at[0];
|
||||||
|
panelWindow.targetedRegionY = clickedLayer.at[1];
|
||||||
|
panelWindow.targetedRegionWidth = clickedLayer.size[0];
|
||||||
|
panelWindow.targetedRegionHeight = clickedLayer.size[1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window regions
|
||||||
|
const clickedWindow = panelWindow.windowRegions.find(region => {
|
||||||
|
return region.at[0] <= x && x <= region.at[0] + region.size[0] && region.at[1] <= y && y <= region.at[1] + region.size[1];
|
||||||
|
});
|
||||||
|
if (clickedWindow) {
|
||||||
|
panelWindow.targetedRegionX = clickedWindow.at[0];
|
||||||
|
panelWindow.targetedRegionY = clickedWindow.at[1];
|
||||||
|
panelWindow.targetedRegionWidth = clickedWindow.size[0];
|
||||||
|
panelWindow.targetedRegionHeight = clickedWindow.size[1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
panelWindow.targetedRegionX = -1;
|
||||||
|
panelWindow.targetedRegionY = -1;
|
||||||
|
panelWindow.targetedRegionWidth = 0;
|
||||||
|
panelWindow.targetedRegionHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
property real regionWidth: Math.abs(draggingX - dragStartX)
|
||||||
|
property real regionHeight: Math.abs(draggingY - dragStartY)
|
||||||
|
property real regionX: Math.min(dragStartX, draggingX)
|
||||||
|
property real regionY: Math.min(dragStartY, draggingY)
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
screen: modelData
|
||||||
|
WlrLayershell.namespace: "quickshell:screenshot"
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
anchors {
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
top: true
|
||||||
|
bottom: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: screenshotProcess
|
||||||
|
running: true
|
||||||
|
command: ["bash", "-c", `mkdir -p '${StringUtils.shellSingleQuoteEscape(root.screenshotDir)}' && grim -o '${StringUtils.shellSingleQuoteEscape(modelData.name)}' '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}'`]
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
panelWindow.visible = true;
|
||||||
|
imageDetectionProcess.running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: imageDetectionProcess
|
||||||
|
command: ["bash", "-c", `${Directories.scriptPath}/images/find_regions.py `
|
||||||
|
+ `--hyprctl `
|
||||||
|
+ `--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}' `
|
||||||
|
+ `--max-width ${Math.round(panelWindow.screen.width * root.falsePositivePreventionRatio)} `
|
||||||
|
+ `--max-height ${Math.round(panelWindow.screen.height * root.falsePositivePreventionRatio)} `]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
id: imageDimensionCollector
|
||||||
|
onStreamFinished: {
|
||||||
|
imageRegions = filterImageRegions(
|
||||||
|
JSON.parse(imageDimensionCollector.text),
|
||||||
|
panelWindow.windowRegions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: snipProc
|
||||||
|
function snip() {
|
||||||
|
if (panelWindow.regionWidth <= 0 || panelWindow.regionHeight <= 0) {
|
||||||
|
console.warn("Invalid region size, skipping snip.");
|
||||||
|
Qt.quit();
|
||||||
|
}
|
||||||
|
snipProc.startDetached();
|
||||||
|
Qt.quit();
|
||||||
|
}
|
||||||
|
command: ["bash", "-c",
|
||||||
|
`magick ${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)} `
|
||||||
|
+ `-crop ${panelWindow.regionWidth * panelWindow.monitorScale}x${panelWindow.regionHeight * panelWindow.monitorScale}+${panelWindow.regionX * panelWindow.monitorScale}+${panelWindow.regionY * panelWindow.monitorScale} - `
|
||||||
|
+ `| ${panelWindow.mouseButton === Qt.LeftButton ? "wl-copy" : "swappy -f -"}`]
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreencopyView {
|
||||||
|
anchors.fill: parent
|
||||||
|
live: false
|
||||||
|
captureSource: modelData
|
||||||
|
|
||||||
|
focus: panelWindow.visible
|
||||||
|
Keys.onPressed: (event) => { // Esc to close
|
||||||
|
if (event.key === Qt.Key_Escape) {
|
||||||
|
Qt.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.CrossCursor
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
// Controls
|
||||||
|
onPressed: mouse => {
|
||||||
|
panelWindow.dragStartX = mouse.x;
|
||||||
|
panelWindow.dragStartY = mouse.y;
|
||||||
|
panelWindow.draggingX = mouse.x;
|
||||||
|
panelWindow.draggingY = mouse.y;
|
||||||
|
panelWindow.dragging = true;
|
||||||
|
panelWindow.mouseButton = mouse.button;
|
||||||
|
}
|
||||||
|
onReleased: mouse => {
|
||||||
|
// Detect if it was a click
|
||||||
|
|
||||||
|
// Image regions
|
||||||
|
if (panelWindow.draggingX === panelWindow.dragStartX && panelWindow.draggingY === panelWindow.dragStartY) {
|
||||||
|
if (panelWindow.targetedRegionX >= 0 && panelWindow.targetedRegionY >= 0) {
|
||||||
|
panelWindow.regionX = panelWindow.targetedRegionX;
|
||||||
|
panelWindow.regionY = panelWindow.targetedRegionY;
|
||||||
|
panelWindow.regionWidth = panelWindow.targetedRegionWidth;
|
||||||
|
panelWindow.regionHeight = panelWindow.targetedRegionHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snipProc.snip();
|
||||||
|
}
|
||||||
|
onPositionChanged: mouse => {
|
||||||
|
if (panelWindow.dragging) {
|
||||||
|
panelWindow.draggingX = mouse.x;
|
||||||
|
panelWindow.draggingY = mouse.y;
|
||||||
|
panelWindow.dragDiffX = mouse.x - panelWindow.dragStartX;
|
||||||
|
panelWindow.dragDiffY = mouse.y - panelWindow.dragStartY;
|
||||||
|
}
|
||||||
|
panelWindow.updateTargetedRegion(mouse.x, mouse.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overlay to darken screen
|
||||||
|
Rectangle { // Base
|
||||||
|
id: overlayRect
|
||||||
|
z: 0
|
||||||
|
anchors.fill: parent
|
||||||
|
color: root.overlayColor
|
||||||
|
layer.enabled: true
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
// TODO: Make this mask the base instead of just overlaying a border
|
||||||
|
z: 1
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
top: parent.top
|
||||||
|
leftMargin: panelWindow.regionX
|
||||||
|
topMargin: panelWindow.regionY
|
||||||
|
}
|
||||||
|
width: panelWindow.regionWidth
|
||||||
|
height: panelWindow.regionHeight
|
||||||
|
color: "transparent"
|
||||||
|
border.color: root.selectionBorderColor
|
||||||
|
border.width: 2
|
||||||
|
radius: root.standardRounding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instructions
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
topMargin: (Appearance.sizes.barHeight - implicitHeight) / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
opacity: panelWindow.dragging ? 0 : 1
|
||||||
|
visible: opacity > 0
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
color: root.genericContentColor
|
||||||
|
radius: 10
|
||||||
|
border.width: 1
|
||||||
|
border.color: Appearance.m3colors.m3outlineVariant
|
||||||
|
implicitWidth: instructionsRow.implicitWidth + 10 * 2
|
||||||
|
implicitHeight: instructionsRow.implicitHeight + 5 * 2
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: instructionsRow
|
||||||
|
anchors.centerIn: parent
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitWidth: screenshotRegionIcon.implicitWidth
|
||||||
|
MaterialSymbol {
|
||||||
|
id: screenshotRegionIcon
|
||||||
|
anchors.centerIn: parent
|
||||||
|
iconSize: Appearance.font.pixelSize.larger
|
||||||
|
text: "screenshot_region"
|
||||||
|
color: root.genericContentForeground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StyledText {
|
||||||
|
text: "Drag or click a region • LMB: Copy • RMB: Edit"
|
||||||
|
color: root.genericContentForeground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window regions
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
values: panelWindow.windowRegions
|
||||||
|
}
|
||||||
|
delegate: TargetRegion {
|
||||||
|
z: 2
|
||||||
|
required property var modelData
|
||||||
|
targeted: !panelWindow.draggedAway &&
|
||||||
|
(panelWindow.targetedRegionX === modelData.at[0]
|
||||||
|
&& panelWindow.targetedRegionY === modelData.at[1]
|
||||||
|
&& panelWindow.targetedRegionWidth === modelData.size[0]
|
||||||
|
&& panelWindow.targetedRegionHeight === modelData.size[1])
|
||||||
|
|
||||||
|
opacity: panelWindow.draggedAway ? 0 : 1
|
||||||
|
visible: opacity > 0
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
x: modelData.at[0]
|
||||||
|
y: modelData.at[1]
|
||||||
|
width: modelData.size[0]
|
||||||
|
height: modelData.size[1]
|
||||||
|
borderColor: root.windowBorderColor
|
||||||
|
fillColor: targeted ? root.windowFillColor : "transparent"
|
||||||
|
border.width: targeted ? 4 : 2
|
||||||
|
text: `${modelData.class}`
|
||||||
|
radius: Appearance.rounding.windowRounding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layer regions
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
values: panelWindow.layerRegions
|
||||||
|
}
|
||||||
|
delegate: TargetRegion {
|
||||||
|
z: 3
|
||||||
|
required property var modelData
|
||||||
|
targeted: !panelWindow.draggedAway &&
|
||||||
|
(panelWindow.targetedRegionX === modelData.at[0]
|
||||||
|
&& panelWindow.targetedRegionY === modelData.at[1]
|
||||||
|
&& panelWindow.targetedRegionWidth === modelData.size[0]
|
||||||
|
&& panelWindow.targetedRegionHeight === modelData.size[1])
|
||||||
|
|
||||||
|
opacity: panelWindow.draggedAway ? 0 : 1
|
||||||
|
visible: opacity > 0
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
x: modelData.at[0]
|
||||||
|
y: modelData.at[1]
|
||||||
|
width: modelData.size[0]
|
||||||
|
height: modelData.size[1]
|
||||||
|
borderColor: root.windowBorderColor
|
||||||
|
fillColor: targeted ? root.windowFillColor : "transparent"
|
||||||
|
border.width: targeted ? 4 : 2
|
||||||
|
text: `${modelData.namespace}`
|
||||||
|
radius: Appearance.rounding.windowRounding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image regions
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
values: panelWindow.imageRegions
|
||||||
|
}
|
||||||
|
delegate: TargetRegion {
|
||||||
|
z: 4
|
||||||
|
required property var modelData
|
||||||
|
targeted: !panelWindow.draggedAway &&
|
||||||
|
(panelWindow.targetedRegionX === modelData.at[0]
|
||||||
|
&& panelWindow.targetedRegionY === modelData.at[1]
|
||||||
|
&& panelWindow.targetedRegionWidth === modelData.size[0]
|
||||||
|
&& panelWindow.targetedRegionHeight === modelData.size[1])
|
||||||
|
|
||||||
|
opacity: panelWindow.draggedAway ? 0 : 1
|
||||||
|
visible: opacity > 0
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
x: modelData.at[0]
|
||||||
|
y: modelData.at[1]
|
||||||
|
width: modelData.size[0]
|
||||||
|
height: modelData.size[1]
|
||||||
|
borderColor: root.imageBorderColor
|
||||||
|
fillColor: targeted ? root.imageFillColor : "transparent"
|
||||||
|
border.width: targeted ? 4 : 2
|
||||||
|
text: "Content region"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -237,7 +237,7 @@ switch() {
|
|||||||
[[ -n "$mode_flag" ]] && matugen_args+=(--mode "$mode_flag") && generate_colors_material_args+=(--mode "$mode_flag")
|
[[ -n "$mode_flag" ]] && matugen_args+=(--mode "$mode_flag") && generate_colors_material_args+=(--mode "$mode_flag")
|
||||||
[[ -n "$type_flag" ]] && matugen_args+=(--type "$type_flag") && generate_colors_material_args+=(--scheme "$type_flag")
|
[[ -n "$type_flag" ]] && matugen_args+=(--type "$type_flag") && generate_colors_material_args+=(--scheme "$type_flag")
|
||||||
generate_colors_material_args+=(--termscheme "$terminalscheme" --blend_bg_fg)
|
generate_colors_material_args+=(--termscheme "$terminalscheme" --blend_bg_fg)
|
||||||
generate_colors_material_args+=(--cache "$STATE_DIR/user/color.txt")
|
generate_colors_material_args+=(--cache "$STATE_DIR/user/generated/color.txt")
|
||||||
|
|
||||||
pre_process "$mode_flag"
|
pre_process "$mode_flag"
|
||||||
|
|
||||||
|
|||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import cv2
|
||||||
|
import json
|
||||||
|
import numpy as np
|
||||||
|
import sys
|
||||||
|
|
||||||
|
DEFAULT_IMAGE_PATH = '/tmp/quickshell/media/screenshot/image'
|
||||||
|
|
||||||
|
def iou(boxA, boxB):
|
||||||
|
# Compute intersection over union for two boxes
|
||||||
|
xA = max(boxA['x'], boxB['x'])
|
||||||
|
yA = max(boxA['y'], boxB['y'])
|
||||||
|
xB = min(boxA['x'] + boxA['width'], boxB['x'] + boxB['width'])
|
||||||
|
yB = min(boxA['y'] + boxA['height'], boxB['y'] + boxB['height'])
|
||||||
|
interW = max(0, xB - xA)
|
||||||
|
interH = max(0, yB - yA)
|
||||||
|
interArea = interW * interH
|
||||||
|
boxAArea = boxA['width'] * boxA['height']
|
||||||
|
boxBArea = boxB['width'] * boxB['height']
|
||||||
|
iou = interArea / float(boxAArea + boxBArea - interArea) if (boxAArea + boxBArea - interArea) > 0 else 0
|
||||||
|
return iou
|
||||||
|
|
||||||
|
def non_max_suppression(regions, iou_threshold=0.7):
|
||||||
|
# Sort by area (largest first)
|
||||||
|
regions = sorted(regions, key=lambda r: r['width'] * r['height'], reverse=True)
|
||||||
|
keep = []
|
||||||
|
while regions:
|
||||||
|
current = regions.pop(0)
|
||||||
|
keep.append(current)
|
||||||
|
regions = [r for r in regions if iou(current, r) < iou_threshold]
|
||||||
|
return keep
|
||||||
|
|
||||||
|
def find_regions(image_path, min_width, min_height, max_width=None, max_height=None, quality=False, k=150, min_size=20, sigma=0.8, resize_factor=1.0):
|
||||||
|
image = cv2.imread(image_path)
|
||||||
|
if image is None:
|
||||||
|
print(f'Error: Could not load image {image_path}', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
orig_h, orig_w = image.shape[:2]
|
||||||
|
if resize_factor != 1.0:
|
||||||
|
image = cv2.resize(image, (int(orig_w * resize_factor), int(orig_h * resize_factor)), interpolation=cv2.INTER_AREA)
|
||||||
|
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
|
||||||
|
ss.setBaseImage(image)
|
||||||
|
if quality:
|
||||||
|
ss.switchToSelectiveSearchQuality(k, min_size, sigma)
|
||||||
|
else:
|
||||||
|
ss.switchToSelectiveSearchFast(k, min_size, sigma)
|
||||||
|
rects = ss.process()
|
||||||
|
regions = []
|
||||||
|
for (x, y, w, h) in rects:
|
||||||
|
# Scale regions back to original image size if resized
|
||||||
|
if resize_factor != 1.0:
|
||||||
|
x = int(x / resize_factor)
|
||||||
|
y = int(y / resize_factor)
|
||||||
|
w = int(w / resize_factor)
|
||||||
|
h = int(h / resize_factor)
|
||||||
|
# Filter out region that is exactly the same size as the original image
|
||||||
|
if w == orig_w and h == orig_h and x == 0 and y == 0:
|
||||||
|
continue
|
||||||
|
if w > min_width and h > min_height:
|
||||||
|
if (max_width is None or w < max_width) and (max_height is None or h < max_height):
|
||||||
|
regions.append({'x': int(x), 'y': int(y), 'width': int(w), 'height': int(h)})
|
||||||
|
# Remove duplicates/overlaps
|
||||||
|
regions = non_max_suppression(regions, iou_threshold=0.7)
|
||||||
|
return regions, cv2.imread(image_path) # Return original image for drawing
|
||||||
|
|
||||||
|
def draw_regions(image, regions, output_path):
|
||||||
|
for region in regions:
|
||||||
|
if 'x' in region:
|
||||||
|
x, y, w, h = region['x'], region['y'], region['width'], region['height']
|
||||||
|
elif 'at' in region and 'size' in region:
|
||||||
|
x, y = region['at']
|
||||||
|
w, h = region['size']
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
|
||||||
|
cv2.imwrite(output_path, image)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Find regions of interest in an image using selective search.')
|
||||||
|
parser.add_argument('-i', '--image', default=DEFAULT_IMAGE_PATH, help='Path to input image')
|
||||||
|
parser.add_argument('-do', '--debug-output', help='Path to save debug image with rectangles')
|
||||||
|
parser.add_argument('--min-width', type=int, default=200, help='Minimum width of detected region')
|
||||||
|
parser.add_argument('--min-height', type=int, default=100, help='Minimum height of detected region')
|
||||||
|
parser.add_argument('--max-width', type=int, help='Maximum width of detected region')
|
||||||
|
parser.add_argument('--max-height', type=int, help='Maximum height of detected region')
|
||||||
|
parser.add_argument('--single', action='store_true', help='Only output the most likely (largest) region')
|
||||||
|
parser.add_argument('--quality', action='store_true', help='Use quality mode for selective search (slower, less sensitive)')
|
||||||
|
parser.add_argument('--k', type=int, default=3000, help='Segmentation parameter k (default: 150)')
|
||||||
|
parser.add_argument('--min-size', type=int, default=50, help='Segmentation parameter min_size (default: 20)')
|
||||||
|
parser.add_argument('--sigma', type=float, default=0.6, help='Segmentation parameter sigma (default: 0.8)')
|
||||||
|
parser.add_argument('--resize-factor', type=float, default=0.1, help='Resize factor for input image before processing (default: 1.0, e.g. 0.5 for half size)')
|
||||||
|
parser.add_argument('--hyprctl', action='store_true', help='Mimics hyprctl\'s window output, like {"at": [x, y], "size": [w, h]}')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
regions, image = find_regions(
|
||||||
|
args.image,
|
||||||
|
min_width=args.min_width,
|
||||||
|
min_height=args.min_height,
|
||||||
|
max_width=args.max_width,
|
||||||
|
max_height=args.max_height,
|
||||||
|
quality=args.quality,
|
||||||
|
k=args.k,
|
||||||
|
min_size=args.min_size,
|
||||||
|
sigma=args.sigma,
|
||||||
|
resize_factor=args.resize_factor
|
||||||
|
)
|
||||||
|
if args.single and regions:
|
||||||
|
largest = max(regions, key=lambda r: r['width'] * r['height'])
|
||||||
|
regions = [largest]
|
||||||
|
if args.hyprctl:
|
||||||
|
regions = [{"at": [r['x'], r['y']], "size": [r['width'], r['height']]} for r in regions]
|
||||||
|
print(json.dumps(regions))
|
||||||
|
if args.debug_output:
|
||||||
|
draw_regions(image, regions, args.debug_output)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
@@ -19,14 +19,14 @@ Singleton {
|
|||||||
readonly property string interfaceRole: "interface"
|
readonly property string interfaceRole: "interface"
|
||||||
readonly property string apiKeyEnvVarName: "API_KEY"
|
readonly property string apiKeyEnvVarName: "API_KEY"
|
||||||
property Component aiMessageComponent: AiMessageData {}
|
property Component aiMessageComponent: AiMessageData {}
|
||||||
property string systemPrompt: ConfigOptions?.ai?.systemPrompt ?? ""
|
property string systemPrompt: Config.options?.ai?.systemPrompt ?? ""
|
||||||
property var messages: []
|
property var messages: []
|
||||||
property var messageIDs: []
|
property var messageIDs: []
|
||||||
property var messageByID: ({})
|
property var messageByID: ({})
|
||||||
readonly property var apiKeys: KeyringStorage.keyringData?.apiKeys ?? {}
|
readonly property var apiKeys: KeyringStorage.keyringData?.apiKeys ?? {}
|
||||||
readonly property var apiKeysLoaded: KeyringStorage.loaded
|
readonly property var apiKeysLoaded: KeyringStorage.loaded
|
||||||
property var postResponseHook
|
property var postResponseHook
|
||||||
property real temperature: PersistentStates?.ai?.temperature ?? 0.5
|
property real temperature: Persistent.states?.ai?.temperature ?? 0.5
|
||||||
|
|
||||||
function idForMessage(message) {
|
function idForMessage(message) {
|
||||||
// Generate a unique ID using timestamp and random value
|
// Generate a unique ID using timestamp and random value
|
||||||
@@ -37,6 +37,10 @@ Singleton {
|
|||||||
return modelName.replace(/:/g, "_").replace(/\./g, "_")
|
return modelName.replace(/:/g, "_").replace(/\./g, "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property list<var> defaultPrompts: []
|
||||||
|
property list<var> userPrompts: []
|
||||||
|
property list<var> promptFiles: [...defaultPrompts, ...userPrompts]
|
||||||
|
|
||||||
// Model properties:
|
// Model properties:
|
||||||
// - name: Name of the model
|
// - name: Name of the model
|
||||||
// - icon: Icon name of the model
|
// - icon: Icon name of the model
|
||||||
@@ -203,11 +207,10 @@ Singleton {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
property var modelList: Object.keys(root.models)
|
property var modelList: Object.keys(root.models)
|
||||||
property var currentModelId: PersistentStates?.ai?.model || modelList[0]
|
property var currentModelId: Persistent.states?.ai?.model || modelList[0]
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
setModel(currentModelId, false); // Do necessary setup for model
|
setModel(currentModelId, false, false); // Do necessary setup for model
|
||||||
getOllamaModels.running = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function guessModelLogo(model) {
|
function guessModelLogo(model) {
|
||||||
@@ -233,6 +236,7 @@ Singleton {
|
|||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: getOllamaModels
|
id: getOllamaModels
|
||||||
|
running: true
|
||||||
command: ["bash", "-c", `${Directories.config}/quickshell/scripts/ai/show-installed-ollama-models.sh`.replace(/file:\/\//, "")]
|
command: ["bash", "-c", `${Directories.config}/quickshell/scripts/ai/show-installed-ollama-models.sh`.replace(/file:\/\//, "")]
|
||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
onRead: data => {
|
onRead: data => {
|
||||||
@@ -261,6 +265,54 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: getDefaultPrompts
|
||||||
|
running: true
|
||||||
|
command: ["ls", "-1", Directories.defaultAiPrompts]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
if (text.length === 0) return;
|
||||||
|
root.defaultPrompts = text.split("\n")
|
||||||
|
.filter(fileName => fileName.endsWith(".md") || fileName.endsWith(".txt"))
|
||||||
|
.map(fileName => `${Directories.defaultAiPrompts}/${fileName}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: getUserPrompts
|
||||||
|
running: true
|
||||||
|
command: ["ls", "-1", Directories.userAiPrompts]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
if (text.length === 0) return;
|
||||||
|
root.userPrompts = text.split("\n")
|
||||||
|
.filter(fileName => fileName.endsWith(".md") || fileName.endsWith(".txt"))
|
||||||
|
.map(fileName => `${Directories.userAiPrompts}/${fileName}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: promptLoader
|
||||||
|
watchChanges: false;
|
||||||
|
onLoadedChanged: {
|
||||||
|
if (!promptLoader.loaded) return;
|
||||||
|
Config.options.ai.systemPrompt = promptLoader.text();
|
||||||
|
root.addMessage(StringUtils.format("Loaded the following system prompt\n\n---\n\n{0}", Config.options.ai.systemPrompt), root.interfaceRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function printPrompt() {
|
||||||
|
root.addMessage(StringUtils.format("The current system prompt is\n\n---\n\n{0}", Config.options.ai.systemPrompt), root.interfaceRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPrompt(filePath) {
|
||||||
|
promptLoader.path = "" // Unload
|
||||||
|
promptLoader.path = filePath; // Load
|
||||||
|
promptLoader.reload();
|
||||||
|
}
|
||||||
|
|
||||||
function addMessage(message, role) {
|
function addMessage(message, role) {
|
||||||
if (message.length === 0) return;
|
if (message.length === 0) return;
|
||||||
const aiMessage = aiMessageComponent.createObject(root, {
|
const aiMessage = aiMessageComponent.createObject(root, {
|
||||||
@@ -294,7 +346,7 @@ Singleton {
|
|||||||
return models[currentModelId];
|
return models[currentModelId];
|
||||||
}
|
}
|
||||||
|
|
||||||
function setModel(modelId, feedback = true) {
|
function setModel(modelId, feedback = true, setPersistentState = true) {
|
||||||
if (!modelId) modelId = ""
|
if (!modelId) modelId = ""
|
||||||
modelId = modelId.toLowerCase()
|
modelId = modelId.toLowerCase()
|
||||||
if (modelList.indexOf(modelId) !== -1) {
|
if (modelList.indexOf(modelId) !== -1) {
|
||||||
@@ -302,12 +354,12 @@ Singleton {
|
|||||||
// Fetch API keys if needed
|
// Fetch API keys if needed
|
||||||
if (model?.requires_key) KeyringStorage.fetchKeyringData();
|
if (model?.requires_key) KeyringStorage.fetchKeyringData();
|
||||||
// See if policy prevents online models
|
// See if policy prevents online models
|
||||||
if (ConfigOptions.policies.ai === 2 && !model.endpoint.includes("localhost")) {
|
if (Config.options.policies.ai === 2 && !model.endpoint.includes("localhost")) {
|
||||||
root.addMessage(StringUtils.format(StringUtils.format("Online models disallowed\n\nControlled by `policies.ai` config option"), model.name), root.interfaceRole);
|
root.addMessage(StringUtils.format(StringUtils.format("Online models disallowed\n\nControlled by `policies.ai` config option"), model.name), root.interfaceRole);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PersistentStateManager.setState("ai.model", modelId);
|
if (setPersistentState) Persistent.states.ai.model = modelId;
|
||||||
if (feedback) root.addMessage(StringUtils.format(StringUtils.format("Model set to {0}"), model.name), root.interfaceRole);
|
if (feedback) root.addMessage(StringUtils.format("Model set to {0}", model.name), root.interfaceRole);
|
||||||
if (model.requires_key) {
|
if (model.requires_key) {
|
||||||
// If key not there show advice
|
// If key not there show advice
|
||||||
if (root.apiKeysLoaded && (!root.apiKeys[model.key_id] || root.apiKeys[model.key_id].length === 0)) {
|
if (root.apiKeysLoaded && (!root.apiKeys[model.key_id] || root.apiKeys[model.key_id].length === 0)) {
|
||||||
@@ -328,7 +380,7 @@ Singleton {
|
|||||||
root.addMessage(Translation.tr("Temperature must be between 0 and 2"), Ai.interfaceRole);
|
root.addMessage(Translation.tr("Temperature must be between 0 and 2"), Ai.interfaceRole);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PersistentStateManager.setState("ai.temperature", value);
|
Persistent.states.ai.temperature = value;
|
||||||
root.temperature = value;
|
root.temperature = value;
|
||||||
root.addMessage(StringUtils.format(Translation.tr("Temperature set to {0}"), value), Ai.interfaceRole);
|
root.addMessage(StringUtils.format(Translation.tr("Temperature set to {0}"), value), Ai.interfaceRole);
|
||||||
}
|
}
|
||||||
@@ -705,7 +757,7 @@ Singleton {
|
|||||||
addFunctionOutputMessage(name, Translation.tr("Switched to search mode. Continue with the user's request."))
|
addFunctionOutputMessage(name, Translation.tr("Switched to search mode. Continue with the user's request."))
|
||||||
requester.makeRequest();
|
requester.makeRequest();
|
||||||
} else if (name === "get_shell_config") {
|
} else if (name === "get_shell_config") {
|
||||||
const configJson = ObjectUtils.toPlainObject(ConfigOptions)
|
const configJson = ObjectUtils.toPlainObject(Config.options)
|
||||||
addFunctionOutputMessage(name, JSON.stringify(configJson));
|
addFunctionOutputMessage(name, JSON.stringify(configJson));
|
||||||
requester.makeRequest();
|
requester.makeRequest();
|
||||||
} else if (name === "set_shell_config") {
|
} else if (name === "set_shell_config") {
|
||||||
@@ -715,8 +767,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
const key = args.key;
|
const key = args.key;
|
||||||
const value = args.value;
|
const value = args.value;
|
||||||
ConfigLoader.setLiveConfigValue(key, value);
|
Config.setNestedValue(key, value);
|
||||||
ConfigLoader.saveConfig();
|
|
||||||
}
|
}
|
||||||
else root.addMessage(Translation.tr("Unknown function call: {0}"), "assistant");
|
else root.addMessage(Translation.tr("Unknown function call: {0}"), "assistant");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import Quickshell.Io
|
|||||||
*/
|
*/
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
property bool sloppySearch: ConfigOptions?.search.sloppy ?? false
|
property bool sloppySearch: Config.options?.search.sloppy ?? false
|
||||||
property real scoreThreshold: 0.2
|
property real scoreThreshold: 0.2
|
||||||
property var substitutions: ({
|
property var substitutions: ({
|
||||||
"code-url-handler": "visual-studio-code",
|
"code-url-handler": "visual-studio-code",
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ Singleton {
|
|||||||
property bool lastReady: false
|
property bool lastReady: false
|
||||||
property real lastVolume: 0
|
property real lastVolume: 0
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (!ConfigOptions.audio.protection.enable) return;
|
if (!Config.options.audio.protection.enable) return;
|
||||||
if (!lastReady) {
|
if (!lastReady) {
|
||||||
lastVolume = sink.audio.volume;
|
lastVolume = sink.audio.volume;
|
||||||
lastReady = true;
|
lastReady = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newVolume = sink.audio.volume;
|
const newVolume = sink.audio.volume;
|
||||||
const maxAllowedIncrease = ConfigOptions.audio.protection.maxAllowedIncrease / 100;
|
const maxAllowedIncrease = Config.options.audio.protection.maxAllowedIncrease / 100;
|
||||||
const maxAllowed = ConfigOptions.audio.protection.maxAllowed / 100;
|
const maxAllowed = Config.options.audio.protection.maxAllowed / 100;
|
||||||
|
|
||||||
if (newVolume - lastVolume > maxAllowedIncrease) {
|
if (newVolume - lastVolume > maxAllowedIncrease) {
|
||||||
sink.audio.volume = lastVolume;
|
sink.audio.volume = lastVolume;
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ Singleton {
|
|||||||
property bool isCharging: chargeState == UPowerDeviceState.Charging
|
property bool isCharging: chargeState == UPowerDeviceState.Charging
|
||||||
property bool isPluggedIn: isCharging || chargeState == UPowerDeviceState.PendingCharge
|
property bool isPluggedIn: isCharging || chargeState == UPowerDeviceState.PendingCharge
|
||||||
property real percentage: UPower.displayDevice.percentage
|
property real percentage: UPower.displayDevice.percentage
|
||||||
readonly property bool allowAutomaticSuspend: ConfigOptions.battery.automaticSuspend
|
readonly property bool allowAutomaticSuspend: Config.options.battery.automaticSuspend
|
||||||
|
|
||||||
property bool isLow: percentage <= ConfigOptions.battery.low / 100
|
property bool isLow: percentage <= Config.options.battery.low / 100
|
||||||
property bool isCritical: percentage <= ConfigOptions.battery.critical / 100
|
property bool isCritical: percentage <= Config.options.battery.critical / 100
|
||||||
property bool isSuspending: percentage <= ConfigOptions.battery.suspend / 100
|
property bool isSuspending: percentage <= Config.options.battery.suspend / 100
|
||||||
|
|
||||||
property bool isLowAndNotCharging: isLow && !isCharging
|
property bool isLowAndNotCharging: isLow && !isCharging
|
||||||
property bool isCriticalAndNotCharging: isCritical && !isCharging
|
property bool isCriticalAndNotCharging: isCritical && !isCharging
|
||||||
@@ -29,7 +29,7 @@ Singleton {
|
|||||||
|
|
||||||
onIsCriticalAndNotChargingChanged: {
|
onIsCriticalAndNotChargingChanged: {
|
||||||
if (available && isCriticalAndNotCharging)
|
if (available && isCriticalAndNotCharging)
|
||||||
Quickshell.execDetached(["bash", "-c", `notify-send "Critically low battery" "🙏 I beg for pleas charg\nAutomatic suspend triggers at ${ConfigOptions.battery.suspend}%" -u critical -a "Shell"`]);
|
Quickshell.execDetached(["bash", "-c", `notify-send "Critically low battery" "🙏 I beg for pleas charg\nAutomatic suspend triggers at ${Config.options.battery.suspend}%" -u critical -a "Shell"`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
onIsSuspendingAndNotChargingChanged: {
|
onIsSuspendingAndNotChargingChanged: {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Singleton {
|
|||||||
property string failMessage: Translation.tr("That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number")
|
property string failMessage: Translation.tr("That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number")
|
||||||
property var responses: []
|
property var responses: []
|
||||||
property int runningRequests: 0
|
property int runningRequests: 0
|
||||||
property var defaultUserAgent: ConfigOptions?.networking?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
|
property var defaultUserAgent: Config.options?.networking?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
|
||||||
property var providerList: Object.keys(providers).filter(provider => provider !== "system" && providers[provider].api)
|
property var providerList: Object.keys(providers).filter(provider => provider !== "system" && providers[provider].api)
|
||||||
property var providers: {
|
property var providers: {
|
||||||
"system": { "name": Translation.tr("System") },
|
"system": { "name": Translation.tr("System") },
|
||||||
@@ -275,7 +275,7 @@ Singleton {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
property var currentProvider: PersistentStates.booru.provider
|
property var currentProvider: Persistent.states.booru.provider
|
||||||
|
|
||||||
function getWorkingImageSource(url) {
|
function getWorkingImageSource(url) {
|
||||||
if (url.includes('pximg.net')) {
|
if (url.includes('pximg.net')) {
|
||||||
@@ -287,7 +287,7 @@ Singleton {
|
|||||||
function setProvider(provider) {
|
function setProvider(provider) {
|
||||||
provider = provider.toLowerCase()
|
provider = provider.toLowerCase()
|
||||||
if (providerList.indexOf(provider) !== -1) {
|
if (providerList.indexOf(provider) !== -1) {
|
||||||
PersistentStateManager.setState("booru.provider", provider)
|
Persistent.states.booru.provider = provider
|
||||||
root.addSystemMessage(Translation.tr("Provider set to ") + providers[provider].name
|
root.addSystemMessage(Translation.tr("Provider set to ") + providers[provider].name
|
||||||
+ (provider == "zerochan" ? Translation.tr(". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!") : ""))
|
+ (provider == "zerochan" ? Translation.tr(". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!") : ""))
|
||||||
} else {
|
} else {
|
||||||
@@ -409,7 +409,7 @@ Singleton {
|
|||||||
xhr.setRequestHeader("User-Agent", defaultUserAgent)
|
xhr.setRequestHeader("User-Agent", defaultUserAgent)
|
||||||
}
|
}
|
||||||
else if (currentProvider == "zerochan") {
|
else if (currentProvider == "zerochan") {
|
||||||
const userAgent = ConfigOptions?.sidebar?.booru?.zerochan?.username ? `Desktop sidebar booru viewer - username: ${ConfigOptions.sidebar.booru.zerochan.username}` : defaultUserAgent
|
const userAgent = Config.options?.sidebar?.booru?.zerochan?.username ? `Desktop sidebar booru viewer - username: ${Config.options.sidebar.booru.zerochan.username}` : defaultUserAgent
|
||||||
xhr.setRequestHeader("User-Agent", userAgent)
|
xhr.setRequestHeader("User-Agent", userAgent)
|
||||||
}
|
}
|
||||||
root.runningRequests++;
|
root.runningRequests++;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import Quickshell.Io
|
|||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
property bool sloppySearch: ConfigOptions?.search.sloppy ?? false
|
property bool sloppySearch: Config.options?.search.sloppy ?? false
|
||||||
property real scoreThreshold: 0.2
|
property real scoreThreshold: 0.2
|
||||||
property list<string> entries: []
|
property list<string> entries: []
|
||||||
readonly property var preparedEntries: entries.map(a => ({
|
readonly property var preparedEntries: entries.map(a => ({
|
||||||
@@ -51,7 +51,7 @@ Singleton {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: delayedUpdateTimer
|
id: delayedUpdateTimer
|
||||||
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay
|
interval: Config.options.hacks.arbitraryRaceConditionDelay
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.refresh()
|
root.refresh()
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import "root:/modules/common"
|
|
||||||
import "root:/modules/common/functions/file_utils.js" as FileUtils
|
|
||||||
import "root:/modules/common/functions/string_utils.js" as StringUtils
|
|
||||||
import "root:/modules/common/functions/object_utils.js" as ObjectUtils
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Qt.labs.platform
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and manages the shell configuration file.
|
|
||||||
* The config file is by default at XDG_CONFIG_HOME/illogical-impulse/config.json.
|
|
||||||
* Automatically reloaded when the file changes.
|
|
||||||
*/
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
property string filePath: Directories.shellConfigPath
|
|
||||||
property bool firstLoad: true
|
|
||||||
property bool preventNextLoad: false
|
|
||||||
property var preventNextNotification: false
|
|
||||||
|
|
||||||
function loadConfig() {
|
|
||||||
configFileView.reload()
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyConfig(fileContent) {
|
|
||||||
try {
|
|
||||||
if (fileContent.trim() === "") {
|
|
||||||
console.warn("[ConfigLoader] Config file is empty, skipping load.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const json = JSON.parse(fileContent);
|
|
||||||
|
|
||||||
ObjectUtils.applyToQtObject(ConfigOptions, json);
|
|
||||||
if (root.firstLoad) {
|
|
||||||
root.firstLoad = false;
|
|
||||||
root.preventNextLoad = true;
|
|
||||||
root.saveConfig(); // Make sure new properties are added to the user's config file
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("[ConfigLoader] Error reading file:", e);
|
|
||||||
console.log("[ConfigLoader] File content was:", fileContent);
|
|
||||||
Quickshell.execDetached(["bash", "-c", `notify-send '${Translation.tr("Shell configuration failed to load")}' '${root.filePath}'`])
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLiveConfigValue(nestedKey, value) {
|
|
||||||
let keys = nestedKey.split(".");
|
|
||||||
let obj = ConfigOptions;
|
|
||||||
let parents = [obj];
|
|
||||||
|
|
||||||
// Traverse and collect parent objects
|
|
||||||
for (let i = 0; i < keys.length - 1; ++i) {
|
|
||||||
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
|
|
||||||
obj[keys[i]] = {};
|
|
||||||
}
|
|
||||||
obj = obj[keys[i]];
|
|
||||||
parents.push(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert value to correct type using JSON.parse when safe
|
|
||||||
let convertedValue = value;
|
|
||||||
if (typeof value === "string") {
|
|
||||||
let trimmed = value.trim();
|
|
||||||
if (trimmed === "true" || trimmed === "false" || !isNaN(Number(trimmed))) {
|
|
||||||
try {
|
|
||||||
convertedValue = JSON.parse(trimmed);
|
|
||||||
} catch (e) {
|
|
||||||
convertedValue = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj[keys[keys.length - 1]] = convertedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveConfig() {
|
|
||||||
const plainConfig = ObjectUtils.toPlainObject(ConfigOptions)
|
|
||||||
Quickshell.execDetached(["bash", "-c", `echo '${StringUtils.shellSingleQuoteEscape(JSON.stringify(plainConfig, null, 2))}' > '${FileUtils.trimFileProtocol(root.filePath)}'`])
|
|
||||||
}
|
|
||||||
|
|
||||||
function setConfigValueAndSave(nestedKey, value, preventNextNotification = true) {
|
|
||||||
setLiveConfigValue(nestedKey, value);
|
|
||||||
root.preventNextNotification = preventNextNotification;
|
|
||||||
saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: delayedFileRead
|
|
||||||
interval: ConfigOptions.hacks.arbitraryRaceConditionDelay
|
|
||||||
running: false
|
|
||||||
onTriggered: {
|
|
||||||
if (root.preventNextLoad) {
|
|
||||||
root.preventNextLoad = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (root.firstLoad) {
|
|
||||||
root.applyConfig(configFileView.text())
|
|
||||||
} else {
|
|
||||||
root.applyConfig(configFileView.text())
|
|
||||||
if (!root.preventNextNotification) {
|
|
||||||
// Quickshell.execDetached(["bash", "-c", `notify-send '${qsTr("Shell configuration reloaded")}' '${root.filePath}'`])
|
|
||||||
} else {
|
|
||||||
root.preventNextNotification = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileView {
|
|
||||||
id: configFileView
|
|
||||||
path: Qt.resolvedUrl(root.filePath)
|
|
||||||
watchChanges: true
|
|
||||||
onFileChanged: {
|
|
||||||
this.reload()
|
|
||||||
delayedFileRead.start()
|
|
||||||
}
|
|
||||||
onLoadedChanged: {
|
|
||||||
const fileContent = configFileView.text()
|
|
||||||
delayedFileRead.start()
|
|
||||||
}
|
|
||||||
onLoadFailed: (error) => {
|
|
||||||
if(error == FileViewError.FileNotFound) {
|
|
||||||
console.log("[ConfigLoader] File not found, creating new file.")
|
|
||||||
root.saveConfig()
|
|
||||||
Quickshell.execDetached(["bash", "-c", `notify-send '${Translation.tr("Shell configuration created")}' '${root.filePath}'`])
|
|
||||||
} else {
|
|
||||||
Quickshell.execDetached(["bash", "-c", `notify-send '${Translation.tr("Shell configuration failed to load")}' '${root.filePath}'`])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,8 +9,8 @@ pragma ComponentBehavior: Bound
|
|||||||
* A nice wrapper for date and time strings.
|
* A nice wrapper for date and time strings.
|
||||||
*/
|
*/
|
||||||
Singleton {
|
Singleton {
|
||||||
property string time: Qt.locale().toString(clock.date, ConfigOptions?.time.format ?? "hh:mm")
|
property string time: Qt.locale().toString(clock.date, Config.options?.time.format ?? "hh:mm")
|
||||||
property string date: Qt.locale().toString(clock.date, ConfigOptions?.time.dateFormat ?? "dddd, dd/MM")
|
property string date: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM")
|
||||||
property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy")
|
property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy")
|
||||||
property string uptime: "0h, 0m"
|
property string uptime: "0h, 0m"
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ Singleton {
|
|||||||
if (hours > 0) formatted += `${formatted ? ", " : ""}${hours}h`
|
if (hours > 0) formatted += `${formatted ? ", " : ""}${hours}h`
|
||||||
if (minutes > 0 || !formatted) formatted += `${formatted ? ", " : ""}${minutes}m`
|
if (minutes > 0 || !formatted) formatted += `${formatted ? ", " : ""}${minutes}m`
|
||||||
uptime = formatted
|
uptime = formatted
|
||||||
interval = ConfigOptions?.resources?.updateInterval ?? 3000
|
interval = Config.options?.resources?.updateInterval ?? 3000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,20 @@ Singleton {
|
|||||||
property var addresses: []
|
property var addresses: []
|
||||||
property var windowByAddress: ({})
|
property var windowByAddress: ({})
|
||||||
property var monitors: []
|
property var monitors: []
|
||||||
|
property var layers: ({})
|
||||||
|
|
||||||
function updateWindowList() {
|
function updateWindowList() {
|
||||||
getClients.running = true
|
getClients.running = true
|
||||||
getMonitors.running = true
|
getMonitors.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLayers() {
|
||||||
|
getLayers.running = true
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
updateWindowList()
|
updateWindowList()
|
||||||
|
updateLayers()
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -56,6 +62,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: getMonitors
|
id: getMonitors
|
||||||
command: ["bash", "-c", "hyprctl monitors -j | jq -c"]
|
command: ["bash", "-c", "hyprctl monitors -j | jq -c"]
|
||||||
@@ -65,5 +72,15 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: getLayers
|
||||||
|
command: ["bash", "-c", "hyprctl layers -j | jq -c"]
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: (data) => {
|
||||||
|
root.layers = JSON.parse(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Singleton {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: delayedFileRead
|
id: delayedFileRead
|
||||||
interval: ConfigOptions?.hacks?.arbitraryRaceConditionDelay ?? 100
|
interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 100
|
||||||
repeat: false
|
repeat: false
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import "root:/modules/common"
|
|
||||||
import "root:/modules/common/functions/object_utils.js" as ObjectUtils
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Qt.labs.platform
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages persistent states across sessions.
|
|
||||||
* Run loadStates() once at startup to load the states, then use setState() and getState() to modify and access them.
|
|
||||||
*/
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
property string fileDir: Directories.state
|
|
||||||
property string fileName: "states.json"
|
|
||||||
property string filePath: `${root.fileDir}/${root.fileName}`
|
|
||||||
property bool allowWriteback: false
|
|
||||||
|
|
||||||
function getState(nestedKey) {
|
|
||||||
let keys = nestedKey.split(".");
|
|
||||||
let obj = PersistentStates;
|
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
|
||||||
if (obj[keys[i]] === undefined) {
|
|
||||||
console.error(`[PersistentStateManager] Key "${keys[i]}" not found in PersistentStates`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
obj = obj[keys[i]];
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setState(nestedKey, value) {
|
|
||||||
if (!root.allowWriteback) return;
|
|
||||||
let keys = nestedKey.split(".");
|
|
||||||
let obj = PersistentStates;
|
|
||||||
let parents = [obj];
|
|
||||||
|
|
||||||
// Traverse and collect parent objects
|
|
||||||
for (let i = 0; i < keys.length - 1; ++i) {
|
|
||||||
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
|
|
||||||
obj[keys[i]] = {};
|
|
||||||
}
|
|
||||||
obj = obj[keys[i]];
|
|
||||||
parents.push(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the value at the innermost key
|
|
||||||
obj[keys[keys.length - 1]] = value;
|
|
||||||
|
|
||||||
saveStates()
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadStates() {
|
|
||||||
stateFileView.reload()
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveStates() {
|
|
||||||
const plainStates = ObjectUtils.toPlainObject(PersistentStates)
|
|
||||||
stateFileView.setText(JSON.stringify(plainStates, null, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyStates(fileContent) {
|
|
||||||
try {
|
|
||||||
const json = JSON.parse(fileContent);
|
|
||||||
ObjectUtils.applyToQtObject(PersistentStates, json);
|
|
||||||
root.allowWriteback = true
|
|
||||||
} catch (e) {
|
|
||||||
console.error("[PersistentStateManager] Error reading file:", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: delayedFileRead
|
|
||||||
interval: ConfigOptions?.hacks?.arbitraryRaceConditionDelay ?? 100
|
|
||||||
repeat: false
|
|
||||||
running: false
|
|
||||||
onTriggered: {
|
|
||||||
root.applyStates(stateFileView.text())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileView {
|
|
||||||
id: stateFileView
|
|
||||||
path: root.filePath
|
|
||||||
watchChanges: true
|
|
||||||
// onFileChanged: {
|
|
||||||
// console.log("[PersistentStateManager] File changed, reloading...")
|
|
||||||
// this.reload()
|
|
||||||
// delayedFileRead.start()
|
|
||||||
// }
|
|
||||||
onLoadedChanged: {
|
|
||||||
const fileContent = stateFileView.text()
|
|
||||||
root.applyStates(fileContent)
|
|
||||||
}
|
|
||||||
onLoadFailed: (error) => {
|
|
||||||
console.log("[PersistentStateManager] File not found, creating new file")
|
|
||||||
root.saveStates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -53,7 +53,7 @@ Singleton {
|
|||||||
|
|
||||||
previousCpuStats = { total, idle }
|
previousCpuStats = { total, idle }
|
||||||
}
|
}
|
||||||
interval = ConfigOptions?.resources?.updateInterval ?? 3000
|
interval = Config.options?.resources?.updateInterval ?? 3000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
MaterialThemeLoader.reapplyTheme()
|
MaterialThemeLoader.reapplyTheme()
|
||||||
ConfigLoader.loadConfig()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
minimumWidth: 600
|
minimumWidth: 600
|
||||||
@@ -93,15 +92,15 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Item { // Titlebar
|
Item { // Titlebar
|
||||||
visible: ConfigOptions?.windows.showTitlebar
|
visible: Config.options?.windows.showTitlebar
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: false
|
Layout.fillHeight: false
|
||||||
implicitHeight: Math.max(titleText.implicitHeight, windowControlsRow.implicitHeight)
|
implicitHeight: Math.max(titleText.implicitHeight, windowControlsRow.implicitHeight)
|
||||||
StyledText {
|
StyledText {
|
||||||
id: titleText
|
id: titleText
|
||||||
anchors {
|
anchors {
|
||||||
left: ConfigOptions.windows.centerTitle ? undefined : parent.left
|
left: Config.options.windows.centerTitle ? undefined : parent.left
|
||||||
horizontalCenter: ConfigOptions.windows.centerTitle ? parent.horizontalCenter : undefined
|
horizontalCenter: Config.options.windows.centerTitle ? parent.horizontalCenter : undefined
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
leftMargin: 12
|
leftMargin: 12
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ ShellRoot {
|
|||||||
property bool enableBar: true
|
property bool enableBar: true
|
||||||
property bool enableBackgroundWidgets: true
|
property bool enableBackgroundWidgets: true
|
||||||
property bool enableCheatsheet: true
|
property bool enableCheatsheet: true
|
||||||
property bool enableDock: false
|
property bool enableDock: true
|
||||||
property bool enableMediaControls: true
|
property bool enableMediaControls: true
|
||||||
property bool enableNotificationPopup: true
|
property bool enableNotificationPopup: true
|
||||||
property bool enableOnScreenDisplayBrightness: true
|
property bool enableOnScreenDisplayBrightness: true
|
||||||
@@ -48,8 +48,6 @@ ShellRoot {
|
|||||||
// Force initialization of some singletons
|
// Force initialization of some singletons
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
MaterialThemeLoader.reapplyTheme()
|
MaterialThemeLoader.reapplyTheme()
|
||||||
ConfigLoader.loadConfig()
|
|
||||||
PersistentStateManager.loadStates()
|
|
||||||
Cliphist.refresh()
|
Cliphist.refresh()
|
||||||
FirstRunExperience.load()
|
FirstRunExperience.load()
|
||||||
}
|
}
|
||||||
@@ -57,7 +55,7 @@ ShellRoot {
|
|||||||
LazyLoader { active: enableBar; component: Bar {} }
|
LazyLoader { active: enableBar; component: Bar {} }
|
||||||
LazyLoader { active: enableBackgroundWidgets; component: BackgroundWidgets {} }
|
LazyLoader { active: enableBackgroundWidgets; component: BackgroundWidgets {} }
|
||||||
LazyLoader { active: enableCheatsheet; component: Cheatsheet {} }
|
LazyLoader { active: enableCheatsheet; component: Cheatsheet {} }
|
||||||
LazyLoader { active: enableDock; component: Dock {} }
|
LazyLoader { active: enableDock && Config.options.dock.enable; component: Dock {} }
|
||||||
LazyLoader { active: enableMediaControls; component: MediaControls {} }
|
LazyLoader { active: enableMediaControls; component: MediaControls {} }
|
||||||
LazyLoader { active: enableNotificationPopup; component: NotificationPopup {} }
|
LazyLoader { active: enableNotificationPopup; component: NotificationPopup {} }
|
||||||
LazyLoader { active: enableOnScreenDisplayBrightness; component: OnScreenDisplayBrightness {} }
|
LazyLoader { active: enableOnScreenDisplayBrightness; component: OnScreenDisplayBrightness {} }
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
// Adjust this to make the app smaller or larger
|
// Adjust this to make the app smaller or larger
|
||||||
//@ pragma Env QT_SCALE_FACTOR=1
|
//@ pragma Env QT_SCALE_FACTOR=1
|
||||||
|
|
||||||
import Qt5Compat.GraphicalEffects
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -32,7 +31,6 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
MaterialThemeLoader.reapplyTheme()
|
MaterialThemeLoader.reapplyTheme()
|
||||||
ConfigLoader.loadConfig()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
minimumWidth: 600
|
minimumWidth: 600
|
||||||
@@ -60,14 +58,14 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Item { // Titlebar
|
Item { // Titlebar
|
||||||
visible: ConfigOptions?.windows.showTitlebar
|
visible: Config.options?.windows.showTitlebar
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
implicitHeight: Math.max(welcomeText.implicitHeight, windowControlsRow.implicitHeight)
|
implicitHeight: Math.max(welcomeText.implicitHeight, windowControlsRow.implicitHeight)
|
||||||
StyledText {
|
StyledText {
|
||||||
id: welcomeText
|
id: welcomeText
|
||||||
anchors {
|
anchors {
|
||||||
left: ConfigOptions.windows.centerTitle ? undefined : parent.left
|
left: Config.options.windows.centerTitle ? undefined : parent.left
|
||||||
horizontalCenter: ConfigOptions.windows.centerTitle ? parent.horizontalCenter : undefined
|
horizontalCenter: Config.options.windows.centerTitle ? parent.horizontalCenter : undefined
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
leftMargin: 12
|
leftMargin: 12
|
||||||
}
|
}
|
||||||
@@ -123,6 +121,24 @@ ApplicationWindow {
|
|||||||
ContentPage {
|
ContentPage {
|
||||||
id: contentColumn
|
id: contentColumn
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
ContentSection {
|
||||||
|
title: "Bar style"
|
||||||
|
|
||||||
|
ConfigSelectionArray {
|
||||||
|
currentValue: Config.options.bar.cornerStyle
|
||||||
|
configOptionName: "bar.cornerStyle"
|
||||||
|
onSelected: (newValue) => {
|
||||||
|
Config.options.bar.cornerStyle = newValue; // Update local copy
|
||||||
|
}
|
||||||
|
options: [
|
||||||
|
{ displayName: "Hug", value: 0 },
|
||||||
|
{ displayName: "Float", value: 1 },
|
||||||
|
{ displayName: "Plain rectangle", value: 2 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ContentSection {
|
ContentSection {
|
||||||
title: "Style & wallpaper"
|
title: "Style & wallpaper"
|
||||||
|
|
||||||
@@ -206,10 +222,10 @@ ApplicationWindow {
|
|||||||
text: "Weeb"
|
text: "Weeb"
|
||||||
}
|
}
|
||||||
ConfigSelectionArray {
|
ConfigSelectionArray {
|
||||||
currentValue: ConfigOptions.policies.weeb
|
currentValue: Config.options.policies.weeb
|
||||||
configOptionName: "policies.weeb"
|
configOptionName: "policies.weeb"
|
||||||
onSelected: (newValue) => {
|
onSelected: (newValue) => {
|
||||||
ConfigLoader.setConfigValueAndSave("policies.weeb", newValue);
|
Config.options.policies.weeb = newValue;
|
||||||
}
|
}
|
||||||
options: [
|
options: [
|
||||||
{ displayName: "No", value: 0 },
|
{ displayName: "No", value: 0 },
|
||||||
@@ -224,10 +240,10 @@ ApplicationWindow {
|
|||||||
text: "AI"
|
text: "AI"
|
||||||
}
|
}
|
||||||
ConfigSelectionArray {
|
ConfigSelectionArray {
|
||||||
currentValue: ConfigOptions.policies.ai
|
currentValue: Config.options.policies.ai
|
||||||
configOptionName: "policies.ai"
|
configOptionName: "policies.ai"
|
||||||
onSelected: (newValue) => {
|
onSelected: (newValue) => {
|
||||||
ConfigLoader.setConfigValueAndSave("policies.ai", newValue);
|
Config.options.policies.ai = newValue;
|
||||||
}
|
}
|
||||||
options: [
|
options: [
|
||||||
{ displayName: "No", value: 0 },
|
{ displayName: "No", value: 0 },
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ license=(None)
|
|||||||
depends=(
|
depends=(
|
||||||
xdg-desktop-portal
|
xdg-desktop-portal
|
||||||
xdg-desktop-portal-kde
|
xdg-desktop-portal-kde
|
||||||
|
xdg-desktop-portal-gtk
|
||||||
xdg-desktop-portal-hyprland
|
xdg-desktop-portal-hyprland
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ arch=(any)
|
|||||||
license=(None)
|
license=(None)
|
||||||
depends=(
|
depends=(
|
||||||
hyprshot
|
hyprshot
|
||||||
ksnip
|
|
||||||
slurp
|
slurp
|
||||||
|
swappy
|
||||||
tesseract
|
tesseract
|
||||||
tesseract-data-eng
|
tesseract-data-eng
|
||||||
wf-recorder
|
wf-recorder
|
||||||
|
|||||||
+1
-1
@@ -144,7 +144,7 @@ esac
|
|||||||
|
|
||||||
v sudo usermod -aG video,i2c,input "$(whoami)"
|
v sudo usermod -aG video,i2c,input "$(whoami)"
|
||||||
v bash -c "echo i2c-dev | sudo tee /etc/modules-load.d/i2c-dev.conf"
|
v bash -c "echo i2c-dev | sudo tee /etc/modules-load.d/i2c-dev.conf"
|
||||||
v sudo pacman -S archlinux-xdg-menu && XDG_MENU_PREFIX=arch- kbuildsycoca6; sudo ln -s /etc/xdg/menus/plasma-applications.menu /etc/xdg/menus/applications.menu
|
v sudo pacman -S archlinux-xdg-menu && XDG_MENU_PREFIX=arch- kbuildsycoca6; sudo ln -sf /etc/xdg/menus/plasma-applications.menu /etc/xdg/menus/applications.menu
|
||||||
v systemctl --user enable ydotool --now
|
v systemctl --user enable ydotool --now
|
||||||
v sudo systemctl enable bluetooth --now
|
v sudo systemctl enable bluetooth --now
|
||||||
v gsettings set org.gnome.desktop.interface font-name 'Rubik 11'
|
v gsettings set org.gnome.desktop.interface font-name 'Rubik 11'
|
||||||
|
|||||||
Reference in New Issue
Block a user