diff --git a/.github/README.md b/.github/README.md
index 12d645adf..2020ab82b 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -78,7 +78,7 @@ Widget system: Quickshell | Support: Yes
| AI, settings app | Some widgets |
|:---|:---------------|
-|
|
|
+|
|
|
| Window management | Weeb power |
|
|
|
diff --git a/.gitignore b/.gitignore
index bc6ebed73..cef4d7aab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ __pycache__/
*.py[cod]
dots/.config/quickshell/ii/.qmlls.ini
.update-lock
+/os-release
diff --git a/diagnose b/diagnose
index 408b5e896..a686cab5e 100755
--- a/diagnose
+++ b/diagnose
@@ -58,6 +58,9 @@ ii_check_venv() {
ii_check_quickshell_version() {
pacman -Q | grep -E 'quickshell|qt6-base'
}
+ii_check_PKGBUILD_version() {
+ pacman -Q | grep '^illogical-impulse-'
+}
e "Checking git repo info"
x git remote get-url origin
@@ -88,6 +91,7 @@ x ls -l ~/.local/state/quickshell/.venv
e "Checking versions"
x Hyprland --version
x ii_check_quickshell_version
+x ii_check_PKGBUILD_version
e "Finished. Output saved as \"$output_file\"."
if ! command -v curl 2>&1 >>/dev/null ;then echo "\"curl\" not found, pastebin upload unavailable.";exit;fi
diff --git a/dots-extra/vianix/README.md b/dots-extra/vianix/README.md
new file mode 100644
index 000000000..5f77637f9
--- /dev/null
+++ b/dots-extra/vianix/README.md
@@ -0,0 +1 @@
+This folder contains tweakd configs when --via-nix is specified.
diff --git a/dots-extra/vianix/hypridle.conf b/dots-extra/vianix/hypridle.conf
new file mode 100644
index 000000000..6f1858607
--- /dev/null
+++ b/dots-extra/vianix/hypridle.conf
@@ -0,0 +1,26 @@
+$lock_cmd = swaylock
+# $lock_cmd = pidof hyprlock || hyprlock
+$suspend_cmd = systemctl suspend || loginctl suspend
+
+general {
+ lock_cmd = $lock_cmd
+ before_sleep_cmd = loginctl lock-session
+ after_sleep_cmd = hyprctl dispatch global quickshell:lockFocus
+ inhibit_sleep = 3
+}
+
+listener {
+ timeout = 300 # 5mins
+ on-timeout = loginctl lock-session
+}
+
+listener {
+ timeout = 600 # 10mins
+ on-timeout = hyprctl dispatch dpms off
+ on-resume = hyprctl dispatch dpms on
+}
+
+listener {
+ timeout = 900 # 15mins
+ on-timeout = $suspend_cmd
+}
diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf
index 263d5048d..b77166eb2 100644
--- a/dots/.config/hypr/hyprland/keybinds.conf
+++ b/dots/.config/hypr/hyprland/keybinds.conf
@@ -41,7 +41,7 @@ bind = Shift+Super+Alt, Slash, exec, qs -p ~/.config/quickshell/$qsConfig/welcom
bindle=, XF86MonBrightnessUp, exec, qs -c $qsConfig ipc call brightness increment || brightnessctl s 5%+ # [hidden]
bindle=, XF86MonBrightnessDown, exec, qs -c $qsConfig ipc call brightness decrement || brightnessctl s 5%- # [hidden]
-bindle=, XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%+ # [hidden]
+bindle=, XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%+ -l 1.5# [hidden]
bindle=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%- # [hidden]
bindl = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_SINK@ toggle # [hidden]
diff --git a/dots/.config/hypr/hyprland/rules.conf b/dots/.config/hypr/hyprland/rules.conf
index 4891ee854..7eb985c94 100644
--- a/dots/.config/hypr/hyprland/rules.conf
+++ b/dots/.config/hypr/hyprland/rules.conf
@@ -144,6 +144,7 @@ layerrule = animation slide bottom, quickshell:osk
layerrule = noanim, quickshell:polkit
layerrule = xray 0, quickshell:popup # No weird color for bar tooltips (this in theory should suffice)
layerrule = ignorealpha 1, quickshell:popup # No weird color for bar tooltips (but somehow this is necessary)
+layerrule = ignorealpha 1, quickshell:mediaControls # Same as above
layerrule = noanim, quickshell:regionSelector
layerrule = noanim, quickshell:screenshot
layerrule = blur, quickshell:session
diff --git a/dots/.config/hypr/hyprland/scripts/start_geoclue_agent.sh b/dots/.config/hypr/hyprland/scripts/start_geoclue_agent.sh
index e464d0531..b4b8fa14d 100755
--- a/dots/.config/hypr/hyprland/scripts/start_geoclue_agent.sh
+++ b/dots/.config/hypr/hyprland/scripts/start_geoclue_agent.sh
@@ -7,13 +7,16 @@ if pgrep -f 'geoclue-2.0/demos/agent' > /dev/null; then
fi
# List of known possible GeoClue agent paths
-AGENT_PATHS="
-/usr/libexec/geoclue-2.0/demos/agent
-/usr/lib/geoclue-2.0/demos/agent
-"
+AGENT_PATHS=(
+ /usr/libexec/geoclue-2.0/demos/agent
+ /usr/lib/geoclue-2.0/demos/agent
+ "$HOME/.nix-profile/libexec/geoclue-2.0/demos/agent"
+ "$HOME/.nix-profile/lib/geoclue-2.0/demos/agent"
+ /run/current-system/sw/libexec/geoclue-2.0/demos/agent
+)
# Find the first valid agent path
-for path in $AGENT_PATHS; do
+for path in "${AGENT_PATHS[@]}"; do
if [ -x "$path" ]; then
echo "Starting GeoClue agent from: $path"
"$path" & # starts in the background
diff --git a/dots/.config/quickshell/ii/modules/background/Background.qml b/dots/.config/quickshell/ii/modules/background/Background.qml
index 9209450be..f36cf3590 100644
--- a/dots/.config/quickshell/ii/modules/background/Background.qml
+++ b/dots/.config/quickshell/ii/modules/background/Background.qml
@@ -334,7 +334,6 @@ Variants {
font {
pixelSize: Appearance.font.pixelSize.normal
weight: 350
- italic: true
}
color: bgRoot.colText
style: Text.Raised
diff --git a/dots/.config/quickshell/ii/modules/bar/Workspaces.qml b/dots/.config/quickshell/ii/modules/bar/Workspaces.qml
index f1da2dab3..f0a61ef23 100644
--- a/dots/.config/quickshell/ii/modules/bar/Workspaces.qml
+++ b/dots/.config/quickshell/ii/modules/bar/Workspaces.qml
@@ -1,6 +1,7 @@
import qs
import qs.services
import qs.modules.common
+import qs.modules.common.models
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
@@ -163,12 +164,12 @@ Item {
horizontalCenter: vertical ? parent.horizontalCenter : undefined
}
- // idx1 is the "leading" indicator position, idx2 is the "following" one
- // The former animates faster than the latter, see the NumberAnimations below
- property real idx1: workspaceIndexInGroup
- property real idx2: workspaceIndexInGroup
- property real indicatorPosition: Math.min(idx1, idx2) * workspaceButtonWidth + root.activeWorkspaceMargin
- property real indicatorLength: Math.abs(idx1 - idx2) * workspaceButtonWidth + workspaceButtonWidth - root.activeWorkspaceMargin * 2
+ AnimatedTabIndexPair {
+ id: idxPair
+ index: root.workspaceIndexInGroup
+ }
+ property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * workspaceButtonWidth + root.activeWorkspaceMargin
+ property real indicatorLength: Math.abs(idxPair.idx1 - idxPair.idx2) * workspaceButtonWidth + workspaceButtonWidth - root.activeWorkspaceMargin * 2
property real indicatorThickness: workspaceButtonWidth - root.activeWorkspaceMargin * 2
x: root.vertical ? null : indicatorPosition
@@ -176,18 +177,6 @@ Item {
y: root.vertical ? indicatorPosition : null
implicitHeight: root.vertical ? indicatorLength : indicatorThickness
- Behavior on idx1 {
- NumberAnimation {
- duration: 100
- easing.type: Easing.OutSine
- }
- }
- Behavior on idx2 {
- NumberAnimation {
- duration: 300
- easing.type: Easing.OutSine
- }
- }
}
// Workspaces - numbers
diff --git a/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml b/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml
index fb9e55367..f44efcb3e 100644
--- a/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml
+++ b/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml
@@ -31,7 +31,6 @@ Scope { // Scope
sourceComponent: PanelWindow { // Window
id: cheatsheetRoot
visible: cheatsheetLoader.active
- property int selectedTab: 0
anchors {
top: true
@@ -76,7 +75,7 @@ Scope { // Scope
border.width: 1
border.color: Appearance.colors.colLayer0Border
radius: Appearance.rounding.windowRounding
- property real padding: 30
+ property real padding: 20
implicitWidth: cheatsheetColumnLayout.implicitWidth + padding * 2
implicitHeight: cheatsheetColumnLayout.implicitHeight + padding * 2
@@ -86,16 +85,16 @@ Scope { // Scope
}
if (event.modifiers === Qt.ControlModifier) {
if (event.key === Qt.Key_PageDown) {
- cheatsheetRoot.selectedTab = Math.min(cheatsheetRoot.selectedTab + 1, root.tabButtonList.length - 1);
+ tabBar.incrementCurrentIndex();
event.accepted = true;
} else if (event.key === Qt.Key_PageUp) {
- cheatsheetRoot.selectedTab = Math.max(cheatsheetRoot.selectedTab - 1, 0);
+ tabBar.decrementCurrentIndex();
event.accepted = true;
} else if (event.key === Qt.Key_Tab) {
- cheatsheetRoot.selectedTab = (cheatsheetRoot.selectedTab + 1) % root.tabButtonList.length;
+ tabBar.setCurrentIndex((tabBar.currentIndex + 1) % root.tabButtonList.length);
event.accepted = true;
} else if (event.key === Qt.Key_Backtab) {
- cheatsheetRoot.selectedTab = (cheatsheetRoot.selectedTab - 1 + root.tabButtonList.length) % root.tabButtonList.length;
+ tabBar.setCurrentIndex((tabBar.currentIndex - 1 + root.tabButtonList.length) % root.tabButtonList.length);
event.accepted = true;
}
}
@@ -129,23 +128,15 @@ Scope { // Scope
ColumnLayout { // Real content
id: cheatsheetColumnLayout
anchors.centerIn: parent
- spacing: 20
+ spacing: 10
- StyledText {
- id: cheatsheetTitle
+ Toolbar {
Layout.alignment: Qt.AlignHCenter
- font {
- family: Appearance.font.family.title
- pixelSize: Appearance.font.pixelSize.title
- variableAxes: Appearance.font.variableAxes.title
- }
- text: Translation.tr("Cheat sheet")
- }
- PrimaryTabBar { // Tab strip
- id: tabBar
- tabButtonList: root.tabButtonList
- Synchronizer on currentIndex {
- property alias source: cheatsheetRoot.selectedTab
+ enableShadow: false
+ ToolbarTabBar {
+ id: tabBar
+ tabButtonList: root.tabButtonList
+ currentIndex: swipeView.currentIndex
}
}
@@ -154,26 +145,11 @@ Scope { // Scope
Layout.topMargin: 5
Layout.fillWidth: true
Layout.fillHeight: true
+ currentIndex: tabBar.currentIndex
spacing: 10
- Behavior on implicitWidth {
- id: contentWidthBehavior
- enabled: false
- animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
- }
- Behavior on implicitHeight {
- id: contentHeightBehavior
- enabled: false
- animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
- }
-
- currentIndex: cheatsheetRoot.selectedTab
- onCurrentIndexChanged: {
- contentWidthBehavior.enabled = true;
- contentHeightBehavior.enabled = true;
- tabBar.enableIndicatorAnimation = true;
- cheatsheetRoot.selectedTab = currentIndex;
- }
+ implicitWidth: Math.max.apply(null, contentChildren.map(child => child.implicitWidth || 0))
+ implicitHeight: Math.max.apply(null, contentChildren.map(child => child.implicitHeight || 0))
clip: true
layer.enabled: true
diff --git a/dots/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml b/dots/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml
index 158e707d3..6262ed77a 100644
--- a/dots/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml
+++ b/dots/.config/quickshell/ii/modules/cheatsheet/CheatsheetPeriodicTable.qml
@@ -11,6 +11,7 @@ Item {
Column {
id: mainLayout
+ anchors.centerIn: parent
spacing: root.spacing
Repeater { // Main table rows
diff --git a/dots/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml b/dots/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml
index d84abedfd..e05b76a9c 100644
--- a/dots/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml
+++ b/dots/.config/quickshell/ii/modules/cheatsheet/ElementTile.qml
@@ -7,8 +7,8 @@ RippleButton {
id: root
required property var element
opacity: element.type != "empty" ? 1 : 0
- implicitHeight: 60
- implicitWidth: 60
+ implicitHeight: 70
+ implicitWidth: 70
colBackground: Appearance.colors.colLayer2
buttonRadius: Appearance.rounding.small
diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml
index c4af0a850..766033e47 100644
--- a/dots/.config/quickshell/ii/modules/common/Config.qml
+++ b/dots/.config/quickshell/ii/modules/common/Config.qml
@@ -373,6 +373,7 @@ Singleton {
property real scale: 0.18 // Relative to screen size
property real rows: 2
property real columns: 5
+ property bool centerIcons: true
}
property JsonObject regionSelector: JsonObject {
diff --git a/dots/.config/quickshell/ii/modules/common/models/AnimatedTabIndexPair.qml b/dots/.config/quickshell/ii/modules/common/models/AnimatedTabIndexPair.qml
new file mode 100644
index 000000000..c18e9ccf2
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/AnimatedTabIndexPair.qml
@@ -0,0 +1,26 @@
+import QtQuick
+
+// idx1 is the "leading" indicator position, idx2 is the "following" one
+// The former animates faster than the latter, see the NumberAnimations below
+QtObject {
+ id: root
+ required property int index
+
+ property real idx1: index
+ property real idx2: index
+ property int idx1Duration: 100
+ property int idx2Duration: 300
+
+ Behavior on idx1 {
+ NumberAnimation {
+ duration: root.idx1Duration
+ easing.type: Easing.OutSine
+ }
+ }
+ Behavior on idx2 {
+ NumberAnimation {
+ duration: root.idx2Duration
+ easing.type: Easing.OutSine
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/IconAndTextToolbarButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/IconAndTextToolbarButton.qml
index 45f90f8a1..875aec400 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/IconAndTextToolbarButton.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/IconAndTextToolbarButton.qml
@@ -13,7 +13,7 @@ ToolbarButton {
contentItem: Row {
anchors.centerIn: parent
- spacing: 6
+ spacing: 4
MaterialSymbol {
anchors.verticalCenter: parent.verticalCenter
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml b/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml
deleted file mode 100644
index 474bdc591..000000000
--- a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml
+++ /dev/null
@@ -1,95 +0,0 @@
-import qs.modules.common
-import qs.services
-import QtQuick
-import QtQuick.Controls
-import QtQuick.Layouts
-import Qt.labs.synchronizer
-
-ColumnLayout {
- id: root
- spacing: 0
- required property var tabButtonList // Something like [{"icon": "notifications", "name": Translation.tr("Notifications")}, {"icon": "volume_up", "name": Translation.tr("Volume mixer")}]
- property int currentIndex
- property bool enableIndicatorAnimation: false
- property color colIndicator: Appearance?.colors.colPrimary ?? "#65558F"
- property color colBorder: Appearance?.m3colors.m3outlineVariant ?? "#C6C6D0"
-
- onCurrentIndexChanged: {
- enableIndicatorAnimation = true
- }
-
- property bool centerTabBar: parent.width > 500
- Layout.fillWidth: !centerTabBar
- Layout.alignment: Qt.AlignHCenter
- implicitWidth: Math.max(tabBar.implicitWidth, 600)
-
- TabBar {
- id: tabBar
- Layout.fillWidth: true
- Synchronizer on currentIndex {
- property alias source: root.currentIndex
- }
-
- background: Item {
- WheelHandler {
- onWheel: (event) => {
- if (event.angleDelta.y < 0)
- tabBar.currentIndex = Math.min(tabBar.currentIndex + 1, root.tabButtonList.length - 1)
- else if (event.angleDelta.y > 0)
- tabBar.currentIndex = Math.max(tabBar.currentIndex - 1, 0)
- }
- acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
- }
- }
-
- Repeater {
- model: root.tabButtonList
- delegate: PrimaryTabButton {
- selected: (index == root.currentIndex)
- buttonText: modelData.name
- buttonIcon: modelData.icon
- minimumWidth: 160
- onClicked: root.currentIndex = index
- }
- }
- }
-
- Item { // Tab indicator
- id: tabIndicator
- Layout.fillWidth: true
- height: 3
-
- Rectangle {
- id: indicator
- property int tabCount: root.tabButtonList.length
- property real fullTabSize: root.width / tabCount;
- property real targetWidth: tabBar.contentItem?.children[0]?.children[tabBar.currentIndex]?.tabContentWidth ?? 0
-
- implicitWidth: targetWidth
- anchors {
- top: parent.top
- bottom: parent.bottom
- }
-
- x: tabBar.currentIndex * fullTabSize + (fullTabSize - targetWidth) / 2
-
- color: root.colIndicator
- radius: Appearance?.rounding.full ?? 9999
-
- Behavior on x {
- animation: Appearance?.animation.elementMove.numberAnimation.createObject(this)
- }
-
- Behavior on implicitWidth {
- animation: Appearance?.animation.elementMove.numberAnimation.createObject(this)
- }
- }
- }
-
- Rectangle { // Tabbar bottom border
- id: tabBarBottomBorder
- Layout.fillWidth: true
- implicitHeight: 1
- color: root.colBorder
- }
-}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabButton.qml
deleted file mode 100644
index bedcc2d92..000000000
--- a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabButton.qml
+++ /dev/null
@@ -1,172 +0,0 @@
-import qs.modules.common
-import qs.modules.common.widgets
-import qs.modules.common.functions
-import Qt5Compat.GraphicalEffects
-import QtQuick
-import QtQuick.Controls
-import QtQuick.Layouts
-
-TabButton {
- id: button
- property string buttonText
- property string buttonIcon
- property real minimumWidth: 110
- property bool selected: false
- property int tabContentWidth: contentItem.children[0].implicitWidth
- property int rippleDuration: 1200
- height: buttonBackground.height
- implicitWidth: Math.max(tabContentWidth, buttonBackground.implicitWidth, minimumWidth)
-
- property color colBackground: ColorUtils.transparentize(Appearance?.colors.colLayer1Hover, 1) || "transparent"
- property color colBackgroundHover: Appearance?.colors.colLayer1Hover ?? "#E5DFED"
- property color colRipple: Appearance?.colors.colLayer1Active ?? "#D6CEE2"
- property color colActive: Appearance?.colors.colPrimary ?? "#65558F"
- property color colInactive: Appearance?.colors.colOnLayer1 ?? "#45464F"
-
- component RippleAnim: NumberAnimation {
- duration: rippleDuration
- easing.type: Appearance?.animation.elementMoveEnter.type
- easing.bezierCurve: Appearance?.animationCurves.standardDecel
- }
-
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- onPressed: (event) => {
- button.click() // Because the MouseArea already consumed the event
- const {x,y} = event
- const stateY = buttonBackground.y;
- rippleAnim.x = x;
- rippleAnim.y = y - stateY;
-
- const dist = (ox,oy) => ox*ox + oy*oy
- const stateEndY = stateY + buttonBackground.height
- rippleAnim.radius = Math.sqrt(Math.max(dist(0, stateY), dist(0, stateEndY), dist(width, stateY), dist(width, stateEndY)))
-
- rippleFadeAnim.complete();
- rippleAnim.restart();
- }
- onReleased: (event) => {
- rippleFadeAnim.restart();
- }
- }
-
- RippleAnim {
- id: rippleFadeAnim
- duration: rippleDuration * 2
- target: ripple
- property: "opacity"
- to: 0
- }
-
- SequentialAnimation {
- id: rippleAnim
-
- property real x
- property real y
- property real radius
-
- PropertyAction {
- target: ripple
- property: "x"
- value: rippleAnim.x
- }
- PropertyAction {
- target: ripple
- property: "y"
- value: rippleAnim.y
- }
- PropertyAction {
- target: ripple
- property: "opacity"
- value: 1
- }
- ParallelAnimation {
- RippleAnim {
- target: ripple
- properties: "implicitWidth,implicitHeight"
- from: 0
- to: rippleAnim.radius * 2
- }
- }
- }
-
- background: Rectangle {
- id: buttonBackground
- radius: Appearance?.rounding.small
- implicitHeight: 50
- color: (button.hovered ? button.colBackgroundHover : button.colBackground)
- layer.enabled: true
- layer.effect: OpacityMask {
- maskSource: Rectangle {
- width: buttonBackground.width
- height: buttonBackground.height
- radius: buttonBackground.radius
- }
- }
-
- Behavior on color {
- animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
- }
-
- Item {
- id: ripple
- width: ripple.implicitWidth
- height: ripple.implicitHeight
- opacity: 0
-
- property real implicitWidth: 0
- property real implicitHeight: 0
- visible: width > 0 && height > 0
-
- Behavior on opacity {
- animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
- }
-
- RadialGradient {
- anchors.fill: parent
- gradient: Gradient {
- GradientStop { position: 0.0; color: button.colRipple }
- GradientStop { position: 0.3; color: button.colRipple }
- GradientStop { position: 0.5 ; color: Qt.rgba(button.colRipple.r, button.colRipple.g, button.colRipple.b, 0) }
- }
- }
-
- transform: Translate {
- x: -ripple.width / 2
- y: -ripple.height / 2
- }
- }
- }
-
- contentItem: Item {
- anchors.centerIn: buttonBackground
- ColumnLayout {
- anchors.centerIn: parent
- spacing: 0
- MaterialSymbol {
- visible: buttonIcon?.length > 0
- Layout.alignment: Qt.AlignHCenter
- horizontalAlignment: Text.AlignHCenter
- text: buttonIcon
- iconSize: Appearance?.font.pixelSize.hugeass ?? 25
- fill: selected ? 1 : 0
- color: selected ? button.colActive : button.colInactive
- Behavior on color {
- animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
- }
- }
- StyledText {
- id: buttonTextWidget
- Layout.alignment: Qt.AlignHCenter
- horizontalAlignment: Text.AlignHCenter
- font.pixelSize: Appearance?.font.pixelSize.small
- color: selected ? button.colActive : button.colInactive
- text: buttonText
- Behavior on color {
- animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml b/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml
index 85112160f..51348c4fa 100644
--- a/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml
+++ b/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml
@@ -10,6 +10,7 @@ import qs.modules.common.widgets
Item {
id: root
+ property bool enableShadow: true
property real padding: 8
property alias colBackground: background.color
property alias spacing: toolbarLayout.spacing
@@ -18,15 +19,20 @@ Item {
implicitHeight: background.implicitHeight
property alias radius: background.radius
- StyledRectangularShadow {
- target: background
+ Loader {
+ active: root.enableShadow
+ anchors.fill: background
+ sourceComponent: StyledRectangularShadow {
+ target: background
+ anchors.fill: undefined
+ }
}
Rectangle {
id: background
anchors.fill: parent
color: Appearance.m3colors.m3surfaceContainer
- implicitHeight: Math.max(toolbarLayout.implicitHeight + root.padding * 2, 56)
+ implicitHeight: 56
implicitWidth: toolbarLayout.implicitWidth + root.padding * 2
radius: height / 2
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabBar.qml b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabBar.qml
new file mode 100644
index 000000000..4d4d56335
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabBar.qml
@@ -0,0 +1,103 @@
+pragma ComponentBehavior: Bound
+import qs.modules.common
+import qs.modules.common.models
+import qs.services
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Qt.labs.synchronizer
+
+Item {
+ id: root
+ property alias currentIndex: tabBar.currentIndex
+ required property var tabButtonList
+
+ function incrementCurrentIndex() {
+ tabBar.incrementCurrentIndex()
+ }
+ function decrementCurrentIndex() {
+ tabBar.decrementCurrentIndex()
+ }
+ function setCurrentIndex(index) {
+ tabBar.setCurrentIndex(index)
+ }
+
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+ implicitWidth: contentItem.implicitWidth
+ implicitHeight: 40
+
+ Row {
+ id: contentItem
+ z: 1
+ anchors.centerIn: parent
+ spacing: 4
+
+ Repeater {
+ model: root.tabButtonList
+ delegate: ToolbarTabButton {
+ required property int index
+ required property var modelData
+ current: index == root.currentIndex
+ text: modelData.name
+ materialSymbol: modelData.icon
+ onClicked: {
+ root.setCurrentIndex(index)
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: activeIndicator
+ z: 0
+ color: Appearance.colors.colSecondaryContainer
+ implicitWidth: contentItem.children[root.currentIndex]?.implicitWidth ?? 0
+ implicitHeight: contentItem.children[root.currentIndex]?.implicitHeight ?? 0
+ radius: height / 2
+ // Animation
+ property Item targetItem: contentItem.children[root.currentIndex]
+ AnimatedTabIndexPair {
+ id: leftBound
+ idx1Duration: 50
+ idx2Duration: 200
+ index: activeIndicator.targetItem.x
+ }
+ AnimatedTabIndexPair {
+ id: rightBound
+ idx1Duration: 50
+ idx2Duration: 200
+ index: activeIndicator.targetItem.x + activeIndicator.targetItem.width
+ }
+ x: Math.min(leftBound.idx1, leftBound.idx2)
+ width: Math.max(rightBound.idx1, rightBound.idx2) - x
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ z: 2
+ acceptedButtons: Qt.NoButton
+ cursorShape: Qt.PointingHandCursor
+ onWheel: (event) => {
+ if (event.angleDelta.y < 0) {
+ root.incrementCurrentIndex();
+ }
+ else {
+ root.decrementCurrentIndex();
+ }
+ }
+ }
+
+ // TabBar doesn't allow tabs to be of different sizes. Literally unusable.
+ // We use it only for the logic and draw stuff manually
+ TabBar {
+ id: tabBar
+ z: -1
+ background: null
+ Repeater { // This is to fool the TabBar that it has tabs so it does the indices properly
+ model: root.tabButtonList.length
+ delegate: TabButton {
+ background: null
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabButton.qml
new file mode 100644
index 000000000..e53518875
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabButton.qml
@@ -0,0 +1,40 @@
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.modules.common.functions
+import Qt5Compat.GraphicalEffects
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+RippleButton {
+ id: root
+ required property string materialSymbol
+ required property bool current
+ horizontalPadding: 10
+
+ implicitHeight: 40
+ implicitWidth: implicitContentWidth + horizontalPadding * 2
+ buttonRadius: height / 2
+
+ colBackground: ColorUtils.transparentize(Appearance.colors.colSurfaceContainer)
+ colBackgroundHover: ColorUtils.transparentize(Appearance.colors.colOnSurface, current ? 1 : 0.95)
+ colRipple: ColorUtils.transparentize(Appearance.colors.colOnSurface, 0.95)
+
+ contentItem: Row {
+ id: contentRow
+ anchors.centerIn: parent
+ spacing: 6
+
+ MaterialSymbol {
+ id: icon
+ anchors.verticalCenter: parent.verticalCenter
+ iconSize: 22
+ text: root.materialSymbol
+ }
+ StyledText {
+ id: label
+ anchors.verticalCenter: parent.verticalCenter
+ text: root.text
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/lock/Lock.qml b/dots/.config/quickshell/ii/modules/lock/Lock.qml
index ead478bdc..e5557425b 100644
--- a/dots/.config/quickshell/ii/modules/lock/Lock.qml
+++ b/dots/.config/quickshell/ii/modules/lock/Lock.qml
@@ -13,10 +13,16 @@ import Quickshell.Hyprland
Scope {
id: root
+ Process {
+ id: unlockKeyringProc
+ onExited: (exitCode, exitStatus) => {
+ KeyringStorage.fetchKeyringData();
+ }
+ }
function unlockKeyring() {
- Quickshell.execDetached({
+ unlockKeyringProc.exec({
environment: ({
- UNLOCK_PASSWORD: root.currentText
+ "UNLOCK_PASSWORD": lockContext.currentText
}),
command: ["bash", "-c", Quickshell.shellPath("scripts/keyring/unlock.sh")]
})
@@ -24,7 +30,7 @@ Scope {
property var windowData: []
function saveWindowPositionAndTile() {
- Hyprland.dispatch(`keyword dwindle:pseudotile true`)
+ Quickshell.execDetached(["hyprctl", "keyword", "dwindle:pseudotile", "true"])
root.windowData = HyprlandData.windowList.filter(w => (w.floating && w.workspace.id === HyprlandData.activeWorkspace.id))
root.windowData.forEach(w => {
Hyprland.dispatch(`pseudo address:${w.address}`)
@@ -38,7 +44,7 @@ Scope {
Hyprland.dispatch(`movewindowpixel exact ${w.at[0]} ${w.at[1]}, address:${w.address}`)
Hyprland.dispatch(`pseudo address:${w.address}`)
})
- Hyprland.dispatch(`keyword dwindle:pseudotile false`)
+ Quickshell.execDetached(["hyprctl", "keyword", "dwindle:pseudotile", "false"])
}
// This stores all the information shared between the lock surfaces on each screen.
@@ -156,20 +162,24 @@ Scope {
}
}
+ function initIfReady() {
+ if (!Config.ready || !Persistent.ready) return;
+ if (Config.options.lock.launchOnStartup && Persistent.isNewHyprlandInstance) {
+ Hyprland.dispatch("global quickshell:lock")
+ } else {
+ KeyringStorage.fetchKeyringData();
+ }
+ }
Connections {
target: Config
function onReadyChanged() {
- if (Config.options.lock.launchOnStartup && Config.ready && Persistent.ready && Persistent.isNewHyprlandInstance) {
- Hyprland.dispatch("global quickshell:lock")
- }
+ root.initIfReady();
}
}
Connections {
target: Persistent
function onReadyChanged() {
- if (Config.options.lock.launchOnStartup && Config.ready && Persistent.ready && Persistent.isNewHyprlandInstance) {
- Hyprland.dispatch("global quickshell:lock")
- }
+ root.initIfReady();
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/lock/LockContext.qml b/dots/.config/quickshell/ii/modules/lock/LockContext.qml
index b3b7fece2..17893bb18 100644
--- a/dots/.config/quickshell/ii/modules/lock/LockContext.qml
+++ b/dots/.config/quickshell/ii/modules/lock/LockContext.qml
@@ -38,6 +38,7 @@ Scope {
root.resetTargetAction();
root.clearText();
root.unlockInProgress = false;
+ stopFingerPam();
}
Timer {
@@ -69,7 +70,9 @@ Scope {
}
function stopFingerPam() {
- fingerPam.abort();
+ if (fingerPam.running) {
+ fingerPam.abort();
+ }
}
Process {
diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml
index 4fc147de4..526a7d3b4 100644
--- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml
+++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml
@@ -119,6 +119,7 @@ MouseArea {
ToolbarTextField {
id: passwordBox
+ Layout.rightMargin: -Layout.leftMargin
placeholderText: GlobalStates.screenUnlockFailed ? Translation.tr("Incorrect password") : Translation.tr("Enter password")
// Style
@@ -156,11 +157,11 @@ MouseArea {
// Shake when wrong password
SequentialAnimation {
id: wrongPasswordShakeAnim
- NumberAnimation { target: passwordBox; property: "x"; to: -30; duration: 50 }
- NumberAnimation { target: passwordBox; property: "x"; to: 30; duration: 50 }
- NumberAnimation { target: passwordBox; property: "x"; to: -15; duration: 40 }
- NumberAnimation { target: passwordBox; property: "x"; to: 15; duration: 40 }
- NumberAnimation { target: passwordBox; property: "x"; to: 0; duration: 30 }
+ NumberAnimation { target: passwordBox; property: "Layout.leftMargin"; to: -30; duration: 50 }
+ NumberAnimation { target: passwordBox; property: "Layout.leftMargin"; to: 30; duration: 50 }
+ NumberAnimation { target: passwordBox; property: "Layout.leftMargin"; to: -15; duration: 40 }
+ NumberAnimation { target: passwordBox; property: "Layout.leftMargin"; to: 15; duration: 40 }
+ NumberAnimation { target: passwordBox; property: "Layout.leftMargin"; to: 0; duration: 30 }
}
Connections {
target: GlobalStates
diff --git a/dots/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml b/dots/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml
index 83bc10a22..f50769a51 100644
--- a/dots/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml
+++ b/dots/.config/quickshell/ii/modules/mediaControls/PlayerControl.qml
@@ -101,7 +101,7 @@ Item { // Player instance
id: background
anchors.fill: parent
anchors.margins: Appearance.sizes.elevationMargin
- color: blendedColors.colLayer0
+ color: ColorUtils.applyAlpha(blendedColors.colLayer0, 1)
radius: root.radius
layer.enabled: true
diff --git a/dots/.config/quickshell/ii/modules/overview/OverviewWindow.qml b/dots/.config/quickshell/ii/modules/overview/OverviewWindow.qml
index e531c4b8c..a05fde09b 100644
--- a/dots/.config/quickshell/ii/modules/overview/OverviewWindow.qml
+++ b/dots/.config/quickshell/ii/modules/overview/OverviewWindow.qml
@@ -43,10 +43,12 @@ Item { // Window
property bool hovered: false
property bool pressed: false
- property var iconToWindowRatio: 0.35
- property var xwaylandIndicatorToIconRatio: 0.35
- property var iconToWindowRatioCompact: 0.6
- property var iconPath: Quickshell.iconPath(AppSearch.guessIcon(windowData?.class), "image-missing")
+ property bool centerIcons: Config.options.overview.centerIcons
+ property real iconGapRatio: 0.06
+ property real iconToWindowRatio: centerIcons ? 0.35 : 0.15
+ property real xwaylandIndicatorToIconRatio: 0.35
+ property real iconToWindowRatioCompact: 0.6
+ property string iconPath: Quickshell.iconPath(AppSearch.guessIcon(windowData?.class), "image-missing")
property bool compactMode: Appearance.font.pixelSize.smaller * 4 > targetWindowHeight || Appearance.font.pixelSize.smaller * 4 > targetWindowWidth
property bool indicateXWayland: windowData?.xwayland ?? false
@@ -109,14 +111,20 @@ Item { // Window
Image {
id: windowIcon
- anchors.centerIn: parent
+ property real baseSize: Math.min(root.targetWindowWidth, root.targetWindowHeight)
+ anchors {
+ top: root.centerIcons ? undefined : parent.top
+ left: root.centerIcons ? undefined : parent.left
+ centerIn: root.centerIcons ? parent : undefined
+ margins: baseSize * root.iconGapRatio
+ }
property var iconSize: {
// console.log("-=-=-", root.toplevel.title, "-=-=-")
// console.log("Target window size:", targetWindowWidth, targetWindowHeight)
// console.log("Icon ratio:", root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio)
// console.log("Scale:", root.monitorData.scale)
// console.log("Final:", Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / root.monitorData.scale)
- return Math.min(root.targetWindowWidth, root.targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio);
+ return baseSize * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio);
}
// mipmap: true
Layout.alignment: Qt.AlignHCenter
diff --git a/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml b/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml
index d4e54ddda..63a3e8c7e 100644
--- a/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml
+++ b/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml
@@ -65,18 +65,16 @@ Toolbar {
}
}
- IconAndTextToolbarButton {
- iconText: "activity_zone"
- text: Translation.tr("Rect")
- toggled: root.selectionMode === RegionSelection.SelectionMode.RectCorners
- onClicked: root.selectionMode = RegionSelection.SelectionMode.RectCorners
- }
-
- IconAndTextToolbarButton {
- iconText: "gesture"
- text: Translation.tr("Circle")
- toggled: root.selectionMode === RegionSelection.SelectionMode.Circle
- onClicked: root.selectionMode = RegionSelection.SelectionMode.Circle
+ ToolbarTabBar {
+ id: tabBar
+ tabButtonList: [
+ {"icon": "activity_zone", "name": Translation.tr("Rect")},
+ {"icon": "gesture", "name": Translation.tr("Circle")}
+ ]
+ currentIndex: root.selectionMode === RegionSelection.SelectionMode.RectCorners ? 0 : 1
+ onCurrentIndexChanged: {
+ root.selectionMode = currentIndex === 0 ? RegionSelection.SelectionMode.RectCorners : RegionSelection.SelectionMode.Circle;
+ }
}
}
diff --git a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml
index 5ecce47ba..a0853cc89 100644
--- a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml
+++ b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml
@@ -17,7 +17,7 @@ PanelWindow {
color: "transparent"
WlrLayershell.namespace: "quickshell:regionSelector"
WlrLayershell.layer: WlrLayer.Overlay
- WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
+ WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
exclusionMode: ExclusionMode.Ignore
anchors {
left: true
diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml
index b1d51063b..90aa11030 100644
--- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml
+++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml
@@ -961,6 +961,14 @@ ContentPage {
Config.options.overview.enable = checked;
}
}
+ ConfigSwitch {
+ buttonIcon: "center_focus_strong"
+ text: Translation.tr("Center icons")
+ checked: Config.options.overview.centerIcons
+ onCheckedChanged: {
+ Config.options.overview.centerIcons = checked;
+ }
+ }
ConfigSpinBox {
icon: "loupe"
text: Translation.tr("Scale (%)")
diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml
index eff0483d3..e4ded1eeb 100644
--- a/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml
@@ -13,27 +13,28 @@ import Quickshell.Io
Item {
id: root
+ property real padding: 4
property var inputField: messageInputField
property string commandPrefix: "/"
property var suggestionQuery: ""
property var suggestionList: []
- onFocusChanged: (focus) => {
+ onFocusChanged: focus => {
if (focus) {
- root.inputField.forceActiveFocus()
+ root.inputField.forceActiveFocus();
}
}
- Keys.onPressed: (event) => {
- messageInputField.forceActiveFocus()
+ Keys.onPressed: event => {
+ messageInputField.forceActiveFocus();
if (event.modifiers === Qt.NoModifier) {
if (event.key === Qt.Key_PageUp) {
- messageListView.contentY = Math.max(0, messageListView.contentY - messageListView.height / 2)
- event.accepted = true
+ messageListView.contentY = Math.max(0, messageListView.contentY - messageListView.height / 2);
+ event.accepted = true;
} else if (event.key === Qt.Key_PageDown) {
- messageListView.contentY = Math.min(messageListView.contentHeight - messageListView.height / 2, messageListView.contentY + messageListView.height / 2)
- event.accepted = true
+ messageListView.contentY = Math.min(messageListView.contentHeight - messageListView.height / 2, messageListView.contentY + messageListView.height / 2);
+ event.accepted = true;
}
}
if ((event.modifiers & Qt.ControlModifier) && (event.modifiers & Qt.ShiftModifier) && event.key === Qt.Key_O) {
@@ -45,21 +46,21 @@ Item {
{
name: "attach",
description: Translation.tr("Attach a file. Only works with Gemini."),
- execute: (args) => {
+ execute: args => {
Ai.attachFile(args.join(" ").trim());
}
},
{
name: "model",
description: Translation.tr("Choose model"),
- execute: (args) => {
+ execute: args => {
Ai.setModel(args[0]);
}
},
{
name: "tool",
description: Translation.tr("Set the tool to use for the model."),
- execute: (args) => {
+ execute: args => {
// console.log(args)
if (args.length == 0 || args[0] == "get") {
Ai.addMessage(Translation.tr("Usage: %1tool TOOL_NAME").arg(root.commandPrefix), Ai.interfaceRole);
@@ -75,7 +76,7 @@ Item {
{
name: "prompt",
description: Translation.tr("Set the system prompt for the model."),
- execute: (args) => {
+ execute: args => {
if (args.length === 0 || args[0] === "get") {
Ai.printPrompt();
return;
@@ -86,9 +87,9 @@ Item {
{
name: "key",
description: Translation.tr("Set API key"),
- execute: (args) => {
+ execute: args => {
if (args[0] == "get") {
- Ai.printApiKey()
+ Ai.printApiKey();
} else {
Ai.setApiKey(args[0]);
}
@@ -97,25 +98,25 @@ Item {
{
name: "save",
description: Translation.tr("Save chat"),
- execute: (args) => {
- const joinedArgs = args.join(" ")
+ execute: args => {
+ const joinedArgs = args.join(" ");
if (joinedArgs.trim().length == 0) {
Ai.addMessage(Translation.tr("Usage: %1save CHAT_NAME").arg(root.commandPrefix), Ai.interfaceRole);
return;
}
- Ai.saveChat(joinedArgs)
+ Ai.saveChat(joinedArgs);
}
},
{
name: "load",
description: Translation.tr("Load chat"),
- execute: (args) => {
- const joinedArgs = args.join(" ")
+ execute: args => {
+ const joinedArgs = args.join(" ");
if (joinedArgs.trim().length == 0) {
Ai.addMessage(Translation.tr("Usage: %1load CHAT_NAME").arg(root.commandPrefix), Ai.interfaceRole);
return;
}
- Ai.loadChat(joinedArgs)
+ Ai.loadChat(joinedArgs);
}
},
{
@@ -128,10 +129,10 @@ Item {
{
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."),
- execute: (args) => {
+ execute: args => {
// console.log(args)
if (args.length == 0 || args[0] == "get") {
- Ai.printTemperature()
+ Ai.printTemperature();
} else {
const temp = parseFloat(args[0]);
Ai.setTemperature(temp);
@@ -191,8 +192,7 @@ Inline w/ double dollar signs: $$\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\p
Inline w/ backslash and square brackets \\[\\int_0^\\infty \\frac{1}{x^2} dx = \\infty\\]
Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
-`,
- Ai.interfaceRole);
+`, Ai.interfaceRole);
}
},
]
@@ -208,13 +208,12 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
} else {
Ai.addMessage(Translation.tr("Unknown command: ") + command, Ai.interfaceRole);
}
- }
- else {
+ } else {
Ai.sendUserMessage(inputText);
}
-
+
// Always scroll to bottom when user sends a message
- messageListView.positionViewAtEnd()
+ messageListView.positionViewAtEnd();
}
Process {
@@ -223,16 +222,14 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
property string imageDecodeFileName: "image"
property string imageDecodeFilePath: `${imageDecodePath}/${imageDecodeFileName}`
function handleEntry(entry: string) {
- imageDecodeFileName = parseInt(entry.match(/^(\d+)\t/)[1])
- decodeImageAndAttachProc.exec(["bash", "-c",
- `[ -f ${imageDecodeFilePath} ] || echo '${StringUtils.shellSingleQuoteEscape(entry)}' | ${Cliphist.cliphistBinary} decode > '${imageDecodeFilePath}'`
- ])
+ imageDecodeFileName = parseInt(entry.match(/^(\d+)\t/)[1]);
+ decodeImageAndAttachProc.exec(["bash", "-c", `[ -f ${imageDecodeFilePath} ] || echo '${StringUtils.shellSingleQuoteEscape(entry)}' | ${Cliphist.cliphistBinary} decode > '${imageDecodeFilePath}'`]);
}
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
Ai.attachFile(imageDecodeFilePath);
} else {
- console.error("[AiChat] Failed to decode image in clipboard content")
+ console.error("[AiChat] Failed to decode image in clipboard content");
}
}
}
@@ -278,37 +275,14 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
ColumnLayout {
id: columnLayout
- anchors.fill: parent
-
- RowLayout { // Status
- Layout.alignment: Qt.AlignHCenter
- spacing: 10
-
- StatusItem {
- icon: Ai.currentModelHasApiKey ? "key" : "key_off"
- statusText: ""
- description: Ai.currentModelHasApiKey ? Translation.tr("API key is set\nChange with /key YOUR_API_KEY") : Translation.tr("No API key\nSet it with /key YOUR_API_KEY")
- }
- StatusSeparator {}
- StatusItem {
- icon: "device_thermostat"
- statusText: Ai.temperature.toFixed(1)
- description: Translation.tr("Temperature\nChange with /temp VALUE")
- }
- StatusSeparator {
- visible: Ai.tokenCount.total > 0
- }
- StatusItem {
- visible: Ai.tokenCount.total > 0
- icon: "token"
- statusText: Ai.tokenCount.total
- description: Translation.tr("Total token count\nInput: %1\nOutput: %2")
- .arg(Ai.tokenCount.input)
- .arg(Ai.tokenCount.output)
- }
+ anchors {
+ fill: parent
+ margins: root.padding
}
+ spacing: root.padding
- Item { // Messages
+ Item {
+ // Messages
Layout.fillWidth: true
Layout.fillHeight: true
layer.enabled: true
@@ -320,6 +294,55 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
}
}
+ StyledRectangularShadow {
+ z: 1
+ target: statusBg
+ opacity: messageListView.atYBeginning ? 0 : 1
+ visible: opacity > 0
+ Behavior on opacity {
+ animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
+ }
+ }
+ Rectangle {
+ id: statusBg
+ z: 2
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ topMargin: 4
+ }
+ implicitWidth: statusRowLayout.implicitWidth + 10 * 2
+ implicitHeight: Math.max(statusRowLayout.implicitHeight, 38)
+ radius: Appearance.rounding.normal - root.padding
+ color: Appearance.colors.colLayer2
+ RowLayout {
+ id: statusRowLayout
+ anchors.centerIn: parent
+ spacing: 10
+
+ StatusItem {
+ icon: Ai.currentModelHasApiKey ? "key" : "key_off"
+ statusText: ""
+ description: Ai.currentModelHasApiKey ? Translation.tr("API key is set\nChange with /key YOUR_API_KEY") : Translation.tr("No API key\nSet it with /key YOUR_API_KEY")
+ }
+ StatusSeparator {}
+ StatusItem {
+ icon: "device_thermostat"
+ statusText: Ai.temperature.toFixed(1)
+ description: Translation.tr("Temperature\nChange with /temp VALUE")
+ }
+ StatusSeparator {
+ visible: Ai.tokenCount.total > 0
+ }
+ StatusItem {
+ visible: Ai.tokenCount.total > 0
+ icon: "token"
+ statusText: Ai.tokenCount.total
+ description: Translation.tr("Total token count\nInput: %1\nOutput: %2").arg(Ai.tokenCount.input).arg(Ai.tokenCount.output)
+ }
+ }
+ }
+
ScrollEdgeFade {
z: 1
target: messageListView
@@ -332,16 +355,20 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
anchors.fill: parent
spacing: 10
popin: false
+ topMargin: statusBg.implicitHeight + statusBg.anchors.topMargin * 2
touchpadScrollFactor: Config.options.interactions.scrolling.touchpadScrollFactor * 1.4
mouseScrollFactor: Config.options.interactions.scrolling.mouseScrollFactor * 1.4
property int lastResponseLength: 0
onContentHeightChanged: {
- if (atYEnd) Qt.callLater(positionViewAtEnd);
+ if (atYEnd)
+ Qt.callLater(positionViewAtEnd);
}
- onCountChanged: { // Auto-scroll when new messages are added
- if (atYEnd) Qt.callLater(positionViewAtEnd);
+ onCountChanged: {
+ // Auto-scroll when new messages are added
+ if (atYEnd)
+ Qt.callLater(positionViewAtEnd);
}
add: null // Prevent function calls from being janky
@@ -357,7 +384,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
required property int index
messageIndex: index
messageData: {
- Ai.messageByID[modelData]
+ Ai.messageByID[modelData];
}
messageInputField: root.inputField
}
@@ -393,8 +420,8 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
Repeater {
id: suggestionRepeater
model: {
- suggestions.selectedIndex = 0
- return root.suggestionList.slice(0, 10)
+ suggestions.selectedIndex = 0;
+ return root.suggestionList.slice(0, 10);
}
delegate: ApiCommandButton {
id: commandButton
@@ -413,7 +440,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
}
}
onClicked: {
- suggestions.acceptSuggestion(modelData.name)
+ suggestions.acceptSuggestion(modelData.name);
}
}
}
@@ -443,14 +470,10 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
id: inputWrapper
property real spacing: 5
Layout.fillWidth: true
- radius: Appearance.rounding.small
- color: Appearance.colors.colLayer1
- implicitHeight: Math.max(inputFieldRowLayout.implicitHeight + inputFieldRowLayout.anchors.topMargin
- + commandButtonsRow.implicitHeight + commandButtonsRow.anchors.bottomMargin + spacing, 45)
- + (attachedFileIndicator.implicitHeight + spacing + attachedFileIndicator.anchors.topMargin)
+ radius: Appearance.rounding.normal - root.padding
+ color: Appearance.colors.colLayer2
+ implicitHeight: Math.max(inputFieldRowLayout.implicitHeight + inputFieldRowLayout.anchors.topMargin + commandButtonsRow.implicitHeight + commandButtonsRow.anchors.bottomMargin + spacing, 45) + (attachedFileIndicator.implicitHeight + spacing + attachedFileIndicator.anchors.topMargin)
clip: true
- border.color: Appearance.colors.colOutlineVariant
- border.width: 1
Behavior on implicitHeight {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
@@ -488,121 +511,122 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
background: null
- onTextChanged: { // Handle suggestions
+ onTextChanged: {
+ // Handle suggestions
if (messageInputField.text.length === 0) {
- root.suggestionQuery = ""
- root.suggestionList = []
- return
+ root.suggestionQuery = "";
+ root.suggestionList = [];
+ return;
} else if (messageInputField.text.startsWith(`${root.commandPrefix}model`)) {
- root.suggestionQuery = messageInputField.text.split(" ")[1] ?? ""
+ root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const modelResults = Fuzzy.go(root.suggestionQuery, Ai.modelList.map(model => {
return {
name: Fuzzy.prepare(model),
- obj: model,
- }
+ obj: model
+ };
}), {
all: true,
key: "name"
- })
+ });
root.suggestionList = modelResults.map(model => {
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "model ") : ""}${model.target}`,
displayName: `${Ai.models[model.target].name}`,
- 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] ?? ""
+ root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.promptFiles.map(file => {
return {
name: Fuzzy.prepare(file),
- obj: 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: Translation.tr("Load prompt from %1").arg(file.target),
- }
- })
+ description: Translation.tr("Load prompt from %1").arg(file.target)
+ };
+ });
} else if (messageInputField.text.startsWith(`${root.commandPrefix}save`)) {
- root.suggestionQuery = messageInputField.text.split(" ")[1] ?? ""
+ root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.savedChats.map(file => {
return {
name: Fuzzy.prepare(file),
- obj: file,
- }
+ obj: file
+ };
}), {
all: true,
key: "name"
- })
+ });
root.suggestionList = promptFileResults.map(file => {
- const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim()
+ const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim();
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "save ") : ""}${chatName}`,
displayName: `${chatName}`,
- description: Translation.tr("Save chat to %1").arg(chatName),
- }
- })
+ description: Translation.tr("Save chat to %1").arg(chatName)
+ };
+ });
} else if (messageInputField.text.startsWith(`${root.commandPrefix}load`)) {
- root.suggestionQuery = messageInputField.text.split(" ")[1] ?? ""
+ root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.savedChats.map(file => {
return {
name: Fuzzy.prepare(file),
- obj: file,
- }
+ obj: file
+ };
}), {
all: true,
key: "name"
- })
+ });
root.suggestionList = promptFileResults.map(file => {
- const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim()
+ const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim();
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "load ") : ""}${chatName}`,
displayName: `${chatName}`,
- description: Translation.tr(`Load chat from %1`).arg(file.target),
- }
- })
+ description: Translation.tr(`Load chat from %1`).arg(file.target)
+ };
+ });
} else if (messageInputField.text.startsWith(`${root.commandPrefix}tool`)) {
- root.suggestionQuery = messageInputField.text.split(" ")[1] ?? ""
+ root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const toolResults = Fuzzy.go(root.suggestionQuery, Ai.availableTools.map(tool => {
return {
name: Fuzzy.prepare(tool),
- obj: tool,
- }
+ obj: tool
+ };
}), {
all: true,
key: "name"
- })
+ });
root.suggestionList = toolResults.map(tool => {
- const toolName = tool.target
+ const toolName = tool.target;
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "tool ") : ""}${tool.target}`,
displayName: toolName,
- description: Ai.toolDescriptions[toolName],
- }
- })
- } else if(messageInputField.text.startsWith(root.commandPrefix)) {
- root.suggestionQuery = messageInputField.text
+ description: Ai.toolDescriptions[toolName]
+ };
+ });
+ } else if (messageInputField.text.startsWith(root.commandPrefix)) {
+ root.suggestionQuery = messageInputField.text;
root.suggestionList = root.allCommands.filter(cmd => cmd.name.startsWith(messageInputField.text.substring(1))).map(cmd => {
return {
name: `${root.commandPrefix}${cmd.name}`,
- description: `${cmd.description}`,
- }
- })
+ description: `${cmd.description}`
+ };
+ });
}
}
function accept() {
- root.handleInput(text)
- text = ""
+ root.handleInput(text);
+ text = "";
}
- Keys.onPressed: (event) => {
+ Keys.onPressed: event => {
if (event.key === Qt.Key_Tab) {
suggestions.acceptSelectedWord();
event.accepted = true;
@@ -615,35 +639,41 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
} else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) {
if (event.modifiers & Qt.ShiftModifier) {
// Insert newline
- messageInputField.insert(messageInputField.cursorPosition, "\n")
- event.accepted = true
- } else { // Accept text
- const inputText = messageInputField.text
- messageInputField.clear()
- root.handleInput(inputText)
- event.accepted = true
+ messageInputField.insert(messageInputField.cursorPosition, "\n");
+ event.accepted = true;
+ } else {
+ // Accept text
+ const inputText = messageInputField.text;
+ messageInputField.clear();
+ root.handleInput(inputText);
+ event.accepted = true;
}
- } else if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_V) { // Intercept Ctrl+V to handle image/file pasting
- if (event.modifiers & Qt.ShiftModifier) { // Let Shift+Ctrl+V = plain paste
- messageInputField.text += Quickshell.clipboardText
+ } else if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_V) {
+ // Intercept Ctrl+V to handle image/file pasting
+ if (event.modifiers & Qt.ShiftModifier) {
+ // Let Shift+Ctrl+V = plain paste
+ messageInputField.text += Quickshell.clipboardText;
event.accepted = true;
return;
}
// Try image paste first
- const currentClipboardEntry = Cliphist.entries[0]
- const cleanCliphistEntry = StringUtils.cleanCliphistEntry(currentClipboardEntry)
- if (/^\d+\t\[\[.*binary data.*\d+x\d+.*\]\]$/.test(currentClipboardEntry)) { // First entry = currently copied entry = image?
- decodeImageAndAttachProc.handleEntry(currentClipboardEntry)
+ const currentClipboardEntry = Cliphist.entries[0];
+ const cleanCliphistEntry = StringUtils.cleanCliphistEntry(currentClipboardEntry);
+ if (/^\d+\t\[\[.*binary data.*\d+x\d+.*\]\]$/.test(currentClipboardEntry)) {
+ // First entry = currently copied entry = image?
+ decodeImageAndAttachProc.handleEntry(currentClipboardEntry);
event.accepted = true;
return;
- } else if (cleanCliphistEntry.startsWith("file://")) { // First entry = currently copied entry = image?
- const fileName = decodeURIComponent(cleanCliphistEntry)
+ } else if (cleanCliphistEntry.startsWith("file://")) {
+ // First entry = currently copied entry = image?
+ const fileName = decodeURIComponent(cleanCliphistEntry);
Ai.attachFile(fileName);
event.accepted = true;
return;
}
event.accepted = false; // No image, let text pasting proceed
- } else if (event.key === Qt.Key_Escape) { // Esc to detach file
+ } else if (event.key === Qt.Key_Escape) {
+ // Esc to detach file
if (Ai.pendingFilePath.length > 0) {
Ai.attachFile("");
event.accepted = true;
@@ -668,19 +698,18 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
anchors.fill: parent
cursorShape: sendButton.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
- const inputText = messageInputField.text
- root.handleInput(inputText)
- messageInputField.clear()
+ const inputText = messageInputField.text;
+ root.handleInput(inputText);
+ messageInputField.clear();
}
}
contentItem: MaterialSymbol {
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
- iconSize: Appearance.font.pixelSize.larger
- // fill: sendButton.enabled ? 1 : 0
+ iconSize: 22
color: sendButton.enabled ? Appearance.m3colors.m3onPrimary : Appearance.colors.colOnLayer2Disabled
- text: "send"
+ text: "arrow_upward"
}
}
}
@@ -699,59 +728,58 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
{
name: "",
sendDirectly: false,
- dontAddSpace: true,
- },
+ dontAddSpace: true
+ },
{
name: "clear",
- sendDirectly: true,
- },
+ sendDirectly: true
+ },
]
- ApiInputBoxIndicator { // Model indicator
+ ApiInputBoxIndicator {
+ // Model indicator
icon: "api"
text: Ai.getModel().name
- tooltipText: Translation.tr("Current model: %1\nSet it with %2model MODEL")
- .arg(Ai.getModel().name)
- .arg(root.commandPrefix)
+ tooltipText: Translation.tr("Current model: %1\nSet it with %2model MODEL").arg(Ai.getModel().name).arg(root.commandPrefix)
}
- ApiInputBoxIndicator { // Tool indicator
+ ApiInputBoxIndicator {
+ // Tool indicator
icon: "service_toolbox"
text: Ai.currentTool.charAt(0).toUpperCase() + Ai.currentTool.slice(1)
- tooltipText: Translation.tr("Current tool: %1\nSet it with %2tool TOOL")
- .arg(Ai.currentTool)
- .arg(root.commandPrefix)
+ tooltipText: Translation.tr("Current tool: %1\nSet it with %2tool TOOL").arg(Ai.currentTool).arg(root.commandPrefix)
}
- Item { Layout.fillWidth: true }
+ Item {
+ Layout.fillWidth: true
+ }
- ButtonGroup { // Command buttons
+ ButtonGroup {
+ // Command buttons
padding: 0
- Repeater { // Command buttons
+ Repeater {
+ // Command buttons
model: commandButtonsRow.commandsShown
delegate: ApiCommandButton {
property string commandRepresentation: `${root.commandPrefix}${modelData.name}`
buttonText: commandRepresentation
downAction: () => {
if (modelData.sendDirectly) {
- root.handleInput(commandRepresentation)
+ root.handleInput(commandRepresentation);
} else {
- messageInputField.text = commandRepresentation + (modelData.dontAddSpace ? "" : " ")
- messageInputField.cursorPosition = messageInputField.text.length
- messageInputField.forceActiveFocus()
+ messageInputField.text = commandRepresentation + (modelData.dontAddSpace ? "" : " ");
+ messageInputField.cursorPosition = messageInputField.text.length;
+ messageInputField.forceActiveFocus();
}
if (modelData.name === "clear") {
- messageInputField.text = ""
+ messageInputField.text = "";
}
}
}
}
}
}
-
}
-
}
-
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml
index 1e1d483c9..ff4b22d42 100644
--- a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml
@@ -12,6 +12,8 @@ import Quickshell
Item {
id: root
+ property real padding: 4
+
property var inputField: tagInputField
readonly property var responses: Booru.responses
property string previewDownloadPath: Directories.booruPreviews
@@ -141,7 +143,11 @@ Item {
ColumnLayout {
id: columnLayout
- anchors.fill: parent
+ anchors {
+ fill: parent
+ margins: root.padding
+ }
+ spacing: root.padding
Item {
Layout.fillWidth: true
@@ -317,14 +323,12 @@ Item {
id: tagInputContainer
property real columnSpacing: 5
Layout.fillWidth: true
- radius: Appearance.rounding.small
- color: Appearance.colors.colLayer1
+ radius: Appearance.rounding.normal - root.padding
+ color: Appearance.colors.colLayer2
implicitWidth: tagInputField.implicitWidth
implicitHeight: Math.max(inputFieldRowLayout.implicitHeight + inputFieldRowLayout.anchors.topMargin
+ commandButtonsRow.implicitHeight + commandButtonsRow.anchors.bottomMargin + columnSpacing, 45)
clip: true
- border.color: Appearance.colors.colOutlineVariant
- border.width: 1
Behavior on implicitHeight {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
@@ -456,10 +460,9 @@ Item {
contentItem: MaterialSymbol {
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
- iconSize: Appearance.font.pixelSize.larger
- // fill: sendButton.enabled ? 1 : 0
+ iconSize: 22
color: sendButton.enabled ? Appearance.m3colors.m3onPrimary : Appearance.colors.colOnLayer2Disabled
- text: "send"
+ text: "arrow_upward"
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml
index 6d8009f0b..9a26b07be 100644
--- a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeft.qml
@@ -127,6 +127,7 @@ Scope { // Scope
sourceComponent: FloatingWindow {
id: detachedSidebarRoot
property var contentParent: detachedSidebarBackground
+ color: "transparent"
visible: GlobalStates.sidebarLeftOpen
onVisibleChanged: {
diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml
index ff1c34509..f3ebfd356 100644
--- a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml
@@ -21,7 +21,6 @@ Item {
...(root.translatorEnabled ? [{"icon": "translate", "name": Translation.tr("Translator")}] : []),
...((root.animeEnabled && !root.animeCloset) ? [{"icon": "bookmark_heart", "name": Translation.tr("Anime")}] : [])
]
- property int selectedTab: 0
property int tabCount: swipeView.count
function focusActiveItem() {
@@ -31,67 +30,64 @@ Item {
Keys.onPressed: (event) => {
if (event.modifiers === Qt.ControlModifier) {
if (event.key === Qt.Key_PageDown) {
- root.selectedTab = Math.min(root.selectedTab + 1, root.tabCount - 1)
+ swipeView.incrementCurrentIndex()
event.accepted = true;
- }
+ }
else if (event.key === Qt.Key_PageUp) {
- root.selectedTab = Math.max(root.selectedTab - 1, 0)
- event.accepted = true;
- }
- else if (event.key === Qt.Key_Tab) {
- root.selectedTab = (root.selectedTab + 1) % root.tabCount;
- event.accepted = true;
- }
- else if (event.key === Qt.Key_Backtab) {
- root.selectedTab = (root.selectedTab - 1 + root.tabCount) % root.tabCount;
+ swipeView.decrementCurrentIndex()
event.accepted = true;
}
}
}
ColumnLayout {
- anchors.fill: parent
- anchors.margins: sidebarPadding
-
+ anchors {
+ fill: parent
+ margins: sidebarPadding
+ }
spacing: sidebarPadding
- PrimaryTabBar { // Tab strip
- id: tabBar
- visible: root.tabButtonList.length > 1
- tabButtonList: root.tabButtonList
- Synchronizer on currentIndex {
- property alias source: root.selectedTab
+ Toolbar {
+ Layout.alignment: Qt.AlignHCenter
+ enableShadow: false
+ ToolbarTabBar {
+ id: tabBar
+ Layout.alignment: Qt.AlignHCenter
+ tabButtonList: root.tabButtonList
+ currentIndex: swipeView.currentIndex
}
}
- SwipeView { // Content pages
- id: swipeView
- Layout.topMargin: 5
+ Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
- spacing: 10
-
- currentIndex: root.selectedTab
- onCurrentIndexChanged: {
- tabBar.enableIndicatorAnimation = true
- root.selectedTab = currentIndex
- }
+ implicitWidth: swipeView.implicitWidth
+ implicitHeight: swipeView.implicitHeight
+ radius: Appearance.rounding.normal
+ color: Appearance.colors.colLayer1
- clip: true
- layer.enabled: true
- layer.effect: OpacityMask {
- maskSource: Rectangle {
- width: swipeView.width
- height: swipeView.height
- radius: Appearance.rounding.small
+ SwipeView { // Content pages
+ id: swipeView
+ anchors.fill: parent
+ spacing: 10
+ currentIndex: tabBar.currentIndex
+
+ clip: true
+ layer.enabled: true
+ layer.effect: OpacityMask {
+ maskSource: Rectangle {
+ width: swipeView.width
+ height: swipeView.height
+ radius: Appearance.rounding.small
+ }
}
- }
- contentChildren: [
- ...((root.aiChatEnabled || (!root.translatorEnabled && !root.animeEnabled)) ? [aiChat.createObject()] : []),
- ...(root.translatorEnabled ? [translator.createObject()] : []),
- ...(root.animeEnabled ? [anime.createObject()] : [])
- ]
+ contentChildren: [
+ ...((root.aiChatEnabled || (!root.translatorEnabled && !root.animeEnabled)) ? [aiChat.createObject()] : []),
+ ...(root.translatorEnabled ? [translator.createObject()] : []),
+ ...(root.animeEnabled ? [anime.createObject()] : [])
+ ]
+ }
}
Component {
diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/Translator.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/Translator.qml
index 41f4fffab..bde48f532 100644
--- a/dots/.config/quickshell/ii/modules/sidebarLeft/Translator.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarLeft/Translator.qml
@@ -13,17 +13,24 @@ import Quickshell.Io
*/
Item {
id: root
+
+ // Sizes
+ property real padding: 4
+
// Widgets
property var inputField: inputCanvas.inputTextArea
+
// Widget variables
property bool translationFor: false // Indicates if the translation is for an autocorrected text
property string translatedText: ""
property list languages: []
+
// Options
property string targetLanguage: Config.options.language.translator.targetLanguage
property string sourceLanguage: Config.options.language.translator.sourceLanguage
property string hostLanguage: targetLanguage
+ // States
property bool showLanguageSelector: false
property bool languageSelectorTarget: false // true for target language, false for source language
@@ -99,7 +106,11 @@ Item {
}
ColumnLayout {
- anchors.fill: parent
+ anchors {
+ fill: parent
+ margins: root.padding
+ }
+
StyledFlickable {
Layout.fillWidth: true
Layout.fillHeight: true
diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/translator/TextCanvas.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/translator/TextCanvas.qml
index 7b4841217..b585a07d7 100644
--- a/dots/.config/quickshell/ii/modules/sidebarLeft/translator/TextCanvas.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarLeft/translator/TextCanvas.qml
@@ -17,10 +17,8 @@ Rectangle {
default property alias actionButtons: actions.data
Layout.fillWidth: true
implicitHeight: Math.max(150, inputColumn.implicitHeight)
- color: isInput ? Appearance.colors.colLayer1 : Appearance.colors.colSurfaceContainer
+ color: Appearance.colors.colLayer2
radius: Appearance.rounding.normal
- border.color: isInput ? Appearance.colors.colOutlineVariant : "transparent"
- border.width: isInput ? 1 : 0
signal inputTextChanged(); // Signal emitted when text changes
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml b/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml
index 9343c4588..f0286fc38 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml
@@ -102,7 +102,7 @@ WindowDialog {
right: parent.right
}
iconSize: Appearance.font.pixelSize.larger
- buttonIcon: "destruction"
+ buttonIcon: "flash_off"
text: Translation.tr("Enable")
checked: Config.options.light.antiFlashbang.enable
onCheckedChanged: {
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml
index b5e49d3b0..f8c93bfff 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml
@@ -29,7 +29,7 @@ AbstractQuickPanel {
readonly property real baseCellHeight: 56
// Toggles
- readonly property list availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile","musicRecognition"]
+ readonly property list availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile","musicRecognition", "antiFlashbang"]
readonly property int columns: Config.options.sidebar.quickToggles.android.columns
readonly property list toggles: Config.ready ? Config.options.sidebar.quickToggles.android.toggles : []
readonly property list toggleRows: toggleRowsForList(toggles)
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAntiFlashbangToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAntiFlashbangToggle.qml
new file mode 100644
index 000000000..4fc8ee4f5
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAntiFlashbangToggle.qml
@@ -0,0 +1,29 @@
+import qs.modules.common
+import qs.modules.common.widgets
+import qs.services
+import QtQuick
+import Quickshell
+
+AndroidQuickToggleButton {
+ id: root
+
+ property bool auto: Config.options.light.night.automatic
+
+ name: Translation.tr("Anti-flashbang")
+
+ toggled: Config.options.light.antiFlashbang.enable
+ buttonIcon: "flash_off"
+
+ mainAction: () => {
+ Config.options.light.antiFlashbang.enable = !Config.options.light.antiFlashbang.enable;
+ }
+
+ altAction: () => {
+ root.openMenu()
+ }
+
+ StyledToolTip {
+ text: Translation.tr("Anti-flashbang")
+ }
+}
+
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml
index 3fff4d620..52f7459a7 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml
@@ -12,7 +12,7 @@ AndroidQuickToggleButton {
statusText: toggled ? Translation.tr("Unmuted") : Translation.tr("Muted")
toggled: !Audio.sink?.audio?.muted
buttonIcon: Audio.sink?.audio?.muted ? "volume_off" : "volume_up"
- onClicked: {
+ mainAction: () => {
Audio.sink.audio.muted = !Audio.sink.audio.muted
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml
index 3b4f8fa8d..ae76d5751 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml
@@ -14,7 +14,7 @@ AndroidQuickToggleButton {
toggled: BluetoothStatus.enabled
buttonIcon: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled"
- onClicked: {
+ mainAction: () => {
Bluetooth.defaultAdapter.enabled = !Bluetooth.defaultAdapter?.enabled
}
altAction: () => {
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml
index d703c67dd..5b65e673d 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
toggled: false
buttonIcon: "cloud_lock"
- onClicked: {
+ mainAction: () => {
if (toggled) {
root.toggled = false
Quickshell.execDetached(["warp-cli", "disconnect"])
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml
index 82efbf544..8fdc59205 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
toggled: false
buttonIcon: "colorize"
- onClicked: {
+ mainAction: () => {
GlobalStates.sidebarRightOpen = false;
delayedActionTimer.start()
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml
index 668f840f2..11be0dae6 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
toggled: Appearance.m3colors.darkmode
buttonIcon: "contrast"
- onClicked: event => {
+ mainAction: () => {
if (Appearance.m3colors.darkmode) {
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]);
} else {
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml
index c907abf77..bfd14335c 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml
@@ -16,7 +16,7 @@ AndroidQuickToggleButton {
EasyEffects.fetchActiveState()
}
- onClicked: {
+ mainAction: () => {
EasyEffects.toggle()
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml
index d4ab4fd81..ae63622fe 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
toggled: toggled
buttonIcon: "gamepad"
- onClicked: {
+ mainAction: () => {
root.toggled = !root.toggled
if (root.toggled) {
Quickshell.execDetached(["bash", "-c", `hyprctl --batch "keyword animations:enabled 0; keyword decoration:shadow:enabled 0; keyword decoration:blur:enabled 0; keyword general:gaps_in 0; keyword general:gaps_out 0; keyword general:border_size 1; keyword decoration:rounding 0; keyword general:allow_tearing 1"`])
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml
index 17dedd7df..2daf1f914 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml
@@ -11,7 +11,7 @@ AndroidQuickToggleButton {
toggled: Idle.inhibit
buttonIcon: "coffee"
- onClicked: {
+ mainAction: () => {
Idle.toggleInhibit()
}
StyledToolTip {
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml
index 40f06f0a4..7ffeea7f7 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml
@@ -12,7 +12,7 @@ AndroidQuickToggleButton {
statusText: toggled ? Translation.tr("Enabled") : Translation.tr("Muted")
toggled: !Audio.source?.audio?.muted
buttonIcon: Audio.source?.audio?.muted ? "mic_off" : "mic"
- onClicked: {
+ mainAction: () => {
Audio.source.audio.muted = !Audio.source.audio.muted
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml
index e8f17f657..23e2cda92 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml
@@ -21,7 +21,7 @@ AndroidQuickToggleButton {
text: Translation.tr("Recognize music | Right-click to toggle source")
}
- onClicked: {
+ mainAction: () => {
SongRec.toggleRunning()
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml
index 53576febb..eaf24e141 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml
@@ -12,7 +12,7 @@ AndroidQuickToggleButton {
toggled: Network.wifiStatus !== "disabled"
buttonIcon: Network.materialSymbol
- onClicked: Network.toggleWifi()
+ mainAction: () => Network.toggleWifi()
altAction: () => {
root.openMenu()
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml
index 699d93dc3..133b0ffcd 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml
@@ -14,7 +14,8 @@ AndroidQuickToggleButton {
toggled: Hyprsunset.active
buttonIcon: auto ? "night_sight_auto" : "bedtime"
- onClicked: {
+
+ mainAction: () => {
Hyprsunset.toggle()
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml
index dc1f381cd..eda39d716 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
toggled: !Notifications.silent
buttonIcon: toggled ? "notifications_active" : "notifications_paused"
- onClicked: {
+ mainAction: () => {
Notifications.silent = !Notifications.silent;
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml
index 7a4283689..779917802 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml
@@ -11,7 +11,8 @@ AndroidQuickToggleButton {
name: Translation.tr("Virtual Keyboard")
toggled: GlobalStates.oskOpen
buttonIcon: toggled ? "keyboard_hide" : "keyboard"
- onClicked: {
+
+ mainAction: () => {
GlobalStates.oskOpen = !GlobalStates.oskOpen
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml
index 064180ae5..381113308 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml
@@ -22,7 +22,7 @@ AndroidQuickToggleButton {
case PowerProfile.Performance: return "Performance"
}
- onClicked: (event) => {
+ mainAction: () => {
if (PowerProfiles.hasPerformanceProfile) {
switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: PowerProfiles.profile = PowerProfile.Balanced
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml
index c2658cede..96401a6c0 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml
@@ -13,6 +13,7 @@ GroupButton {
required property bool expandedSize
required property string buttonIcon
required property string name
+ required property var mainAction
property string statusText: toggled ? Translation.tr("Active") : Translation.tr("Inactive")
required property real baseCellWidth
@@ -54,6 +55,11 @@ GroupButton {
property color colText: (toggled && !(altAction && expandedSize)) ? Appearance.colors.colOnPrimary : Appearance.colors.colOnLayer2
property color colIcon: expandedSize ? (root.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnLayer3) : colText
+ onClicked: {
+ if (root.expandedSize && root.altAction) root.altAction();
+ else root.mainAction();
+ }
+
contentItem: RowLayout {
id: contentItem
spacing: 4
@@ -64,35 +70,63 @@ GroupButton {
rightMargin: root.horizontalPadding
}
- Rectangle {
+ // Icon
+ MouseArea {
+ id: iconMouseArea
+ hoverEnabled: true
+ acceptedButtons: (root.expandedSize && root.altAction) ? Qt.LeftButton : Qt.NoButton
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: true
Layout.topMargin: root.verticalPadding
Layout.bottomMargin: root.verticalPadding
- implicitWidth: height
- radius: root.radius - root.verticalPadding
- color: {
- const baseColor = root.toggled ? Appearance.colors.colPrimary : Appearance.colors.colLayer3
- const transparentizeAmount = (root.altAction && root.expandedSize) ? 0 : 1
- return ColorUtils.transparentize(baseColor, transparentizeAmount)
- }
+ implicitHeight: iconBackground.implicitHeight
+ implicitWidth: iconBackground.implicitWidth
+ cursorShape: Qt.PointingHandCursor
- Behavior on radius {
- animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
- }
- Behavior on color {
- animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
- }
+ onClicked: root.mainAction()
- MaterialSymbol {
- anchors.centerIn: parent
- fill: root.toggled ? 1 : 0
- iconSize: root.expandedSize ? 22 : 24
- color: root.colIcon
- text: root.buttonIcon
+ Rectangle {
+ id: iconBackground
+ anchors.fill: parent
+ implicitWidth: height
+ radius: root.radius - root.verticalPadding
+ color: {
+ const baseColor = root.toggled ? Appearance.colors.colPrimary : Appearance.colors.colLayer3
+ const transparentizeAmount = (root.altAction && root.expandedSize) ? 0 : 1
+ return ColorUtils.transparentize(baseColor, transparentizeAmount)
+ }
+
+ Behavior on radius {
+ animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
+ }
+ Behavior on color {
+ animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
+ }
+
+ MaterialSymbol {
+ anchors.centerIn: parent
+ fill: root.toggled ? 1 : 0
+ iconSize: root.expandedSize ? 22 : 24
+ color: root.colIcon
+ text: root.buttonIcon
+ }
+
+ // State layer
+ Loader {
+ anchors.fill: parent
+ active: (root.expandedSize && root.altAction)
+ sourceComponent: Rectangle {
+ radius: iconBackground.radius
+ color: ColorUtils.transparentize(root.colIcon, iconMouseArea.containsPress ? 0.88 : iconMouseArea.containsMouse ? 0.95 : 1)
+ Behavior on color {
+ animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
+ }
+ }
+ }
}
}
+ // Text column for expanded size
Loader {
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
@@ -119,8 +153,9 @@ GroupButton {
}
font {
pixelSize: Appearance.font.pixelSize.smaller
+ weight: 100
}
- color: Appearance.colors.colSubtext
+ color: root.colText
elide: Text.ElideRight
text: root.statusText
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml
index 5a22b616a..c4b4a5479 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml
@@ -14,7 +14,7 @@ AndroidQuickToggleButton {
toggled: false
buttonIcon: "screenshot_region"
- onClicked: {
+ mainAction: () => {
GlobalStates.sidebarRightOpen = false;
delayedActionTimer.start()
}
diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml
index aa5356e2e..43cc712b5 100644
--- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml
+++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml
@@ -245,4 +245,20 @@ DelegateChooser {
cellSize: modelData.size
} }
+ DelegateChoice { roleValue: "antiFlashbang"; AndroidAntiFlashbangToggle {
+ required property int index
+ required property var modelData
+ buttonIndex: root.startingIndex + index
+ buttonData: modelData
+ editMode: root.editMode
+ expandedSize: modelData.size > 1
+ baseCellWidth: root.baseCellWidth
+ baseCellHeight: root.baseCellHeight
+ cellSpacing: root.spacing
+ cellSize: modelData.size
+ onOpenMenu: {
+ root.openNightLightDialog()
+ }
+ } }
+
}
diff --git a/dots/.config/quickshell/ii/modules/wallpaperSelector/WallpaperSelectorContent.qml b/dots/.config/quickshell/ii/modules/wallpaperSelector/WallpaperSelectorContent.qml
index a093d38ca..c237a8854 100644
--- a/dots/.config/quickshell/ii/modules/wallpaperSelector/WallpaperSelectorContent.qml
+++ b/dots/.config/quickshell/ii/modules/wallpaperSelector/WallpaperSelectorContent.qml
@@ -186,6 +186,8 @@ MouseArea {
colBackgroundToggled: Appearance.colors.colSecondaryContainer
colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover
colRippleToggled: Appearance.colors.colSecondaryContainerActive
+ buttonRadius: height / 2
+ implicitHeight: 38
contentItem: RowLayout {
MaterialSymbol {
diff --git a/dots/.config/quickshell/ii/scripts/colors/scheme_for_image.py b/dots/.config/quickshell/ii/scripts/colors/scheme_for_image.py
index 8aa0ccbea..7adc8ce70 100755
--- a/dots/.config/quickshell/ii/scripts/colors/scheme_for_image.py
+++ b/dots/.config/quickshell/ii/scripts/colors/scheme_for_image.py
@@ -30,12 +30,7 @@ def image_colorfulness(image):
# scheme-content respects the image's colors very well, but it might
# look too saturated, so we only use it for not very colorful images to be safe
def pick_scheme(colorfulness):
- if colorfulness < 10:
- # return "scheme-monochrome"
- return "scheme-content"
- elif colorfulness < 20:
- return "scheme-content"
- elif colorfulness < 50:
+ if colorfulness < 40:
return "scheme-neutral"
else:
return "scheme-tonal-spot"
diff --git a/dots/.config/quickshell/ii/scripts/keyring/is_unlocked.sh b/dots/.config/quickshell/ii/scripts/keyring/is_unlocked.sh
new file mode 100755
index 000000000..d4063d816
--- /dev/null
+++ b/dots/.config/quickshell/ii/scripts/keyring/is_unlocked.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+locked_state=$(busctl --user get-property org.freedesktop.secrets \
+ /org/freedesktop/secrets/collection/login \
+ org.freedesktop.Secret.Collection Locked)
+if [[ "${locked_state}" == "b false" ]]; then
+ echo 'Keyring is unlocked' >&2
+ exit 0
+else
+ echo 'Keyring is locked' >&2
+ exit 1
+fi
diff --git a/dots/.config/quickshell/ii/scripts/keyring/try_lookup.sh b/dots/.config/quickshell/ii/scripts/keyring/try_lookup.sh
new file mode 100755
index 000000000..a076aac91
--- /dev/null
+++ b/dots/.config/quickshell/ii/scripts/keyring/try_lookup.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+data=$(secret-tool lookup 'application' 'illogical-impulse')
+if [[ -z "$data" ]]; then
+ if "${SCRIPT_DIR}/is_unlocked.sh"; then
+ echo 'not found'
+ exit 1
+ else
+ echo 'locked'
+ exit 2
+ fi
+fi
+echo "$data"
diff --git a/dots/.config/quickshell/ii/scripts/keyring/unlock.sh b/dots/.config/quickshell/ii/scripts/keyring/unlock.sh
index b255f8e0f..30509aa37 100755
--- a/dots/.config/quickshell/ii/scripts/keyring/unlock.sh
+++ b/dots/.config/quickshell/ii/scripts/keyring/unlock.sh
@@ -1,12 +1,10 @@
#!/usr/bin/env bash
# Based on https://unix.stackexchange.com/a/602935
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
# Skip if already unlocked
-locked_state=$(busctl --user get-property org.freedesktop.secrets \
- /org/freedesktop/secrets/collection/login \
- org.freedesktop.Secret.Collection Locked)
-if [[ "${locked_state}" == "b false" ]]; then
- echo 'Keyring is already unlocked.' >&2
+if "${SCRIPT_DIR}/is_unlocked.sh"; then
exit 1
fi
diff --git a/dots/.config/quickshell/ii/services/Ai.qml b/dots/.config/quickshell/ii/services/Ai.qml
index 47b1d151f..ccd237de8 100644
--- a/dots/.config/quickshell/ii/services/Ai.qml
+++ b/dots/.config/quickshell/ii/services/Ai.qml
@@ -532,8 +532,6 @@ Singleton {
modelId = modelId.toLowerCase()
if (modelList.indexOf(modelId) !== -1) {
const model = models[modelId]
- // Fetch API keys if needed
- if (model?.requires_key) KeyringStorage.fetchKeyringData();
// See if policy prevents online models
if (Config.options.policies.ai === 2 && !model.endpoint.includes("localhost")) {
root.addMessage(
@@ -641,6 +639,10 @@ Singleton {
function makeRequest() {
const model = models[currentModelId];
+
+ // Fetch API keys if needed
+ if (model?.requires_key && !KeyringStorage.loaded) KeyringStorage.fetchKeyringData();
+
requester.currentStrategy = root.currentApiStrategy;
requester.currentStrategy.reset(); // Reset strategy state
diff --git a/dots/.config/quickshell/ii/services/AppSearch.qml b/dots/.config/quickshell/ii/services/AppSearch.qml
index 6be896404..196e1bed3 100644
--- a/dots/.config/quickshell/ii/services/AppSearch.qml
+++ b/dots/.config/quickshell/ii/services/AppSearch.qml
@@ -86,6 +86,10 @@ Singleton {
return str.toLowerCase().replace(/\s+/g, "-");
}
+ function getUndescoreToKebabAppName(str) {
+ return str.toLowerCase().replace(/_/g, "-");
+ }
+
function guessIcon(str) {
if (!str || str.length == 0) return "image-missing";
@@ -124,6 +128,8 @@ Singleton {
const kebabNormalizedGuess = getKebabNormalizedAppName(str);
if (iconExists(kebabNormalizedGuess)) return kebabNormalizedGuess;
+ const undescoreToKebabGuess = getUndescoreToKebabAppName(str);
+ if (iconExists(undescoreToKebabGuess)) return undescoreToKebabGuess;
// Search in desktop entries
const iconSearchResults = Fuzzy.go(str, preppedIcons, {
diff --git a/dots/.config/quickshell/ii/services/Booru.qml b/dots/.config/quickshell/ii/services/Booru.qml
index 3a13a9bd8..090476b9f 100644
--- a/dots/.config/quickshell/ii/services/Booru.qml
+++ b/dots/.config/quickshell/ii/services/Booru.qml
@@ -47,7 +47,7 @@ Singleton {
}
})
},
- "tagSearchTemplate": "https://yande.re/tag.json?order=count&name={{query}}*",
+ "tagSearchTemplate": "https://yande.re/tag.json?order=count&limit=10&name={{query}}*",
"tagMapFunc": (response) => {
return response.map(item => {
return {
@@ -81,7 +81,7 @@ Singleton {
}
})
},
- "tagSearchTemplate": "https://konachan.net/tag.json?order=count&name={{query}}*",
+ "tagSearchTemplate": "https://konachan.net/tag.json?order=count&limit=10&name={{query}}*",
"tagMapFunc": (response) => {
return response.map(item => {
return {
@@ -142,7 +142,7 @@ Singleton {
}
})
},
- "tagSearchTemplate": "https://danbooru.donmai.us/tags.json?search[name_matches]={{query}}*",
+ "tagSearchTemplate": "https://danbooru.donmai.us/tags.json?limit=10&search[name_matches]={{query}}*",
"tagMapFunc": (response) => {
return response.map(item => {
return {
@@ -151,7 +151,6 @@ Singleton {
}
})
}
-
},
"gelbooru": {
"name": "Gelbooru",
@@ -178,7 +177,7 @@ Singleton {
}
})
},
- "tagSearchTemplate": "https://gelbooru.com/index.php?page=dapi&s=tag&q=index&json=1&orderby=count&name_pattern={{query}}%",
+ "tagSearchTemplate": "https://gelbooru.com/index.php?page=dapi&s=tag&q=index&json=1&orderby=count&limit=10&name_pattern={{query}}%",
"tagMapFunc": (response) => {
return response.tag.map(item => {
return {
diff --git a/dots/.config/quickshell/ii/services/Brightness.qml b/dots/.config/quickshell/ii/services/Brightness.qml
index 5232f76f9..f3cec016c 100644
--- a/dots/.config/quickshell/ii/services/Brightness.qml
+++ b/dots/.config/quickshell/ii/services/Brightness.qml
@@ -86,7 +86,7 @@ Singleton {
property int rawMaxBrightness: 100
property real brightness
property real brightnessMultiplier: 1.0
- property real multipliedBrightness: Math.max(0, Math.min(1, brightness * brightnessMultiplier))
+ property real multipliedBrightness: Math.max(0, Math.min(1, brightness * (Config.options.light.antiFlashbang.enable ? brightnessMultiplier : 1)))
property bool ready: false
property bool animateChanges: !monitor.isDdc
diff --git a/dots/.config/quickshell/ii/services/KeyringStorage.qml b/dots/.config/quickshell/ii/services/KeyringStorage.qml
index 508247966..1e8562cac 100644
--- a/dots/.config/quickshell/ii/services/KeyringStorage.qml
+++ b/dots/.config/quickshell/ii/services/KeyringStorage.qml
@@ -1,6 +1,7 @@
pragma Singleton
pragma ComponentBehavior: Bound
+import qs
import qs.modules.common
import qs.modules.common.functions
import Quickshell;
@@ -89,11 +90,13 @@ Singleton {
Process {
id: getData
command: [ // We need to use echo for a newline so splitparser does parse
- "bash", "-c", `echo $(secret-tool lookup 'application' 'illogical-impulse')`,
+ "bash", "-c", `${Directories.scriptPath}/keyring/try_lookup.sh 2> /dev/null`,
]
- stdout: SplitParser {
- onRead: data => {
- if(data.length === 0) return;
+ stdout: StdioCollector {
+ id: keyringDataOutputCollector
+ onStreamFinished: {
+ const data = keyringDataOutputCollector.text;
+ if (data.length === 0 || !data.startsWith("{")) return;
try {
root.keyringData = JSON.parse(data);
// console.log("[KeyringStorage] Keyring data fetched:", JSON.stringify(root.keyringData));
@@ -105,13 +108,15 @@ Singleton {
}
}
onExited: (exitCode, exitStatus) => {
- // console.log("[KeyringStorage] Keyring data fetch process exited with code:", exitCode);
- if (exitCode !== 0) {
- console.error("[KeyringStorage] Failed to get keyring data, reinitializing.");
+ console.log("[KeyringStorage] Keyring data fetch process exited with code:", exitCode);
+ if (exitCode === 1) {
+ console.error("[KeyringStorage] Entry not found, initializing.");
root.keyringData = {};
saveKeyringData()
}
- root.loaded = true;
+ if (exitCode !== 2) {
+ root.loaded = true;
+ }
}
}
diff --git a/sdata/dist-arch/illogical-impulse-audio/PKGBUILD b/sdata/dist-arch/illogical-impulse-audio/PKGBUILD
index 4a9294122..fe645cf37 100644
--- a/sdata/dist-arch/illogical-impulse-audio/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-audio/PKGBUILD
@@ -5,11 +5,11 @@ pkgdesc='Illogical Impulse Audio Dependencies'
arch=(any)
license=(None)
depends=(
- cava
- pavucontrol-qt
- wireplumber
- pipewire-pulse
- libdbusmenu-gtk3
- playerctl
+ cava
+ pavucontrol-qt
+ wireplumber
+ pipewire-pulse
+ libdbusmenu-gtk3
+ playerctl
)
diff --git a/sdata/dist-arch/illogical-impulse-backlight/PKGBUILD b/sdata/dist-arch/illogical-impulse-backlight/PKGBUILD
index 451c7e5d5..2cca7c7fa 100644
--- a/sdata/dist-arch/illogical-impulse-backlight/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-backlight/PKGBUILD
@@ -5,8 +5,8 @@ pkgdesc='Illogical Impulse Backlight Dependencies'
arch=(any)
license=(None)
depends=(
- geoclue
- brightnessctl
- ddcutil
+ geoclue
+ brightnessctl
+ ddcutil
)
diff --git a/sdata/dist-arch/illogical-impulse-basic/PKGBUILD b/sdata/dist-arch/illogical-impulse-basic/PKGBUILD
index a403480e8..3948d41bf 100644
--- a/sdata/dist-arch/illogical-impulse-basic/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-basic/PKGBUILD
@@ -5,7 +5,6 @@ pkgdesc='Illogical Impulse Basic Dependencies'
arch=(any)
license=(None)
depends=(
- axel
bc
coreutils
cliphist
@@ -14,7 +13,6 @@ depends=(
wget
ripgrep
jq
- meson
xdg-user-dirs
# Used in install script
rsync
diff --git a/sdata/dist-arch/illogical-impulse-hyprland/PKGBUILD b/sdata/dist-arch/illogical-impulse-hyprland/PKGBUILD
index 797d2d470..8722c9246 100644
--- a/sdata/dist-arch/illogical-impulse-hyprland/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-hyprland/PKGBUILD
@@ -6,16 +6,10 @@ arch=(any)
license=(None)
depends=(
hypridle
- hyprcursor
hyprland
- hyprland-qtutils
- hyprland-qt-support
- hyprlang
hyprlock
hyprpicker
hyprsunset
- hyprutils
- hyprwayland-scanner
xdg-desktop-portal-hyprland
wl-clipboard
)
diff --git a/sdata/dist-arch/illogical-impulse-kde/PKGBUILD b/sdata/dist-arch/illogical-impulse-kde/PKGBUILD
index 99eec5651..0e09ee748 100644
--- a/sdata/dist-arch/illogical-impulse-kde/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-kde/PKGBUILD
@@ -5,11 +5,11 @@ pkgdesc='Illogical Impulse KDE Dependencies'
arch=(any)
license=(None)
depends=(
- bluedevil
- gnome-keyring
- networkmanager
- plasma-nm
- polkit-kde-agent
- dolphin
- systemsettings
+ bluedevil
+ gnome-keyring
+ networkmanager
+ plasma-nm
+ polkit-kde-agent
+ dolphin
+ systemsettings
)
diff --git a/sdata/dist-arch/illogical-impulse-microtex-git/PKGBUILD b/sdata/dist-arch/illogical-impulse-microtex-git/PKGBUILD
index fcb14b68b..b2f48a5bd 100644
--- a/sdata/dist-arch/illogical-impulse-microtex-git/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-microtex-git/PKGBUILD
@@ -8,10 +8,10 @@ arch=("x86_64")
url="https://github.com/NanoMichael/${_pkgname}"
license=('MIT')
depends=(
- tinyxml2
- gtkmm3
- gtksourceviewmm
- cairomm
+ tinyxml2
+ gtkmm3
+ gtksourceviewmm
+ cairomm
)
makedepends=("git" "cmake")
source=("git+${url}.git")
@@ -23,9 +23,9 @@ pkgver() {
}
prepare() {
- cd $_pkgname
- sed -i 's/gtksourceviewmm-3.0/gtksourceviewmm-4.0/' CMakeLists.txt
- sed -i 's/tinyxml2.so.10/tinyxml2.so.11/' CMakeLists.txt
+ cd $_pkgname
+ sed -i 's/gtksourceviewmm-3.0/gtksourceviewmm-4.0/' CMakeLists.txt
+ sed -i 's/tinyxml2.so.10/tinyxml2.so.11/' CMakeLists.txt
}
build() {
diff --git a/sdata/dist-arch/illogical-impulse-portal/PKGBUILD b/sdata/dist-arch/illogical-impulse-portal/PKGBUILD
index 4394d8484..5e01482b7 100644
--- a/sdata/dist-arch/illogical-impulse-portal/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-portal/PKGBUILD
@@ -5,9 +5,9 @@ pkgdesc='Illogical Impulse XDG Desktop Portals'
arch=(any)
license=(None)
depends=(
- xdg-desktop-portal
- xdg-desktop-portal-kde
- xdg-desktop-portal-gtk
- xdg-desktop-portal-hyprland
+ xdg-desktop-portal
+ xdg-desktop-portal-kde
+ xdg-desktop-portal-gtk
+ xdg-desktop-portal-hyprland
)
diff --git a/sdata/dist-arch/illogical-impulse-python/PKGBUILD b/sdata/dist-arch/illogical-impulse-python/PKGBUILD
index fc1ac1e05..a0de2df19 100644
--- a/sdata/dist-arch/illogical-impulse-python/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-python/PKGBUILD
@@ -12,5 +12,4 @@ depends=(
libsoup3
libportal-gtk4
gobject-introspection
- sassc
)
diff --git a/sdata/dist-arch/illogical-impulse-quickshell-git/PKGBUILD b/sdata/dist-arch/illogical-impulse-quickshell-git/PKGBUILD
index 96865a0dd..9aac9658c 100644
--- a/sdata/dist-arch/illogical-impulse-quickshell-git/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-quickshell-git/PKGBUILD
@@ -44,7 +44,7 @@ _pkgsrc="$_pkgname"
source=("$_pkgsrc::git+$url.git#commit=$_commit"
quickshell-check.hook)
sha256sums=('SKIP'
- '8543e21aeaaa5441b73a679160e7601a957f16c433e8d6bd9257e80bd0e94083')
+ '8543e21aeaaa5441b73a679160e7601a957f16c433e8d6bd9257e80bd0e94083')
pkgver() {
diff --git a/sdata/dist-arch/illogical-impulse-screencapture/PKGBUILD b/sdata/dist-arch/illogical-impulse-screencapture/PKGBUILD
index cde216bf0..6373dcb5c 100644
--- a/sdata/dist-arch/illogical-impulse-screencapture/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-screencapture/PKGBUILD
@@ -5,10 +5,10 @@ pkgdesc='Illogical Impulse Screenshot and Recording Dependencies'
arch=(any)
license=(None)
depends=(
- hyprshot
- slurp
- swappy
- tesseract
- tesseract-data-eng
- wf-recorder
+ hyprshot
+ slurp
+ swappy
+ tesseract
+ tesseract-data-eng
+ wf-recorder
)
diff --git a/sdata/dist-arch/illogical-impulse-toolkit/PKGBUILD b/sdata/dist-arch/illogical-impulse-toolkit/PKGBUILD
index 636709f29..f3e4f943b 100644
--- a/sdata/dist-arch/illogical-impulse-toolkit/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-toolkit/PKGBUILD
@@ -5,23 +5,23 @@ pkgdesc='Illogical Impulse GTK/Qt Dependencies'
arch=(any)
license=(None)
depends=(
- kdialog
- qt6-5compat
- qt6-avif-image-plugin
- qt6-base
- qt6-declarative
- qt6-imageformats
- qt6-multimedia
- qt6-positioning
- qt6-quicktimeline
- qt6-sensors
- qt6-svg
- qt6-tools
- qt6-translations
- qt6-virtualkeyboard
- qt6-wayland
- syntax-highlighting
- upower
- wtype
- ydotool
+ kdialog
+ syntax-highlighting
+ upower
+ wtype
+ ydotool
+ qt6-5compat
+ qt6-avif-image-plugin
+ qt6-base
+ qt6-declarative
+ qt6-imageformats
+ qt6-multimedia
+ qt6-positioning
+ qt6-quicktimeline
+ qt6-sensors
+ qt6-svg
+ qt6-tools
+ qt6-translations
+ qt6-virtualkeyboard
+ qt6-wayland
)
diff --git a/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD b/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD
index 45e8bb1d4..76f71d43f 100644
--- a/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD
+++ b/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD
@@ -6,13 +6,11 @@ arch=(any)
license=(None)
depends=(
fuzzel
- glib2 # for `gsettings` it seems?
+ glib2
imagemagick
hypridle
- hyprutils
hyprlock
hyprpicker
- nm-connection-editor
songrec
translate-shell
wlogout
diff --git a/sdata/dist-arch/previous_dependencies.conf b/sdata/dist-arch/previous_dependencies.conf
index 4f32959e3..733e63359 100644
--- a/sdata/dist-arch/previous_dependencies.conf
+++ b/sdata/dist-arch/previous_dependencies.conf
@@ -2,7 +2,6 @@
### Must be one package per line as it needs to be compared against the explicitly installed list from pacman
illogical-impulse-ags
archlinux-xdg-menu
-axel
bc
coreutils
cliphist
@@ -14,7 +13,6 @@ wget
ripgrep
gojq
npm
-meson
typescript
gjs
xdg-user-dirs
diff --git a/sdata/dist-nix/README.md b/sdata/dist-nix/README.md
index 20f80025d..5febf4698 100644
--- a/sdata/dist-nix/README.md
+++ b/sdata/dist-nix/README.md
@@ -9,7 +9,12 @@
Note that this script must be idempotent.
TODO:
-- [ ] Write a proper `flake.nix` and `home.nix` and other files under `dist-nix/home-manager/` to install all dependencies that `dist-arch/` does. (**excluding** the screenlock)
+- [ ] Fix all TODOs inside `dist-nix`.
+- [ ] Warn user if inode-limited filesystem (typically ext4) is used.
+- [ ] Deal with error when running `systemctl --user enable ydotool --now`:
+ ```plain
+ Failed to connect to user scope bus via local transport: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=@.host --user to connect to bus of other user)
+ ```
## Attentions
### PAM
diff --git a/sdata/dist-nix/home-manager/flake.lock b/sdata/dist-nix/home-manager/flake.lock
index 3c2f0f3f0..c184eee32 100644
--- a/sdata/dist-nix/home-manager/flake.lock
+++ b/sdata/dist-nix/home-manager/flake.lock
@@ -1,57 +1,8 @@
{
"nodes": {
- "aquamarine": {
- "inputs": {
- "hyprutils": [
- "hyprland",
- "hyprutils"
- ],
- "hyprwayland-scanner": [
- "hyprland",
- "hyprwayland-scanner"
- ],
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1760101617,
- "narHash": "sha256-8jf/3ZCi+B7zYpIyV04+3wm72BD7Z801IlOzsOACR7I=",
- "owner": "hyprwm",
- "repo": "aquamarine",
- "rev": "1826a9923881320306231b1c2090379ebf9fa4f8",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "aquamarine",
- "type": "github"
- }
- },
- "flake-compat": {
- "flake": false,
- "locked": {
- "lastModified": 1747046372,
- "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
- "owner": "edolstra",
- "repo": "flake-compat",
- "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
- "type": "github"
- },
- "original": {
- "owner": "edolstra",
- "repo": "flake-compat",
- "type": "github"
- }
- },
"flake-utils": {
"inputs": {
- "systems": "systems_2"
+ "systems": "systems"
},
"locked": {
"lastModified": 1731533236,
@@ -67,28 +18,6 @@
"type": "github"
}
},
- "gitignore": {
- "inputs": {
- "nixpkgs": [
- "hyprland",
- "pre-commit-hooks",
- "nixpkgs"
- ]
- },
- "locked": {
- "lastModified": 1709087332,
- "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
- "owner": "hercules-ci",
- "repo": "gitignore.nix",
- "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
- "type": "github"
- },
- "original": {
- "owner": "hercules-ci",
- "repo": "gitignore.nix",
- "type": "github"
- }
- },
"home-manager": {
"inputs": {
"nixpkgs": [
@@ -110,269 +39,10 @@
"type": "github"
}
},
- "hyprcursor": {
- "inputs": {
- "hyprlang": [
- "hyprland",
- "hyprlang"
- ],
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1753964049,
- "narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=",
- "owner": "hyprwm",
- "repo": "hyprcursor",
- "rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprcursor",
- "type": "github"
- }
- },
- "hyprgraphics": {
- "inputs": {
- "hyprutils": [
- "hyprland",
- "hyprutils"
- ],
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1760445448,
- "narHash": "sha256-fXGjL6dw31FPFRrmIemzGiNSlfvEJTJNsmadZi+qNhI=",
- "owner": "hyprwm",
- "repo": "hyprgraphics",
- "rev": "50fb9f069219f338a11cf0bcccb9e58357d67757",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprgraphics",
- "type": "github"
- }
- },
- "hyprland": {
- "inputs": {
- "aquamarine": "aquamarine",
- "hyprcursor": "hyprcursor",
- "hyprgraphics": "hyprgraphics",
- "hyprland-protocols": "hyprland-protocols",
- "hyprland-qtutils": "hyprland-qtutils",
- "hyprlang": "hyprlang",
- "hyprutils": "hyprutils",
- "hyprwayland-scanner": "hyprwayland-scanner",
- "nixpkgs": "nixpkgs",
- "pre-commit-hooks": "pre-commit-hooks",
- "systems": "systems",
- "xdph": "xdph"
- },
- "locked": {
- "lastModified": 1761780088,
- "narHash": "sha256-ylKrWQeIAGyysfHbgZpcWUs9UsbiOBIVXTPqaiV3lf0=",
- "owner": "hyprwm",
- "repo": "Hyprland",
- "rev": "6ade4d58cab67e18aa758ef664e36421cab4d8b2",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "Hyprland",
- "type": "github"
- }
- },
- "hyprland-protocols": {
- "inputs": {
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1759610243,
- "narHash": "sha256-+KEVnKBe8wz+a6dTLq8YDcF3UrhQElwsYJaVaHXJtoI=",
- "owner": "hyprwm",
- "repo": "hyprland-protocols",
- "rev": "bd153e76f751f150a09328dbdeb5e4fab9d23622",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprland-protocols",
- "type": "github"
- }
- },
- "hyprland-qt-support": {
- "inputs": {
- "hyprlang": [
- "hyprland",
- "hyprland-qtutils",
- "hyprlang"
- ],
- "nixpkgs": [
- "hyprland",
- "hyprland-qtutils",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "hyprland-qtutils",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1749154592,
- "narHash": "sha256-DO7z5CeT/ddSGDEnK9mAXm1qlGL47L3VAHLlLXoCjhE=",
- "owner": "hyprwm",
- "repo": "hyprland-qt-support",
- "rev": "4c8053c3c888138a30c3a6c45c2e45f5484f2074",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprland-qt-support",
- "type": "github"
- }
- },
- "hyprland-qtutils": {
- "inputs": {
- "hyprland-qt-support": "hyprland-qt-support",
- "hyprlang": [
- "hyprland",
- "hyprlang"
- ],
- "hyprutils": [
- "hyprland",
- "hyprland-qtutils",
- "hyprlang",
- "hyprutils"
- ],
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1759080228,
- "narHash": "sha256-RgDoAja0T1hnF0pTc56xPfLfFOO8Utol2iITwYbUhTk=",
- "owner": "hyprwm",
- "repo": "hyprland-qtutils",
- "rev": "629b15c19fa4082e4ce6be09fdb89e8c3312aed7",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprland-qtutils",
- "type": "github"
- }
- },
- "hyprlang": {
- "inputs": {
- "hyprutils": [
- "hyprland",
- "hyprutils"
- ],
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1758927902,
- "narHash": "sha256-LZgMds7M94+vuMql2bERQ6LiFFdhgsEFezE4Vn+Ys3A=",
- "owner": "hyprwm",
- "repo": "hyprlang",
- "rev": "4dafa28d4f79877d67a7d1a654cddccf8ebf15da",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprlang",
- "type": "github"
- }
- },
- "hyprutils": {
- "inputs": {
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1759619523,
- "narHash": "sha256-r1ed7AR2ZEb2U8gy321/Xcp1ho2tzn+gG1te/Wxsj1A=",
- "owner": "hyprwm",
- "repo": "hyprutils",
- "rev": "3df7bde01efb3a3e8e678d1155f2aa3f19e177ef",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprutils",
- "type": "github"
- }
- },
- "hyprwayland-scanner": {
- "inputs": {
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1755184602,
- "narHash": "sha256-RCBQN8xuADB0LEgaKbfRqwm6CdyopE1xIEhNc67FAbw=",
- "owner": "hyprwm",
- "repo": "hyprwayland-scanner",
- "rev": "b3b0f1f40ae09d4447c20608e5a4faf8bf3c492d",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "hyprwayland-scanner",
- "type": "github"
- }
- },
"nixgl": {
"inputs": {
"flake-utils": "flake-utils",
- "nixpkgs": "nixpkgs_2"
+ "nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1752054764,
@@ -389,22 +59,6 @@
}
},
"nixpkgs": {
- "locked": {
- "lastModified": 1761114652,
- "narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c",
- "type": "github"
- },
- "original": {
- "owner": "NixOS",
- "ref": "nixos-unstable",
- "repo": "nixpkgs",
- "type": "github"
- }
- },
- "nixpkgs_2": {
"locked": {
"lastModified": 1746378225,
"narHash": "sha256-OeRSuL8PUjIfL3Q0fTbNJD/fmv1R+K2JAOqWJd3Oceg=",
@@ -419,7 +73,7 @@
"type": "github"
}
},
- "nixpkgs_3": {
+ "nixpkgs_2": {
"locked": {
"lastModified": 1761597516,
"narHash": "sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8+ON/0Yy8+a5vsDU=",
@@ -434,53 +88,36 @@
"type": "indirect"
}
},
- "pre-commit-hooks": {
+ "quickshell": {
"inputs": {
- "flake-compat": "flake-compat",
- "gitignore": "gitignore",
"nixpkgs": [
- "hyprland",
"nixpkgs"
]
},
"locked": {
- "lastModified": 1760663237,
- "narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=",
- "owner": "cachix",
- "repo": "git-hooks.nix",
- "rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37",
+ "lastModified": 1761821581,
+ "narHash": "sha256-nLuc6jA7z+H/6bHPEBSOYPbz7RtvNCZiTKmYItJuBmM=",
+ "owner": "quickshell-mirror",
+ "repo": "quickshell",
+ "rev": "db1777c20b936a86528c1095cbcb1ebd92801402",
"type": "github"
},
"original": {
- "owner": "cachix",
- "repo": "git-hooks.nix",
+ "owner": "quickshell-mirror",
+ "repo": "quickshell",
+ "rev": "db1777c20b936a86528c1095cbcb1ebd92801402",
"type": "github"
}
},
"root": {
"inputs": {
"home-manager": "home-manager",
- "hyprland": "hyprland",
"nixgl": "nixgl",
- "nixpkgs": "nixpkgs_3"
+ "nixpkgs": "nixpkgs_2",
+ "quickshell": "quickshell"
}
},
"systems": {
- "locked": {
- "lastModified": 1689347949,
- "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
- "owner": "nix-systems",
- "repo": "default-linux",
- "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
- "type": "github"
- },
- "original": {
- "owner": "nix-systems",
- "repo": "default-linux",
- "type": "github"
- }
- },
- "systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
@@ -494,47 +131,6 @@
"repo": "default",
"type": "github"
}
- },
- "xdph": {
- "inputs": {
- "hyprland-protocols": [
- "hyprland",
- "hyprland-protocols"
- ],
- "hyprlang": [
- "hyprland",
- "hyprlang"
- ],
- "hyprutils": [
- "hyprland",
- "hyprutils"
- ],
- "hyprwayland-scanner": [
- "hyprland",
- "hyprwayland-scanner"
- ],
- "nixpkgs": [
- "hyprland",
- "nixpkgs"
- ],
- "systems": [
- "hyprland",
- "systems"
- ]
- },
- "locked": {
- "lastModified": 1760713634,
- "narHash": "sha256-5HXelmz2x/uO26lvW7MudnadbAfoBnve4tRBiDVLtOM=",
- "owner": "hyprwm",
- "repo": "xdg-desktop-portal-hyprland",
- "rev": "753bbbdf6a052994da94062e5b753288cef28dfb",
- "type": "github"
- },
- "original": {
- "owner": "hyprwm",
- "repo": "xdg-desktop-portal-hyprland",
- "type": "github"
- }
}
},
"root": "root",
diff --git a/sdata/dist-nix/home-manager/flake.nix b/sdata/dist-nix/home-manager/flake.nix
index 3422f5c4b..d9b9a30b6 100644
--- a/sdata/dist-nix/home-manager/flake.nix
+++ b/sdata/dist-nix/home-manager/flake.nix
@@ -9,13 +9,17 @@
url = "github:nix-community/home-manager/release-25.05";
inputs.nixpkgs.follows = "nixpkgs";
};
- hyprland = {
- url = "github:hyprwm/Hyprland";
- };
+ #hyprland = {
+ # url = "github:hyprwm/Hyprland";
+ #};
nixgl.url = "github:nix-community/nixGL";
+ quickshell = {
+ url = "github:quickshell-mirror/quickshell/db1777c20b936a86528c1095cbcb1ebd92801402";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
};
- outputs = { nixpkgs, home-manager, nixgl, ... }:
+ outputs = { nixpkgs, home-manager, nixgl, quickshell, ... }:
let
home_attrs = rec {
username = import ./username.nix;
@@ -31,7 +35,7 @@
homeConfigurations = {
illogical_impulse = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
- extraSpecialArgs = { inherit nixgl home_attrs; };
+ extraSpecialArgs = { inherit home_attrs nixgl quickshell; };
modules = [
./home.nix
];
diff --git a/sdata/dist-nix/home-manager/home.nix b/sdata/dist-nix/home-manager/home.nix
index 39d84584e..63a895af0 100644
--- a/sdata/dist-nix/home-manager/home.nix
+++ b/sdata/dist-nix/home-manager/home.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, nixgl, home_attrs, ... }:
+{ config, lib, pkgs, nixgl, quickshell, home_attrs, ... }:
{
programs.home-manager.enable = true;
nixGL.packages = nixgl.packages;
@@ -10,6 +10,7 @@
xdg-desktop-portal-gnome
xdg-desktop-portal-gtk
xdg-desktop-portal-wlr
+ kdePackages.xdg-desktop-portal-kde
];
config.hyprland = {
default = [ "hyprland" "gtk" ];
@@ -21,7 +22,6 @@
## Allow fontconfig to discover fonts in home.packages
fonts.fontconfig.enable = true;
- # home.sessionVariables.NIXOS_OZONE_WL = "1";
wayland.windowManager.hyprland = {
## Make sure home-manager not generate ~/.config/hypr/hyprland.conf
systemd.enable = false; plugins = []; settings = {}; extraConfig = "";
@@ -30,44 +30,182 @@
package = config.lib.nixGL.wrap pkgs.hyprland;
};
+
+
home = {
packages = with pkgs; [
##### Sure #####
## Basic cli tool
## inetutils: provides hostname, ifconfig, ping, etc.
## libnotify: provides notify-send
- jq rsync inetutils libnotify
- ## Media related
- brightnessctl pavucontrol
- ## Clipboard/Emoji
- wl-clipboard cliphist
- ## Terminal and shell
- foot cowsay lolcat
+ inetutils libnotify
- ##### Fonts/Icons/Cursors/Decoration #####
- fontconfig
+ ##### Other MISC #####
+ dbus xorg.xlsclients # some basic things
+ foot # Used in Quickshell and Hyprland config; its config is also included
+ kdePackages.kconfig # provide kwriteconfig6, used in install script
- ##### Other basic things #####
- dbus xorg.xlsclients networkmanager
##### Not work, to be solved #####
- # swaylock pamtester
+ # hyprlock pamtester
- # TODO: migrate all packages from dist-arch. Note that for each package, must know why it's needed and how it's used specifically, cuz things may be need tweak to properly use the package installed by Nix, especially those have hardcoded path /usr/* .
+ # NOTE: below are migrated from dist-arch. For each package, must know why it's needed and how it's used specifically, cuz things may be need tweak to properly use the package installed by Nix, for example those have hardcoded path /usr/* .
### illogical-impulse-audio
- libcava #cava
- lxqt.pavucontrol-qt #pavucontrol-qt
+ libcava #cava (Used in Quickshell config)
+ lxqt.pavucontrol-qt #pavucontrol-qt (Used in Hyprland and Quickshell config)
wireplumber #wireplumber (not explicitly used)
- pipewire #pipewire-pulse
- libdbusmenu-gtk3 #libdbusmenu-gtk3 (not explicitly used)
- playerctl #playerctl
+ pipewire #pipewire-pulse (not explicitly used)
+ libdbusmenu-gtk3 #libdbusmenu-gtk3 (not explicitly used)
+ playerctl #playerctl (Used in Hyprland and Quickshell config)
+
### illogical-impulse-backlight
- # TODO: geoclue is used in https://github.com/end-4/dots-hyprland/blob/0551c010b586dbf5578c32de2735698cca0801a7/dots/.config/hypr/hyprland/scripts/start_geoclue_agent.sh with hardcoded absolute path to search the agent. Below will not work without futher tweaks in that start_geoclue_agent.sh
- geoclue2 # geoclue
- brightnessctl # brightnessctl
- ddcutil # ddcutil
+ (geoclue2.override { withDemoAgent = true; }) #geoclue (which demo agent used in Quickshell config)
+ brightnessctl #brightnessctl (Used in Hyprland and Quickshell config)
+ ddcutil #ddcutil (Used in Quickshell config)
+
+
+ ### illogical-impulse-basic
+ bc #bc (Used in quickshell/ii/scripts/colors/switchwall.sh for example)
+ uutils-coreutils-noprefix #coreutils (Too many executables involved, not sure where been used)
+ cliphist #cliphist (Used in Hyprland and Quickshell config)
+ cmake #cmake (Used in building quickshell and MicroTeX)
+ curlFull #curl (Used in Quickshell config)
+ wget #wget (Used in Quickshell config)
+ ripgrep #ripgrep (Not sure where been used)
+ jq #jq (Widely used)
+ xdg-user-dirs #xdg-user-dirs (Used in Hyprland and Quickshell config)
+ rsync #rsync (Used in install script)
+ yq-go #go-yq (Used in install script)
+
+
+ ### illogical-impulse-bibata-modern-classic-bin
+ bibata-cursors #https://github.com/ful1e5/Bibata_Cursor (Used in Hyprland config, not necessary)
+
+
+ ### illogical-impulse-fonts-themes
+ adw-gtk3 #adw-gtk-theme-git (https://github.com/lassekongo83/adw-gtk3) (Used in Quickshell config)
+ kdePackages.breeze kdePackages.breeze-icons #breeze (Used in kdeglobals config)
+ #breeze-plus (https://github.com/mjkim0727/breeze-plus) (TODO: Not available as nixpkg) (Used in kde-material-you-colors config)
+ darkly darkly-qt5 #darkly-bin (darkly is supposed to be set as the theme for Qt apps, just have not figured out how to properly set it yet.)
+ eza #eza (Used in Fish config: `alias ls 'eza --icons'`)
+ #fish (Install via system PM instead)
+ fontconfig #fontconfig (Basic thing)
+ kitty #kitty (Used in fuzzel, Hyprland, kdeglobals and Quickshell config; kitty config is also included as dots)
+ matugen #matugen-bin (Used in Quickshell)
+ #otf-space-grotesk (https://events.ccc.de/congress/2024/infos/styleguide.html) (TODO: Not available as Nixpkg) (Used in Quickshell and matugen config)
+ starship #starship (Used in Fish config)
+ #ttf-gabarito-git (Font name: Gabarito) (Used in fuzzel and Quickshell config) (TODO: Not available as Nixpkg)
+ nerd-fonts.jetbrains-mono #ttf-jetbrains-mono-nerd (Font name: JetBrains Mono NF, JetBrainsMono Nerd Font) (Used in foot, kdeglobals, kitty, qt5ct, qt6ct and Quickshell config)
+ material-symbols #ttf-material-symbols-variable-git (Font name: Material Symbols Rounded, Material Symbols Outlined) (Used in Hyprland, matugen, Quickshell and wlogout config)
+ #ttf-readex-pro (Font name: Readex Pro) (Used in Quickshell config) (TODO: seems not available as nixpkg)
+ roboto-flex #ttf-roboto-flex (Font name: Roboto Flex) (Used in Hyprland, matugen and Quickshell config)
+ rubik #ttf-rubik-vf (Font name: Rubik, Rubik Light) (Used in Hyprland, kdeglobals, matugen, qt5ct, qt6ct and Quickshell config)
+ twemoji-color-font #ttf-twemoji (Not explicitly used, but it may help as fallback for displaying emoji charaters)
+
+
+ ### illogical-impulse-hyprland
+ hypridle #hypridle (Used for loginctl to lock session)
+ #hyprland (Need NixGL, included elsewhere)
+ #hyprlock (Should not be installed via Nix)
+ hyprpicker #hyprpicker (Used in Hyprland and Quickshell config)
+ hyprsunset #hyprsunset (Used in Quickshell config)
+ #xdg-desktop-portal-hyprland (DUPLICATE)
+ wl-clipboard #wl-clipboard (Surely needed)
+
+
+ ### illogical-impulse-kde
+ kdePackages.bluedevil #bluedevil (Seems not being used anywhere, maybe a part of KDE settings panel)
+ #gnome-keyring #gnome-keyring (TODO: Install via system PM instead) (Provide executable gnome-keyring-daemon, used in Hyprland and Quickshell config)
+ networkmanager #networkmanager
+ kdePackages.plasma-nm #plasma-nm (Seems not being used anywhere, maybe a part of KDE settings panel)
+ #polkit-kde-agent (TODO: Install via system PM instead)
+ kdePackages.dolphin #dolphin (Used in Hyprland and Quickshell config)
+ kdePackages.systemsettings #systemsettings (Used in Hyprland keybinds.conf)
+
+
+ ### illogical-impulse-microtex-git
+ # This package will be installed as /opt/MicroTeX
+ #MicroTeX#https://github.com/NanoMichael/MicroTeX
+ # TODO: Not available as nixpkg
+
+
+ ### illogical-impulse-oneui4-icons-git
+ #OneUI4-Icons#https://github.com/end-4/OneUI4-Icons
+ # TODO: Custom repo, need to make a package
+
+
+ ### illogical-impulse-portal
+ #xdg-desktop-portal (Included elsewhere)
+ #xdg-desktop-portal-kde (Included elsewhere)
+ #xdg-desktop-portal-gtk (Included elsewhere)
+ #xdg-desktop-portal-hyprland (Included elsewhere)
+
+
+ ### illogical-impulse-python
+ #clang (Some python package may need this to be built, e.g. #1235; However when cmake is installed by Nix, then pkg-config, cairo etc will be used but they can only be accessible in Nix development environment for example nix-shell, nix develop, etc. See `sdata/uv/shell.nix`. )
+ uv #uv (Used for python venv)
+ gtk4 #gtk4 (Not explicitly used)
+ libadwaita #libadwaita (Not explicitly used)
+ libsoup_3 #libsoup3 (Not explicitly used)
+ libportal-gtk4 #libportal-gtk4 (Not explicitly used)
+ gobject-introspection #gobject-introspection (Not explicitly used)
+
+
+ ### illogical-impulse-quickshell-git
+ #quickshell.packages.x86_64-linux.default (NixGL applicable, included elsewhere)
+
+
+ ### illogical-impulse-screencapture
+ hyprshot #hyprshot (Used in Hyprland keybinds.conf as fallback)
+ slurp #slurp (Used in Hyprland and Quickshell config)
+ swappy #swappy (Used in Quickshell config)
+ tesseract #tesseract (Used in Quickshell and Hyprland config)
+ #tesseract-data-eng (Used as data for tesseract) (TODO: Seems not available as nixpkg)
+ wf-recorder #wf-recorder (Used in Quickshell config)
+
+
+ ### illogical-impulse-toolkit
+ kdePackages.kdialog #kdialog (Used in Quickshell config)
+ # https://nixos.wiki/wiki/Qt
+ # https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/qt-6/srcs.nix
+ qt6.qt5compat #qt6-5compat
+ #qt6.qtimageformats (TODO: really?) #qt6-avif-image-plugin
+ qt6.qtbase #qt6-base
+ qt6.qtdeclarative #qt6-declarative
+ qt6.qtimageformats #qt6-imageformats
+ qt6.qtmultimedia #qt6-multimedia
+ qt6.qtpositioning #qt6-positioning
+ qt6.qtquicktimeline #qt6-quicktimeline
+ qt6.qtsensors #qt6-sensors
+ qt6.qtsvg #qt6-svg
+ qt6.qttools #qt6-tools
+ qt6.qttranslations #qt6-translations
+ qt6.qtvirtualkeyboard #qt6-virtualkeyboard
+ qt6.qtwayland #qt6-wayland
+ kdePackages.syntax-highlighting #syntax-highlighting (Used in Quickshell config)
+ upower #upower (Used in Quickshell config)
+ wtype #wtype (Used in Hyprland scripts/fuzzel-emoji.sh)
+ ydotool #ydotool (Used in Quickshell config)
+
+
+ ### illogical-impulse-widgets
+ fuzzel #fuzzel (Used in Hyprland and Quickshell config; its config is also included)
+ glib #glib2 (Provide executable gsettings) (Used in install script, also in matugen and quickshell config)
+ imagemagick #imagemagick (Provide executable: magick) (Used in Quickshell config)
+ #hypridle (DUPLICATE)
+ #hyprutils (DUPLICATE)
+ #hyprlock (DUPLICATE)
+ #hyprpicker (DUPLICATE)
+ songrec #songrec (Used in Quickshell config)
+ translate-shell #translate-shell (Used in Quickshell config)
+ wlogout #wlogout (Used in Hyprland config)
+
+ ]
+ ++ [
+ #(config.lib.nixGL.wrap pkgs.hyprland)
+ (config.lib.nixGL.wrap quickshell.packages.x86_64-linux.default)
];
}//home_attrs;
}
diff --git a/sdata/dist-nix/install-deps.sh b/sdata/dist-nix/install-deps.sh
index 726a51259..731258e87 100644
--- a/sdata/dist-nix/install-deps.sh
+++ b/sdata/dist-nix/install-deps.sh
@@ -1,6 +1,14 @@
# This script is meant to be sourced.
# It's not for directly running.
+function vianix-warning(){
+ printf "${STY_YELLOW}Currently \"--via-nix\" will run:\n"
+ printf " home-manager switch --flake .#illogical_impulse\n"
+ printf "If you are already using home-manager, it may override your current config,\n"
+ printf "despite that this should be reversible.\n"
+ pause
+}
+
function install_home-manager(){
# https://nix-community.github.io/home-manager/index.xhtml#sec-install-standalone
local cmd=home-manager
@@ -16,6 +24,11 @@ function install_home-manager(){
command -v $cmd && return
echo "Failed in installing $cmd."
echo "Please install it by yourself and then retry."
+ echo ""
+ echo "Hint: It's also possible that the installation is actually successful,"
+ echo "but your \"\$PATH\" is not properly set."
+ echo "This can happen when you have used \"su user\" to switch user."
+ echo "If this is the problem, use \"su - user\" instead."
return 1
}
function install_nix(){
@@ -48,8 +61,8 @@ function install_curl(){
echo "Please install it by yourself and then retry."
return 1
}
-function install_zsh(){
- local cmd=zsh
+function install_fish(){
+ local cmd=fish
if [[ "$OS_DISTRO_ID" == "arch" || "$OS_DISTRO_ID_LIKE" == "arch" || "$OS_DISTRO_ID" == "cachyos" ]]; then
x sudo pacman -Syu
@@ -99,15 +112,18 @@ function hm_deps(){
##################################################
##################################################
+
+vianix-warning
+
if ! command -v curl >/dev/null 2>&1;then
echo -e "${STY_YELLOW}[$0]: \"curl\" not found.${STY_RST}"
showfun install_curl
v install_curl
fi
-if ! command -v zsh >/dev/null 2>&1;then
- echo -e "${STY_YELLOW}[$0]: \"zsh\" not found.${STY_RST}"
- showfun install_zsh
- v install_zsh
+if ! command -v fish >/dev/null 2>&1;then
+ echo -e "${STY_YELLOW}[$0]: \"fish\" not found.${STY_RST}"
+ showfun install_fish
+ v install_fish
fi
if ! command -v swaylock >/dev/null 2>&1;then
echo -e "${STY_YELLOW}[$0]: \"swaylock\" not found.${STY_RST}"
diff --git a/sdata/lib/package-installers.sh b/sdata/lib/package-installers.sh
index 54da9833d..5f71cd7c1 100644
--- a/sdata/lib/package-installers.sh
+++ b/sdata/lib/package-installers.sh
@@ -5,21 +5,6 @@
# This file is provided for any distros, mainly non-Arch(based) distros.
-install-agsv1(){
- x mkdir -p $REPO_ROOT/cache/agsv1
- x cd $REPO_ROOT/cache/agsv1
- try git init -b main
- try git remote add origin https://github.com/Aylur/ags.git
- x git pull origin main && git submodule update --init --recursive
- x git fetch --tags
- x git checkout v1.9.0
- x npm install
- x meson setup build # --reconfigure
- x meson install -C build
- x sudo mv /usr/local/bin/ags{,v1}
- x cd $REPO_ROOT
-}
-
install-Rubik(){
x mkdir -p $REPO_ROOT/cache/Rubik
x cd $REPO_ROOT/cache/Rubik
@@ -68,8 +53,8 @@ install-bibata(){
x cd $REPO_ROOT/cache/bibata-cursor
name="Bibata-Modern-Classic"
file="$name.tar.xz"
- # Use axel because `curl -O` always downloads a file with 0 byte size, idk why
- x axel https://github.com/ful1e5/Bibata_Cursor/releases/latest/download/$file
+ try rm $file
+ x curl -JLO https://github.com/ful1e5/Bibata_Cursor/releases/latest/download/$file
tar -xf $file
x sudo mkdir -p /usr/local/share/icons
x sudo cp -r $name /usr/local/share/icons
@@ -103,6 +88,10 @@ install-python-packages(){
# we need python 3.12 https://github.com/python-pillow/Pillow/issues/8089
x uv venv --prompt .venv $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV) -p 3.12
x source $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate
- x uv pip install -r sdata/uv/requirements.txt
+ if [[ "$INSTALL_VIA_NIX" = true ]]; then
+ x nix-shell ${REPO_ROOT}/sdata/uv/shell.nix --run "uv pip install -r ${REPO_ROOT}/sdata/uv/requirements.txt"
+ else
+ x uv pip install -r ${REPO_ROOT}/sdata/uv/requirements.txt
+ fi
x deactivate
}
diff --git a/sdata/subcmd-install/1.deps-selector.sh b/sdata/subcmd-install/1.deps-selector.sh
index 27661925e..dec23c463 100644
--- a/sdata/subcmd-install/1.deps-selector.sh
+++ b/sdata/subcmd-install/1.deps-selector.sh
@@ -65,9 +65,15 @@ esac
# Helpful link(s):
# http://stackoverflow.com/questions/29581754
# https://github.com/which-distro/os-release
-export OS_RELEASE_FILE=${OS_RELEASE_FILE:-/etc/os-release}
-test -f ${OS_RELEASE_FILE} || \
- ( echo "${OS_RELEASE_FILE} does not exist. Aborting..." ; exit 1 ; )
+OS_RELEASE_FILE_CUSTOM="${REPO_ROOT}/os-release"
+if test -f "${OS_RELEASE_FILE_CUSTOM}"; then
+ printf "${STY_YELLOW}Warning: using custom os-release file \"${OS_RELEASE_FILE_CUSTOM}\".${STY_RST}\n"
+ OS_RELEASE_FILE="${OS_RELEASE_FILE_CUSTOM}"
+elif test -f /etc/os-release; then
+ OS_RELEASE_FILE=/etc/os-release
+else
+ printf "${STY_RED}/etc/os-release does not exist, aborting...${STY_RST}\n" ; exit 1
+fi
export OS_DISTRO_ID=$(awk -F'=' '/^ID=/ { gsub("\"","",$2); print tolower($2) }' ${OS_RELEASE_FILE} 2> /dev/null)
export OS_DISTRO_ID_LIKE=$(awk -F'=' '/^ID_LIKE=/ { gsub("\"","",$2); print tolower($2) }' ${OS_RELEASE_FILE} 2> /dev/null)
diff --git a/sdata/subcmd-install/3.files-exp.sh b/sdata/subcmd-install/3.files-exp.sh
index 8f0bcd8f9..0ff62c0e3 100644
--- a/sdata/subcmd-install/3.files-exp.sh
+++ b/sdata/subcmd-install/3.files-exp.sh
@@ -9,6 +9,7 @@
# TODO: add --exp-files-regen Force copy the default config to ${EXP_FILE_PATH} (auto do this when not existed)
# TODO: Implement versioning, i.e. when user-defined yaml config file has version number mismatch with the default one, produce error. If only minor version number is not the same, the error can be ommitted via --exp-file-no-strict .
# TODO: add --exp-files-no-strict Ignore error when minor version number is not the same
+# TODO: When --via-nix is specified, use dots-extra/vianix/hypridle.conf instead
#
# Stage 2 todos:
# TODO: Implement bool key symlink (both read-write and read-only), when the value of `symlink` is true, then instead using `rsync` or `cp`, use `ln`.
diff --git a/sdata/subcmd-install/3.files-legacy.sh b/sdata/subcmd-install/3.files-legacy.sh
index 608b4ac6d..6f67f0a16 100644
--- a/sdata/subcmd-install/3.files-legacy.sh
+++ b/sdata/subcmd-install/3.files-legacy.sh
@@ -79,13 +79,18 @@ case $SKIP_HYPRLAND in
v cp dots/.config/hypr/hyprland.conf $t
fi
t="$XDG_CONFIG_HOME/hypr/hypridle.conf"
+ if [[ "$INSTALL_VIA_NIX" = true ]]; then
+ s=dots-extra/vianix/hypridle.conf
+ else
+ s=dots/.config/hypr/hypridle.conf
+ fi
if [ -f $t ];then
echo -e "${STY_BLUE}[$0]: \"$t\" already exists.${STY_RST}"
- v cp -f dots/.config/hypr/hypridle.conf $t.new
+ v cp -f $s $t.new
existed_hypridle_conf=y
else
echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RST}"
- v cp dots/.config/hypr/hypridle.conf $t
+ v cp $s $t
existed_hypridle_conf=n
fi
t="$XDG_CONFIG_HOME/hypr/hyprlock.conf"
diff --git a/sdata/uv/shell.nix b/sdata/uv/shell.nix
new file mode 100644
index 000000000..46f9f8f65
--- /dev/null
+++ b/sdata/uv/shell.nix
@@ -0,0 +1,12 @@
+{ pkgs ? import {} }:
+pkgs.mkShell {
+ buildInputs = with pkgs; [
+ pkg-config
+ meson
+ ninja
+ cairo
+ dbus
+ dbus-glib
+ glib
+ ];
+}