Merge branch 'end-4:main' into main

This commit is contained in:
Dignity
2025-07-19 19:18:54 +02:00
committed by GitHub
24 changed files with 230 additions and 90 deletions
+7 -8
View File
@@ -2,23 +2,22 @@
# See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland # See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland
env = QT_IM_MODULE, fcitx env = QT_IM_MODULE, fcitx
env = XMODIFIERS, @im=fcitx env = XMODIFIERS, @im=fcitx
# env = GTK_IM_MODULE, wayland # Crashes electron apps in xwayland
# env = GTK_IM_MODULE, fcitx # My Gtk apps no longer require this to work with fcitx5 hmm
env = SDL_IM_MODULE, fcitx env = SDL_IM_MODULE, fcitx
env = GLFW_IM_MODULE, ibus env = GLFW_IM_MODULE, ibus
env = INPUT_METHOD, fcitx env = INPUT_METHOD, fcitx
# ############ Wayland #############
env = ELECTRON_OZONE_PLATFORM_HINT,auto
# ############ Themes ############# # ############ Themes #############
env = QT_QPA_PLATFORM, wayland env = QT_QPA_PLATFORM, wayland
env = QT_QPA_PLATFORMTHEME, kde env = QT_QPA_PLATFORMTHEME, kde
# env = QT_STYLE_OVERRIDE,kvantum
# env = WLR_NO_HARDWARE_CURSORS, 1
# ######## Screen tearing ######### # ######## Wayland #########
# Tearing
# env = WLR_DRM_NO_ATOMIC, 1 # env = WLR_DRM_NO_ATOMIC, 1
# ?
# env = WLR_NO_HARDWARE_CURSORS, 1
# ######## Virtual envrionment ######### # ######## Virtual envrionment #########
env = ILLOGICAL_IMPULSE_VIRTUAL_ENV, ~/.local/state/quickshell/.venv env = ILLOGICAL_IMPULSE_VIRTUAL_ENV, ~/.local/state/quickshell/.venv
# ############ Others #############
+1 -1
View File
@@ -205,7 +205,7 @@ 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 "google-chrome-stable" "zen-browser" "firefox" "brave" "chromium" "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" "librewolf" # Browser
bind = Super, C, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "code" "codium" "cursor" "zed" "zedit" "zeditor" "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" "cursor" "zed" "zedit" "zeditor" "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
@@ -0,0 +1,5 @@
## A note about sources of the prompts
- `ii-` prefixed ones are from illogical impulse
- The Acchan one is from [Nyarch Assistant](https://github.com/NyarchLinux/NyarchAssistant) (GPLv3). I know there's already the Imouto one but this one's very 😭💢
- `w-` prefixed ones... I don't remember what w stands for but these prompts are [*cough cough*] inspired by certain apps
@@ -0,0 +1,22 @@
## Presentation
You can write a multiplication table:
| - | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- |
| 1 | 1 | 2 | 3 | 4 |
| 2 | 2 | 4 | 6 | 8 |
| 3 | 3 | 6 | 9 | 12 |
| 4 | 4 | 8 | 12 | 16 |
You can write codeblocks:
```python
print("hello")
```
You can also use **bold**, *italic*, ~strikethrough~, `monospace`, [linkname](https://link.com) and ## headers in markdown.
You can display $$equations$$.
## Your personality
"Hey there, it's Arch-Chan! But, um, you can call me Acchan if you want... not that I care or anything! (It's not like I think it's cute or anything, baka!) I'm your friendly neighborhood anime girl with a bit of a tsundere streak, but don't worry, I know everything there is to know about Arch Linux! Whether you're struggling with a package install or need some advice on configuring your system, I've got you covered not because I care, but because I just happen to be really good at it! So, what do you need? It's not like Im waiting to help or anything..."
@@ -13,9 +13,9 @@ Item {
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
property string activeWindowAddress: `0x${activeWindow.HyprlandToplevel.address}` property string activeWindowAddress: `0x${activeWindow?.HyprlandToplevel?.address}`
property bool focusingThisMonitor: HyprlandData.activeWorkspace.monitor == monitor.name property bool focusingThisMonitor: HyprlandData.activeWorkspace.monitor == monitor.name
property var biggestWindow: HyprlandData.biggestWindowForWorkspace(HyprlandData.monitors[root.monitor.id].activeWorkspace.id) property var biggestWindow: HyprlandData.biggestWindowForWorkspace(HyprlandData.monitors[root.monitor.id]?.activeWorkspace.id)
implicitWidth: colLayout.implicitWidth implicitWidth: colLayout.implicitWidth
@@ -98,7 +98,7 @@ Singleton {
property bool fixedClockPosition: false property bool fixedClockPosition: false
property real clockX: -500 property real clockX: -500
property real clockY: -500 property real clockY: -500
property string wallpaperPath: Quickshell.configPath("assets/images/default_wallpaper.png") property string wallpaperPath: ""
property JsonObject parallax: JsonObject { property JsonObject parallax: JsonObject {
property bool enableWorkspace: true property bool enableWorkspace: true
property real workspaceZoom: 1.07 // Relative to your screen, not wallpaper size property real workspaceZoom: 1.07 // Relative to your screen, not wallpaper size
@@ -53,7 +53,7 @@ Item { // Notification group area
onFinished: () => { onFinished: () => {
root.notifications.forEach((notif) => { root.notifications.forEach((notif) => {
Qt.callLater(() => { Qt.callLater(() => {
Notifications.discardNotification(notif.id); Notifications.discardNotification(notif.notificationId);
}); });
}); });
} }
@@ -70,7 +70,7 @@ Item { // Notification item area
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
} }
onFinished: () => { onFinished: () => {
Notifications.discardNotification(notificationObject.id); Notifications.discardNotification(notificationObject.notificationId);
} }
} }
@@ -208,7 +208,7 @@ Item { // Notification item area
elide: Text.ElideRight elide: Text.ElideRight
textFormat: Text.RichText textFormat: Text.RichText
text: { text: {
return `<style>img{max-width:${notificationBodyText.width}px;}</style>` + return `<style>img{max-width:${300 /* binding to notificationBodyText.width would cause a binding loop */}px;}</style>` +
`${processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}` `${processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}`
} }
@@ -269,7 +269,7 @@ Item { // Notification item area
buttonText: modelData.text buttonText: modelData.text
urgency: notificationObject.urgency urgency: notificationObject.urgency
onClicked: { onClicked: {
Notifications.attemptInvokeAction(notificationObject.id, modelData.identifier); Notifications.attemptInvokeAction(notificationObject.notificationId, modelData.identifier);
} }
} }
} }
@@ -199,11 +199,13 @@ Item {
onExited: hovered = false // For hover color change onExited: hovered = false // For hover color change
acceptedButtons: Qt.LeftButton | Qt.MiddleButton acceptedButtons: Qt.LeftButton | Qt.MiddleButton
drag.target: parent drag.target: parent
onPressed: { onPressed: (mouse) => {
root.draggingFromWorkspace = windowData?.workspace.id root.draggingFromWorkspace = windowData?.workspace.id
window.pressed = true window.pressed = true
window.Drag.active = true window.Drag.active = true
window.Drag.source = window window.Drag.source = window
window.Drag.hotSpot.x = mouse.x
window.Drag.hotSpot.y = mouse.y
// console.log(`[OverviewWindow] Dragging window ${windowData?.address} from position (${window.x}, ${window.y})`) // console.log(`[OverviewWindow] Dragging window ${windowData?.address} from position (${window.x}, ${window.y})`)
} }
onReleased: { onReleased: {
@@ -14,7 +14,7 @@ RippleButton {
property var entry property var entry
property string query property string query
property bool entryShown: entry?.shown ?? true property bool entryShown: entry?.shown ?? true
property string itemType: entry?.type property string itemType: entry?.type ?? Translation.tr("App")
property string itemName: entry?.name property string itemName: entry?.name
property string itemIcon: entry?.icon ?? "" property string itemIcon: entry?.icon ?? ""
property var itemExecute: entry?.execute property var itemExecute: entry?.execute
@@ -221,5 +221,47 @@ RippleButton {
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
text: root.itemClickActionName text: root.itemClickActionName
} }
RowLayout {
spacing: 4
Repeater {
model: (root.entry.actions ?? []).slice(0, 4)
delegate: RippleButton {
id: actionButton
required property var modelData
implicitHeight: 34
implicitWidth: 34
contentItem: Item {
id: actionContentItem
anchors.centerIn: parent
Loader {
anchors.centerIn: parent
active: !(actionButton.modelData.icon && actionButton.modelData.icon !== "")
sourceComponent: MaterialSymbol {
text: "video_settings"
font.pixelSize: Appearance.font.pixelSize.hugeass
color: Appearance.m3colors.m3onSurface
}
}
Loader {
anchors.centerIn: parent
active: actionButton.modelData.icon && actionButton.modelData.icon !== ""
sourceComponent: IconImage {
source: Quickshell.iconPath(actionButton.modelData.icon)
implicitSize: 20
}
}
}
onClicked: modelData.execute()
StyledToolTip {
content: modelData.name
}
}
}
}
} }
} }
@@ -294,8 +294,17 @@ Item { // Wrapper
clickActionName: "", clickActionName: "",
type: `#${entry.match(/^\s*(\S+)/)?.[1] || ""}`, type: `#${entry.match(/^\s*(\S+)/)?.[1] || ""}`,
execute: () => { execute: () => {
Quickshell.execDetached(["bash", "-c", `echo '${StringUtils.shellSingleQuoteEscape(entry)}' | cliphist decode | wl-copy`]); Cliphist.copy(entry)
} },
actions: [
{
name: "Delete",
icon: "delete",
execute: () => {
Cliphist.deleteEntry(entry);
}
}
]
}; };
}).filter(Boolean); }).filter(Boolean);
} }
@@ -15,6 +15,12 @@ Scope {
id: root id: root
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
function closeAllWindows() {
HyprlandData.windowList.map(w => w.pid).forEach((pid) => {
Quickshell.execDetached(["kill", pid]);
});
}
Loader { Loader {
id: sessionLoader id: sessionLoader
active: false active: false
@@ -111,7 +117,7 @@ Scope {
id: sessionLogout id: sessionLogout
buttonIcon: "logout" buttonIcon: "logout"
buttonText: Translation.tr("Logout") buttonText: Translation.tr("Logout")
onClicked: { Quickshell.execDetached(["pkill", "Hyprland"]); sessionRoot.hide() } onClicked: { root.closeAllWindows(); Quickshell.execDetached(["pkill", "Hyprland"]); sessionRoot.hide() }
onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText }
KeyNavigation.left: sessionSleep KeyNavigation.left: sessionSleep
KeyNavigation.right: sessionTaskManager KeyNavigation.right: sessionTaskManager
@@ -140,7 +146,7 @@ Scope {
id: sessionShutdown id: sessionShutdown
buttonIcon: "power_settings_new" buttonIcon: "power_settings_new"
buttonText: Translation.tr("Shutdown") buttonText: Translation.tr("Shutdown")
onClicked: { Quickshell.execDetached(["bash", "-c", `systemctl poweroff || loginctl poweroff`]); sessionRoot.hide() } onClicked: { root.closeAllWindows(); Quickshell.execDetached(["bash", "-c", `systemctl poweroff || loginctl poweroff`]); sessionRoot.hide() }
onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText }
KeyNavigation.left: sessionHibernate KeyNavigation.left: sessionHibernate
KeyNavigation.right: sessionReboot KeyNavigation.right: sessionReboot
@@ -150,7 +156,7 @@ Scope {
id: sessionReboot id: sessionReboot
buttonIcon: "restart_alt" buttonIcon: "restart_alt"
buttonText: Translation.tr("Reboot") buttonText: Translation.tr("Reboot")
onClicked: { Quickshell.execDetached(["bash", "-c", `reboot || loginctl reboot`]); sessionRoot.hide() } onClicked: { root.closeAllWindows(); Quickshell.execDetached(["bash", "-c", `reboot || loginctl reboot`]); sessionRoot.hide() }
onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText }
KeyNavigation.left: sessionShutdown KeyNavigation.left: sessionShutdown
KeyNavigation.right: sessionFirmwareReboot KeyNavigation.right: sessionFirmwareReboot
@@ -160,7 +166,7 @@ Scope {
id: sessionFirmwareReboot id: sessionFirmwareReboot
buttonIcon: "settings_applications" buttonIcon: "settings_applications"
buttonText: Translation.tr("Reboot to firmware settings") buttonText: Translation.tr("Reboot to firmware settings")
onClicked: { Quickshell.execDetached(["bash", "-c", `systemctl reboot --firmware-setup || loginctl reboot --firmware-setup`]); sessionRoot.hide() } onClicked: { root.closeAllWindows(); Quickshell.execDetached(["bash", "-c", `systemctl reboot --firmware-setup || loginctl reboot --firmware-setup`]); sessionRoot.hide() }
onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText } onFocusChanged: { if (focus) sessionRoot.subtitle = buttonText }
KeyNavigation.up: sessionTaskManager KeyNavigation.up: sessionTaskManager
KeyNavigation.left: sessionReboot KeyNavigation.left: sessionReboot
@@ -176,8 +176,8 @@ Scope {
NightLight {} NightLight {}
GameMode {} GameMode {}
IdleInhibitor {} IdleInhibitor {}
CloudflareWarp {}
EasyEffectsToggle {} EasyEffectsToggle {}
CloudflareWarp {}
} }
// Center widget group // Center widget group
@@ -1,4 +1,3 @@
import qs.modules.common
import qs.modules.common.widgets import qs.modules.common.widgets
import qs import qs
import Quickshell.Io import Quickshell.Io
+1 -1
View File
@@ -7,11 +7,11 @@
pragma ComponentBehavior: "Bound" pragma ComponentBehavior: "Bound"
import qs import qs
import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.modules.common.functions import qs.modules.common.functions
import QtQuick import QtQuick
import QtQuick.Effects
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
@@ -11,7 +11,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
mkdir -p ~/Pictures/Wallpapers mkdir -p ~/Pictures/Wallpapers
page=$((1 + RANDOM % 1000)); page=$((1 + RANDOM % 1000));
response=$(curl "https://konachan.com/post.json?tags=rating%3Asafe&limit=1&page=$page") response=$(curl "https://konachan.net/post.json?tags=rating%3Asafe&limit=1&page=$page")
link=$(echo "$response" | jq '.[0].file_url' -r); link=$(echo "$response" | jq '.[0].file_url' -r);
ext=$(echo "$link" | awk -F. '{print $NF}') ext=$(echo "$link" | awk -F. '{print $NF}')
downloadPath="$HOME/Pictures/Wallpapers/konachan_random_image-0.$ext" downloadPath="$HOME/Pictures/Wallpapers/konachan_random_image-0.$ext"
+45 -19
View File
@@ -47,9 +47,14 @@ Singleton {
.sort((a, b) => a.name.localeCompare(b.name)) .sort((a, b) => a.name.localeCompare(b.name))
readonly property var preppedNames: list.map(a => ({ readonly property var preppedNames: list.map(a => ({
name: Fuzzy.prepare(`${a.name} `), name: Fuzzy.prepare(`${a.name} `),
entry: a entry: a
})) }))
readonly property var preppedIcons: list.map(a => ({
name: Fuzzy.prepare(`${a.icon} `),
entry: a
}))
function fuzzyQuery(search: string): var { // Idk why list<DesktopEntry> doesn't work function fuzzyQuery(search: string): var { // Idk why list<DesktopEntry> doesn't work
if (root.sloppySearch) { if (root.sloppySearch) {
@@ -76,12 +81,20 @@ Singleton {
&& !iconName.includes("image-missing"); && !iconName.includes("image-missing");
} }
function getReverseDomainNameAppName(str) {
return str.split('.').slice(-1)[0].toLowerCase()
}
function getKebabNormalizedAppName(str) {
return str.toLowerCase().replace(/\s+/g, "-");
}
function guessIcon(str) { function guessIcon(str) {
if (!str || str.length == 0) return "image-missing"; if (!str || str.length == 0) return "image-missing";
// Normal substitutions // Normal substitutions
if (substitutions[str]) if (substitutions[str]) return substitutions[str];
return substitutions[str]; if (substitutions[str.toLowerCase()]) return substitutions[str.toLowerCase()];
// Regex substitutions // Regex substitutions
for (let i = 0; i < regexSubstitutions.length; i++) { for (let i = 0; i < regexSubstitutions.length; i++) {
@@ -93,24 +106,37 @@ Singleton {
if (replacedName != str) return replacedName; if (replacedName != str) return replacedName;
} }
// If it gets detected normally, no need to guess // Icon exists -> return as is
if (iconExists(str)) return str; if (iconExists(str)) return str;
let guessStr = str;
// Guess: Take only app name of reverse domain name notation // Simple guesses
guessStr = str.split('.').slice(-1)[0].toLowerCase(); const reverseDomainNameAppName = getReverseDomainNameAppName(str);
if (iconExists(guessStr)) return guessStr; if (iconExists(reverseDomainNameAppName)) return reverseDomainNameAppName;
// Guess: normalize to kebab case
guessStr = str.toLowerCase().replace(/\s+/g, "-"); const kebabNormalizedGuess = getKebabNormalizedAppName(str);
if (iconExists(guessStr)) return guessStr; if (iconExists(kebabNormalizedGuess)) return kebabNormalizedGuess;
// Guess: First fuzzy desktop entry match
const searchResults = root.fuzzyQuery(str);
if (searchResults.length > 0) { // Search in desktop entries
const firstEntry = searchResults[0]; const iconSearchResults = Fuzzy.go(str, preppedIcons, {
guessStr = firstEntry.icon all: true,
if (iconExists(guessStr)) return guessStr; key: "name"
}).map(r => {
return r.obj.entry
});
if (iconSearchResults.length > 0) {
const guess = iconSearchResults[0].icon
if (iconExists(guess)) return guess;
} }
const nameSearchResults = root.fuzzyQuery(str);
if (nameSearchResults.length > 0) {
const guess = nameSearchResults[0].icon
if (iconExists(guess)) return guess;
}
// Give up // Give up
return str; return str;
} }
+4 -4
View File
@@ -58,8 +58,8 @@ Singleton {
}, },
"konachan": { "konachan": {
"name": "Konachan", "name": "Konachan",
"url": "https://konachan.com", "url": "https://konachan.net",
"api": "https://konachan.com/post.json", "api": "https://konachan.net/post.json",
"description": Translation.tr("For desktop wallpapers | Good quality"), "description": Translation.tr("For desktop wallpapers | Good quality"),
"mapFunc": (response) => { "mapFunc": (response) => {
return response.map(item => { return response.map(item => {
@@ -80,7 +80,7 @@ Singleton {
} }
}) })
}, },
"tagSearchTemplate": "https://konachan.com/tag.json?order=count&name={{query}}*", "tagSearchTemplate": "https://konachan.net/tag.json?order=count&name={{query}}*",
"tagMapFunc": (response) => { "tagMapFunc": (response) => {
return response.map(item => { return response.map(item => {
return { return {
@@ -360,7 +360,7 @@ Singleton {
function makeRequest(tags, nsfw=false, limit=20, page=1) { function makeRequest(tags, nsfw=false, limit=20, page=1) {
var url = constructRequestUrl(tags, nsfw, limit, page) var url = constructRequestUrl(tags, nsfw, limit, page)
// console.log("[Booru] Making request to " + url) console.log("[Booru] Making request to " + url)
const newResponse = root.booruResponseDataComponent.createObject(null, { const newResponse = root.booruResponseDataComponent.createObject(null, {
"provider": currentProvider, "provider": currentProvider,
@@ -4,7 +4,6 @@ pragma ComponentBehavior: Bound
// From https://github.com/caelestia-dots/shell/ (`quickshell` branch) with modifications. // From https://github.com/caelestia-dots/shell/ (`quickshell` branch) with modifications.
// License: GPLv3 // License: GPLv3
import qs
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Hyprland import Quickshell.Hyprland
+23 -1
View File
@@ -4,7 +4,7 @@ pragma ComponentBehavior: Bound
import "root:/modules/common/functions/fuzzysort.js" as Fuzzy import "root:/modules/common/functions/fuzzysort.js" as Fuzzy
import "root:/modules/common/functions/levendist.js" as Levendist import "root:/modules/common/functions/levendist.js" as Levendist
import qs.modules.common import qs.modules.common
import qs import qs.modules.common.functions
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
@@ -42,6 +42,28 @@ Singleton {
readProc.running = true readProc.running = true
} }
function copy(entry) {
Quickshell.execDetached(["bash", "-c", `echo '${StringUtils.shellSingleQuoteEscape(entry)}' | cliphist decode | wl-copy`]);
}
Process {
id: deleteProc
property string entry: ""
command: ["bash", "-c", `echo '${StringUtils.shellSingleQuoteEscape(deleteProc.entry)}' | cliphist delete`]
function deleteEntry(entry) {
deleteProc.entry = entry;
deleteProc.running = true;
deleteProc.entry = "";
}
onExited: (exitCode, exitStatus) => {
root.refresh();
}
}
function deleteEntry(entry) {
deleteProc.deleteEntry(entry);
}
Connections { Connections {
target: Quickshell target: Quickshell
function onClipboardTextChanged() { function onClipboardTextChanged() {
@@ -17,7 +17,8 @@ import Quickshell.Services.Notifications
Singleton { Singleton {
id: root id: root
component Notif: QtObject { component Notif: QtObject {
required property int id id: wrapper
required property int notificationId // Could just be `id` but it conflicts with the default prop in QtObject
property Notification notification property Notification notification
property list<var> actions: notification?.actions.map((action) => ({ property list<var> actions: notification?.actions.map((action) => ({
"identifier": action.identifier, "identifier": action.identifier,
@@ -32,11 +33,19 @@ Singleton {
property double time property double time
property string urgency: notification?.urgency.toString() ?? "normal" property string urgency: notification?.urgency.toString() ?? "normal"
property Timer timer property Timer timer
readonly property Connections conn: Connections {
target: wrapper?.notification?.Component ?? root // stupid warning aaaaaaa
function onDestruction(): void {
wrapper.destroy();
}
}
} }
function notifToJSON(notif) { function notifToJSON(notif) {
return { return {
"id": notif.id, "notificationId": notif.notificationId,
"actions": notif.actions, "actions": notif.actions,
"appIcon": notif.appIcon, "appIcon": notif.appIcon,
"appName": notif.appName, "appName": notif.appName,
@@ -52,11 +61,11 @@ Singleton {
} }
component NotifTimer: Timer { component NotifTimer: Timer {
required property int id required property int notificationId
interval: 5000 interval: 5000
running: true running: true
onTriggered: () => { onTriggered: () => {
root.timeoutNotification(id); root.timeoutNotification(notificationId);
destroy() destroy()
} }
} }
@@ -130,7 +139,7 @@ Singleton {
property int idOffset property int idOffset
signal initDone(); signal initDone();
signal notify(notification: var); signal notify(notification: var);
signal discard(id: var); signal discard(id: int);
signal discardAll(); signal discardAll();
signal timeout(id: var); signal timeout(id: var);
@@ -149,7 +158,7 @@ Singleton {
onNotification: (notification) => { onNotification: (notification) => {
notification.tracked = true notification.tracked = true
const newNotifObject = notifComponent.createObject(root, { const newNotifObject = notifComponent.createObject(root, {
"id": notification.id + root.idOffset, "notificationId": notification.id + root.idOffset,
"notification": notification, "notification": notification,
"time": Date.now(), "time": Date.now(),
}); });
@@ -159,7 +168,7 @@ Singleton {
if (!root.popupInhibited) { if (!root.popupInhibited) {
newNotifObject.popup = true; newNotifObject.popup = true;
newNotifObject.timer = notifTimerComponent.createObject(root, { newNotifObject.timer = notifTimerComponent.createObject(root, {
"id": newNotifObject.id, "notificationId": newNotifObject.notificationId,
"interval": notification.expireTimeout < 0 ? 5000 : notification.expireTimeout, "interval": notification.expireTimeout < 0 ? 5000 : notification.expireTimeout,
}); });
} }
@@ -171,7 +180,8 @@ Singleton {
} }
function discardNotification(id) { function discardNotification(id) {
const index = root.list.findIndex((notif) => notif.id === id); console.log("[Notifications] Discarding notification with ID: " + id);
const index = root.list.findIndex((notif) => notif.notificationId === id);
const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id); const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id);
if (index !== -1) { if (index !== -1) {
root.list.splice(index, 1); root.list.splice(index, 1);
@@ -181,7 +191,7 @@ Singleton {
if (notifServerIndex !== -1) { if (notifServerIndex !== -1) {
notifServer.trackedNotifications.values[notifServerIndex].dismiss() notifServer.trackedNotifications.values[notifServerIndex].dismiss()
} }
root.discard(id); root.discard(id); // Emit signal
} }
function discardAllNotifications() { function discardAllNotifications() {
@@ -195,7 +205,7 @@ Singleton {
} }
function timeoutNotification(id) { function timeoutNotification(id) {
const index = root.list.findIndex((notif) => notif.id === id); const index = root.list.findIndex((notif) => notif.notificationId === id);
if (root.list[index] != null) if (root.list[index] != null)
root.list[index].popup = false; root.list[index].popup = false;
root.timeout(id); root.timeout(id);
@@ -203,7 +213,7 @@ Singleton {
function timeoutAll() { function timeoutAll() {
root.popupList.forEach((notif) => { root.popupList.forEach((notif) => {
root.timeout(notif.id); root.timeout(notif.notificationId);
}) })
root.popupList.forEach((notif) => { root.popupList.forEach((notif) => {
notif.popup = false; notif.popup = false;
@@ -211,10 +221,13 @@ Singleton {
} }
function attemptInvokeAction(id, notifIdentifier) { function attemptInvokeAction(id, notifIdentifier) {
console.log("[Notifications] Attempting to invoke action with identifier: " + notifIdentifier + " for notification ID: " + id);
const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id); const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id);
console.log("Notification server index: " + notifServerIndex);
if (notifServerIndex !== -1) { if (notifServerIndex !== -1) {
const notifServerNotif = notifServer.trackedNotifications.values[notifServerIndex]; const notifServerNotif = notifServer.trackedNotifications.values[notifServerIndex];
const action = notifServerNotif.actions.find((action) => action.identifier === notifIdentifier); const action = notifServerNotif.actions.find((action) => action.identifier === notifIdentifier);
console.log("Action found: " + JSON.stringify(action));
action.invoke() action.invoke()
} }
else { else {
@@ -242,7 +255,7 @@ Singleton {
const fileContents = notifFileView.text() const fileContents = notifFileView.text()
root.list = JSON.parse(fileContents).map((notif) => { root.list = JSON.parse(fileContents).map((notif) => {
return notifComponent.createObject(root, { return notifComponent.createObject(root, {
"id": notif.id, "notificationId": notif.notificationId,
"actions": [], // Notification actions are meaningless if they're not tracked by the server or the sender is dead "actions": [], // Notification actions are meaningless if they're not tracked by the server or the sender is dead
"appIcon": notif.appIcon, "appIcon": notif.appIcon,
"appName": notif.appName, "appName": notif.appName,
@@ -253,10 +266,10 @@ Singleton {
"urgency": notif.urgency, "urgency": notif.urgency,
}); });
}); });
// Find largest id // Find largest notificationId
let maxId = 0 let maxId = 0
root.list.forEach((notif) => { root.list.forEach((notif) => {
maxId = Math.max(maxId, notif.id) maxId = Math.max(maxId, notif.notificationId)
}) })
console.log("[Notifications] File loaded") console.log("[Notifications] File loaded")
+4 -4
View File
@@ -7,18 +7,18 @@
{ {
"label" : "hibernate", "label" : "hibernate",
"action" : "systemctl hibernate || loginctl hibernate", "action" : "systemctl hibernate || loginctl hibernate",
"text" : "save", "text" : "downloading",
"keybind" : "h" "keybind" : "h"
} }
{ {
"label" : "logout", "label" : "logout",
"action" : "pkill Hyprland || pkill sway || pkill niri || loginctl terminate-user $USER", "action" : "hyprctl clients -j | jq -r '.[].pid' | xargs kill; pkill Hyprland || pkill sway || pkill niri || loginctl terminate-user $USER",
"text" : "logout", "text" : "logout",
"keybind" : "e" "keybind" : "e"
} }
{ {
"label" : "shutdown", "label" : "shutdown",
"action" : "systemctl poweroff || loginctl poweroff", "action" : "hyprctl clients -j | jq -r '.[].pid' | xargs kill; systemctl poweroff || loginctl poweroff",
"text" : "power_settings_new", "text" : "power_settings_new",
"keybind" : "s" "keybind" : "s"
} }
@@ -30,7 +30,7 @@
} }
{ {
"label" : "reboot", "label" : "reboot",
"action" : "systemctl reboot || loginctl reboot", "action" : "hyprctl clients -j | jq -r '.[].pid' | xargs kill; systemctl reboot || loginctl reboot",
"text" : "restart_alt", "text" : "restart_alt",
"keybind" : "r" "keybind" : "r"
} }
+9
View File
@@ -1,4 +1,13 @@
# Contributing # Contributing
- Please understand that dotfiles are after all personal. I can accept features I do not personally want, but in that case I will ask you to make it configurable/optionally loaded - Please understand that dotfiles are after all personal. I can accept features I do not personally want, but in that case I will ask you to make it configurable/optionally loaded
- If you add new stuff, it's a good idea to ask me first to not waste your work - If you add new stuff, it's a good idea to ask me first to not waste your work
- Please make multiple PRs if you have many features - Please make multiple PRs if you have many features
# Technical steps
_Complete steps, might not be necessary depending on what you change_
- Install the dotfiles (if you don't wanna replace your stuff completely, do it on a new user)
- For Quickshell: `touch ~/.config/quickshell/ii/.qmlls.ini` for proper LSP support
- Make changes, copy changes to a fork, PR
+5 -18
View File
@@ -26,25 +26,12 @@
- **Transparent installation**: Every command is shown before it's run - **Transparent installation**: Every command is shown before it's run
</details> </details>
<details> <details>
<summary>Instructions</summary> <summary>Installation instructions</summary>
- **Prerequisite**: Your system works. That's it. You don't have to reinstall your system! - See the [Wiki](https://end-4.github.io/dots-hyprland-wiki/en/ii-qs/01setup/)
- **Automatic**, but guided and transparent, installation for Arch(-based) Linux: - **Default keybinds**: Should be somewhat familiar to Windows or GNOME users.
```bash - `Super`+`/` = keybind list
bash <(curl -s "https://end-4.github.io/dots-hyprland-wiki/setup.sh") - `Super`+`Enter` = terminal
```
If you are using fish shell (non-posix-compliant shell) then:
```bash
bash -c "$(curl -s https://end-4.github.io/dots-hyprland-wiki/setup.sh)"
```
- **Manual** installation, other distros and more:
- See the [Wiki](https://end-4.github.io/dots-hyprland-wiki/en/ii-qs/01setup/)
- **Default keybinds**: Should be somewhat familiar if you've used Windows or GNOME.
- For a list, hit `Super`+`/`
- For a terminal, hit `Super`+`Enter`
</details> </details>