mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 14:59:27 -05:00
Merge branch 'end-4:main' into keybinds-settings
This commit is contained in:
+1
-1
@@ -78,7 +78,7 @@ Widget system: Quickshell | Support: Yes
|
||||
|
||||
| AI, settings app | Some widgets |
|
||||
|:---|:---------------|
|
||||
| <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/7b98a354-4489-4a46-aa6a-d08616e77399" /> | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/6eba0d57-2606-4cea-8993-e6f169e82e70" /> |
|
||||
| <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/ea0154a1-e984-4bb6-a424-23247cefe3c6" /> | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/6eba0d57-2606-4cea-8993-e6f169e82e70" /> |
|
||||
| Window management | Weeb power |
|
||||
| <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/e77a7c96-1905-4126-a2a0-434f818825a2" /> | <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/c8544e99-8881-477f-b83a-d6e35c0184a1" /> |
|
||||
|
||||
|
||||
@@ -5,3 +5,4 @@ __pycache__/
|
||||
*.py[cod]
|
||||
dots/.config/quickshell/ii/.qmlls.ini
|
||||
.update-lock
|
||||
/os-release
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
This folder contains tweakd configs when --via-nix is specified.
|
||||
@@ -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
|
||||
}
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -334,7 +334,6 @@ Variants {
|
||||
font {
|
||||
pixelSize: Appearance.font.pixelSize.normal
|
||||
weight: 350
|
||||
italic: true
|
||||
}
|
||||
color: bgRoot.colText
|
||||
style: Text.Raised
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainLayout
|
||||
anchors.centerIn: parent
|
||||
spacing: root.spacing
|
||||
|
||||
Repeater { // Main table rows
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ ToolbarButton {
|
||||
|
||||
contentItem: Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: 6
|
||||
spacing: 4
|
||||
|
||||
MaterialSymbol {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 (%)")
|
||||
|
||||
@@ -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 = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ Scope { // Scope
|
||||
sourceComponent: FloatingWindow {
|
||||
id: detachedSidebarRoot
|
||||
property var contentParent: detachedSidebarBackground
|
||||
color: "transparent"
|
||||
|
||||
visible: GlobalStates.sidebarLeftOpen
|
||||
onVisibleChanged: {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<string> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -29,7 +29,7 @@ AbstractQuickPanel {
|
||||
readonly property real baseCellHeight: 56
|
||||
|
||||
// Toggles
|
||||
readonly property list<string> availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile","musicRecognition"]
|
||||
readonly property list<string> 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<var> toggles: Config.ready ? Config.options.sidebar.quickToggles.android.toggles : []
|
||||
readonly property list<var> toggleRows: toggleRowsForList(toggles)
|
||||
|
||||
+29
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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: () => {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
|
||||
toggled: false
|
||||
buttonIcon: "cloud_lock"
|
||||
|
||||
onClicked: {
|
||||
mainAction: () => {
|
||||
if (toggled) {
|
||||
root.toggled = false
|
||||
Quickshell.execDetached(["warp-cli", "disconnect"])
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
|
||||
toggled: false
|
||||
buttonIcon: "colorize"
|
||||
|
||||
onClicked: {
|
||||
mainAction: () => {
|
||||
GlobalStates.sidebarRightOpen = false;
|
||||
delayedActionTimer.start()
|
||||
}
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ AndroidQuickToggleButton {
|
||||
EasyEffects.fetchActiveState()
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
mainAction: () => {
|
||||
EasyEffects.toggle()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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"`])
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ AndroidQuickToggleButton {
|
||||
|
||||
toggled: Idle.inhibit
|
||||
buttonIcon: "coffee"
|
||||
onClicked: {
|
||||
mainAction: () => {
|
||||
Idle.toggleInhibit()
|
||||
}
|
||||
StyledToolTip {
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ AndroidQuickToggleButton {
|
||||
text: Translation.tr("Recognize music | Right-click to toggle source")
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
mainAction: () => {
|
||||
SongRec.toggleRunning()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ AndroidQuickToggleButton {
|
||||
|
||||
toggled: Network.wifiStatus !== "disabled"
|
||||
buttonIcon: Network.materialSymbol
|
||||
onClicked: Network.toggleWifi()
|
||||
mainAction: () => Network.toggleWifi()
|
||||
altAction: () => {
|
||||
root.openMenu()
|
||||
}
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ AndroidQuickToggleButton {
|
||||
|
||||
toggled: Hyprsunset.active
|
||||
buttonIcon: auto ? "night_sight_auto" : "bedtime"
|
||||
onClicked: {
|
||||
|
||||
mainAction: () => {
|
||||
Hyprsunset.toggle()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ AndroidQuickToggleButton {
|
||||
toggled: !Notifications.silent
|
||||
buttonIcon: toggled ? "notifications_active" : "notifications_paused"
|
||||
|
||||
onClicked: {
|
||||
mainAction: () => {
|
||||
Notifications.silent = !Notifications.silent;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ AndroidQuickToggleButton {
|
||||
name: Translation.tr("Virtual Keyboard")
|
||||
toggled: GlobalStates.oskOpen
|
||||
buttonIcon: toggled ? "keyboard_hide" : "keyboard"
|
||||
onClicked: {
|
||||
|
||||
mainAction: () => {
|
||||
GlobalStates.oskOpen = !GlobalStates.oskOpen
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+56
-21
@@ -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
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ AndroidQuickToggleButton {
|
||||
toggled: false
|
||||
buttonIcon: "screenshot_region"
|
||||
|
||||
onClicked: {
|
||||
mainAction: () => {
|
||||
GlobalStates.sidebarRightOpen = false;
|
||||
delayedActionTimer.start()
|
||||
}
|
||||
|
||||
+16
@@ -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()
|
||||
}
|
||||
} }
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ pkgdesc='Illogical Impulse Backlight Dependencies'
|
||||
arch=(any)
|
||||
license=(None)
|
||||
depends=(
|
||||
geoclue
|
||||
brightnessctl
|
||||
ddcutil
|
||||
geoclue
|
||||
brightnessctl
|
||||
ddcutil
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -12,5 +12,4 @@ depends=(
|
||||
libsoup3
|
||||
libportal-gtk4
|
||||
gobject-introspection
|
||||
sassc
|
||||
)
|
||||
|
||||
@@ -44,7 +44,7 @@ _pkgsrc="$_pkgname"
|
||||
source=("$_pkgsrc::git+$url.git#commit=$_commit"
|
||||
quickshell-check.hook)
|
||||
sha256sums=('SKIP'
|
||||
'8543e21aeaaa5441b73a679160e7601a957f16c433e8d6bd9257e80bd0e94083')
|
||||
'8543e21aeaaa5441b73a679160e7601a957f16c433e8d6bd9257e80bd0e94083')
|
||||
|
||||
|
||||
pkgver() {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=<user>@.host --user to connect to bus of other user)
|
||||
```
|
||||
|
||||
## Attentions
|
||||
### PAM
|
||||
|
||||
Generated
+14
-418
@@ -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",
|
||||
|
||||
@@ -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
|
||||
];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
pkg-config
|
||||
meson
|
||||
ninja
|
||||
cairo
|
||||
dbus
|
||||
dbus-glib
|
||||
glib
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user