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 main
This commit is contained in:
@@ -74,6 +74,9 @@ windowrulev2 = immediate, title:.*\.exe
|
||||
windowrulev2 = immediate, title:.*minecraft.*
|
||||
windowrulev2 = immediate, class:^(steam_app).*
|
||||
|
||||
# Fix Jetbrain IDEs focus/rerendering problem
|
||||
windowrulev2=noinitialfocus,class:^jetbrains-.*$,floating:1,title:^$|^\s$|^win\d+$
|
||||
|
||||
# No shadow for tiled windows (matches windows that are not floating).
|
||||
windowrulev2 = noshadow, floating:0
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import qs.modules.common
|
||||
import qs
|
||||
import qs.modules.common
|
||||
import qs.services
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
@@ -44,6 +45,13 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
onSidebarRightOpenChanged: {
|
||||
if (GlobalStates.sidebarRightOpen) {
|
||||
Notifications.timeoutAll();
|
||||
Notifications.markAllRead();
|
||||
}
|
||||
}
|
||||
|
||||
property real screenZoom: 1
|
||||
onScreenZoomChanged: {
|
||||
Quickshell.execDetached(["hyprctl", "keyword", "cursor:zoom_factor", root.screenZoom.toString()]);
|
||||
|
||||
@@ -58,7 +58,7 @@ Scope {
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
onPressed: {
|
||||
popupLoader.active = false
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,10 @@ Item {
|
||||
|
||||
Behavior on rotation {
|
||||
enabled: Config.options.background.clock.cookie.constantlyRotate // Animating every second is expensive...
|
||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
animation: NumberAnimation {
|
||||
duration: 1000 // 1 second
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -295,6 +295,48 @@ Item { // Bar content region
|
||||
Layout.rightMargin: indicatorsRowLayout.realSpacing
|
||||
color: rightSidebarButton.colText
|
||||
}
|
||||
Revealer {
|
||||
reveal: Notifications.silent || Notifications.unread > 0
|
||||
Layout.fillHeight: true
|
||||
Layout.rightMargin: reveal ? indicatorsRowLayout.realSpacing : 0
|
||||
implicitHeight: reveal ? notificationIcon.implicitHeight : 0
|
||||
implicitWidth: reveal ? notificationIcon.implicitWidth : 0
|
||||
Behavior on Layout.rightMargin {
|
||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
}
|
||||
Rectangle {
|
||||
id: notifPing
|
||||
visible: !Notifications.silent && Notifications.unread > 0
|
||||
property bool showUnreadCount: Config.options.bar.indicators.notifications.showUnreadCount
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
rightMargin: showUnreadCount ? 0 : 1
|
||||
topMargin: showUnreadCount ? 0 : 3
|
||||
}
|
||||
radius: Appearance.rounding.full
|
||||
color: Appearance.colors.colOnLayer0
|
||||
z: 1
|
||||
|
||||
implicitHeight: showUnreadCount ? Math.max(notificationCounterText.implicitWidth, notificationCounterText.implicitHeight) : 8
|
||||
implicitWidth: implicitHeight
|
||||
|
||||
StyledText {
|
||||
id: notificationCounterText
|
||||
visible: notifPing.showUnreadCount
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Appearance.font.pixelSize.smallest
|
||||
color: Appearance.colors.colLayer0
|
||||
text: Notifications.unread
|
||||
}
|
||||
}
|
||||
MaterialSymbol {
|
||||
id: notificationIcon
|
||||
text: Notifications.silent ? "notifications_paused" : "notifications"
|
||||
iconSize: Appearance.font.pixelSize.larger
|
||||
color: rightSidebarButton.colText
|
||||
}
|
||||
}
|
||||
MaterialSymbol {
|
||||
Layout.rightMargin: indicatorsRowLayout.realSpacing
|
||||
text: Network.materialSymbol
|
||||
@@ -302,6 +344,7 @@ Item { // Bar content region
|
||||
color: rightSidebarButton.colText
|
||||
}
|
||||
MaterialSymbol {
|
||||
visible: BluetoothStatus.available
|
||||
text: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled"
|
||||
iconSize: Appearance.font.pixelSize.larger
|
||||
color: rightSidebarButton.colText
|
||||
|
||||
@@ -75,7 +75,7 @@ Item {
|
||||
toggled: root.trayOverflowOpen
|
||||
property bool containsMouse: hovered
|
||||
|
||||
onClicked: root.trayOverflowOpen = !root.trayOverflowOpen
|
||||
downAction: () => root.trayOverflowOpen = !root.trayOverflowOpen
|
||||
|
||||
Layout.fillHeight: !root.vertical
|
||||
Layout.fillWidth: root.vertical
|
||||
|
||||
@@ -48,7 +48,7 @@ PopupWindow {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.BackButton | Qt.RightButton
|
||||
onClicked: event => {
|
||||
onPressed: event => {
|
||||
if ((event.button === Qt.BackButton || event.button === Qt.RightButton) && stackView.depth > 1)
|
||||
stackView.pop();
|
||||
}
|
||||
@@ -152,7 +152,7 @@ PopupWindow {
|
||||
implicitWidth: contentItem.implicitWidth + horizontalPadding * 2
|
||||
implicitHeight: 36
|
||||
|
||||
onClicked: stackView.pop()
|
||||
downAction: () => stackView.pop()
|
||||
|
||||
contentItem: RowLayout {
|
||||
anchors {
|
||||
|
||||
@@ -15,7 +15,7 @@ MouseArea {
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
onPressed: {
|
||||
Weather.getData();
|
||||
Quickshell.execDetached(["notify-send",
|
||||
Translation.tr("Weather"),
|
||||
|
||||
@@ -18,7 +18,9 @@ Singleton {
|
||||
// Transparency. The quadratic functions were derived from analysis of hand-picked transparency values.
|
||||
ColorQuantizer {
|
||||
id: wallColorQuant
|
||||
source: Qt.resolvedUrl(Config.options.background.wallpaperPath)
|
||||
property string wallpaperPath: Config.options.background.wallpaperPath
|
||||
property bool wallpaperIsVideo: wallpaperPath.endsWith(".mp4") || wallpaperPath.endsWith(".webm") || wallpaperPath.endsWith(".mkv") || wallpaperPath.endsWith(".avi") || wallpaperPath.endsWith(".mov")
|
||||
source: Qt.resolvedUrl(wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath)
|
||||
depth: 0 // 2^0 = 1 color
|
||||
rescaleSize: 10
|
||||
}
|
||||
@@ -303,7 +305,7 @@ Singleton {
|
||||
}
|
||||
|
||||
property QtObject elementResize: QtObject {
|
||||
property int duration: 400
|
||||
property int duration: 300
|
||||
property int type: Easing.BezierSpline
|
||||
property list<real> bezierCurve: animationCurves.emphasized
|
||||
property int velocity: 650
|
||||
|
||||
@@ -137,7 +137,7 @@ Singleton {
|
||||
property string secondHandStyle: "dot" // Options: "dot", "line" , "hide"
|
||||
property string dateStyle: "bubble" // Options: "border", "rect", "bubble" , "hide"
|
||||
property bool timeIndicators: true
|
||||
property bool hourMarks: true
|
||||
property bool hourMarks: false
|
||||
property bool dateInClock: true
|
||||
property bool constantlyRotate: false
|
||||
}
|
||||
@@ -212,6 +212,11 @@ Singleton {
|
||||
property bool useUSCS: false // Instead of metric (SI) units
|
||||
property int fetchInterval: 10 // minutes
|
||||
}
|
||||
property JsonObject indicators: JsonObject {
|
||||
property JsonObject notifications: JsonObject {
|
||||
property bool showUnreadCount: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property JsonObject battery: JsonObject {
|
||||
@@ -341,8 +346,12 @@ Singleton {
|
||||
property JsonObject sidebar: JsonObject {
|
||||
property bool keepRightSidebarLoaded: true
|
||||
property JsonObject translator: JsonObject {
|
||||
property bool enable: false
|
||||
property int delay: 300 // Delay before sending request. Reduces (potential) rate limits and lag.
|
||||
}
|
||||
property JsonObject ai: JsonObject {
|
||||
property bool textFadeIn: true
|
||||
}
|
||||
property JsonObject booru: JsonObject {
|
||||
property bool allowNsfw: false
|
||||
property string defaultProvider: "yandere"
|
||||
|
||||
@@ -35,7 +35,7 @@ Rectangle {
|
||||
|
||||
RippleButton {
|
||||
id: parentDirButton
|
||||
onClicked: root.navigateToDirectory(FileUtils.parentDirectory(root.directory))
|
||||
downAction: () => root.navigateToDirectory(FileUtils.parentDirectory(root.directory))
|
||||
contentItem: MaterialSymbol {
|
||||
text: "drive_folder_upload"
|
||||
iconSize: Appearance.font.pixelSize.larger
|
||||
@@ -105,7 +105,7 @@ Rectangle {
|
||||
RippleButton {
|
||||
id: dirEditButton
|
||||
toggled: !root.showBreadcrumb
|
||||
onClicked: root.showBreadcrumb = !root.showBreadcrumb
|
||||
downAction: () => root.showBreadcrumb = !root.showBreadcrumb
|
||||
contentItem: MaterialSymbol {
|
||||
text: "edit"
|
||||
iconSize: Appearance.font.pixelSize.larger
|
||||
|
||||
@@ -23,6 +23,7 @@ ColumnLayout {
|
||||
text: root.title
|
||||
font.pixelSize: Appearance.font.pixelSize.larger
|
||||
font.weight: Font.Medium
|
||||
color: Appearance.colors.colOnSecondaryContainer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import QtQuick
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
|
||||
MaterialCookie {
|
||||
id: root
|
||||
property alias text: symbol.text
|
||||
property alias iconSize: symbol.iconSize
|
||||
property alias font: symbol.font
|
||||
property alias colSymbol: symbol.color
|
||||
property real padding: 6
|
||||
|
||||
color: Appearance.colors.colSecondaryContainer
|
||||
colSymbol: Appearance.colors.colOnSecondaryContainer
|
||||
|
||||
sides: 5
|
||||
|
||||
implicitSize: Math.max(symbol.implicitWidth, symbol.implicitHeight) + padding * 2
|
||||
|
||||
MaterialSymbol {
|
||||
id: symbol
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,7 +32,7 @@ Button {
|
||||
implicitWidth: (root.down && bounce) ? clickedWidth : baseWidth
|
||||
implicitHeight: (root.down && bounce) ? clickedHeight : baseHeight
|
||||
|
||||
property color colBackground: ColorUtils.transparentize(Appearance?.colors.colLayer1Hover, 1) || "transparent"
|
||||
property color colBackground: ColorUtils.transparentize(colBackgroundHover, 1) || "transparent"
|
||||
property color colBackgroundHover: Appearance?.colors.colLayer1Hover ?? "#E5DFED"
|
||||
property color colBackgroundActive: Appearance?.colors.colLayer1Active ?? "#D6CEE2"
|
||||
property color colBackgroundToggled: Appearance?.colors.colPrimary ?? "#65558F"
|
||||
|
||||
@@ -9,7 +9,7 @@ RippleButton {
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
Layout.leftMargin: 8
|
||||
onClicked: {
|
||||
downAction: () => {
|
||||
parent.expanded = !parent.expanded;
|
||||
}
|
||||
buttonRadius: Appearance.rounding.full
|
||||
|
||||
@@ -6,25 +6,25 @@ import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Services.Notifications
|
||||
|
||||
Rectangle { // App icon
|
||||
MaterialCookie { // App icon
|
||||
id: root
|
||||
property var appIcon: ""
|
||||
property var summary: ""
|
||||
property var urgency: NotificationUrgency.Normal
|
||||
property bool isUrgent: urgency === NotificationUrgency.Critical
|
||||
property var image: ""
|
||||
property real scale: 1
|
||||
property real size: 38 * scale
|
||||
property real materialIconScale: 0.57
|
||||
property real appIconScale: 0.8
|
||||
property real smallAppIconScale: 0.49
|
||||
property real materialIconSize: size * materialIconScale
|
||||
property real appIconSize: size * appIconScale
|
||||
property real smallAppIconSize: size * smallAppIconScale
|
||||
property real materialIconSize: implicitSize * materialIconScale
|
||||
property real appIconSize: implicitSize * appIconScale
|
||||
property real smallAppIconSize: implicitSize * smallAppIconScale
|
||||
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
radius: Appearance.rounding.full
|
||||
color: Appearance.colors.colSecondaryContainer
|
||||
implicitSize: 38 * scale
|
||||
sides: isUrgent ? 10 : 0
|
||||
amplitude: implicitSize / 24
|
||||
|
||||
color: isUrgent ? Appearance.colors.colPrimary : Appearance.colors.colSecondaryContainer
|
||||
Loader {
|
||||
id: materialSymbolLoader
|
||||
active: root.appIcon == ""
|
||||
@@ -34,12 +34,10 @@ Rectangle { // App icon
|
||||
const defaultIcon = NotificationUtils.findSuitableMaterialSymbol("")
|
||||
const guessedIcon = NotificationUtils.findSuitableMaterialSymbol(root.summary)
|
||||
return (root.urgency == NotificationUrgency.Critical && guessedIcon === defaultIcon) ?
|
||||
"release_alert" : guessedIcon
|
||||
"priority_high" : guessedIcon
|
||||
}
|
||||
anchors.fill: parent
|
||||
color: (root.urgency == NotificationUrgency.Critical) ?
|
||||
ColorUtils.mix(Appearance.m3colors.m3onSecondary, Appearance.m3colors.m3onSecondaryContainer, 0.1) :
|
||||
Appearance.m3colors.m3onSecondaryContainer
|
||||
color: isUrgent ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer
|
||||
iconSize: root.materialIconSize
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
@@ -6,6 +6,7 @@ import "./notification_utils.js" as NotificationUtils
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Services.Notifications
|
||||
|
||||
/**
|
||||
* A group of notifications from the same app.
|
||||
@@ -154,6 +155,8 @@ MouseArea { // Notification group area
|
||||
image: root?.multipleNotifications ? "" : notificationGroup?.notifications[0]?.image ?? ""
|
||||
appIcon: notificationGroup?.appIcon
|
||||
summary: notificationGroup?.notifications[root.notificationCount - 1]?.summary
|
||||
urgency: root.notifications.some(n => n.urgency === NotificationUrgency.Critical.toString()) ?
|
||||
NotificationUrgency.Critical : NotificationUrgency.Normal
|
||||
}
|
||||
|
||||
ColumnLayout { // Content
|
||||
|
||||
@@ -32,7 +32,8 @@ TabButton {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: (event) => {
|
||||
onPressed: (event) => {
|
||||
button.click() // Because the MouseArea already consumed the event
|
||||
const {x,y} = event
|
||||
const stateY = buttonBackground.y;
|
||||
rippleAnim.x = x;
|
||||
@@ -46,7 +47,6 @@ TabButton {
|
||||
rippleAnim.restart();
|
||||
}
|
||||
onReleased: (event) => {
|
||||
button.click() // Because the MouseArea already consumed the event
|
||||
rippleFadeAnim.restart();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ TabButton {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: (event) => {
|
||||
onPressed: (event) => {
|
||||
root.click() // Because the MouseArea already consumed the event
|
||||
const {x,y} = event
|
||||
const stateY = buttonBackground.y;
|
||||
rippleAnim.x = x;
|
||||
@@ -44,7 +45,6 @@ TabButton {
|
||||
rippleAnim.restart();
|
||||
}
|
||||
onReleased: (event) => {
|
||||
root.click() // Because the MouseArea already consumed the event
|
||||
rippleFadeAnim.restart();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ Item { // Player instance
|
||||
}
|
||||
TrackChangeButton {
|
||||
iconName: "skip_previous"
|
||||
onClicked: root.player?.previous()
|
||||
downAction: () => root.player?.previous()
|
||||
}
|
||||
Item {
|
||||
id: progressBarContainer
|
||||
@@ -277,7 +277,7 @@ Item { // Player instance
|
||||
}
|
||||
TrackChangeButton {
|
||||
iconName: "skip_next"
|
||||
onClicked: root.player?.next()
|
||||
downAction: () => root.player?.next()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ Item { // Player instance
|
||||
property real size: 44
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
onClicked: root.player.togglePlaying();
|
||||
downAction: () => root.player.togglePlaying();
|
||||
|
||||
buttonRadius: root.player?.isPlaying ? Appearance?.rounding.normal : size / 2
|
||||
colBackground: root.player?.isPlaying ? blendedColors.colPrimary : blendedColors.colSecondaryContainer
|
||||
|
||||
@@ -18,7 +18,7 @@ Scope { // Scope
|
||||
baseWidth: 40
|
||||
baseHeight: 40
|
||||
clickedWidth: baseWidth
|
||||
clickedHeight: baseHeight + 20
|
||||
clickedHeight: baseHeight + 10
|
||||
buttonRadius: Appearance.rounding.normal
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ Scope { // Scope
|
||||
VerticalButtonGroup {
|
||||
OskControlButton { // Pin button
|
||||
toggled: root.pinned
|
||||
onClicked: root.pinned = !root.pinned
|
||||
downAction: () => root.pinned = !root.pinned
|
||||
contentItem: MaterialSymbol {
|
||||
text: "keep"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
@@ -111,7 +111,7 @@ Item {
|
||||
id: workspaceArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: {
|
||||
onPressed: {
|
||||
if (root.draggingTargetWorkspace === -1) {
|
||||
GlobalStates.overviewOpen = false
|
||||
Hyprland.dispatch(`workspace ${workspaceValue}`)
|
||||
|
||||
@@ -144,41 +144,13 @@ ContentPage {
|
||||
title: Translation.tr("Policies")
|
||||
|
||||
ConfigRow {
|
||||
ColumnLayout {
|
||||
// Weeb policy
|
||||
ContentSubsectionLabel {
|
||||
text: Translation.tr("Weeb")
|
||||
}
|
||||
ConfigSelectionArray {
|
||||
currentValue: Config.options.policies.weeb
|
||||
onSelected: newValue => {
|
||||
Config.options.policies.weeb = newValue;
|
||||
}
|
||||
options: [
|
||||
{
|
||||
displayName: Translation.tr("No"),
|
||||
icon: "close",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
displayName: Translation.tr("Yes"),
|
||||
icon: "check",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
displayName: Translation.tr("Closet"),
|
||||
icon: "ev_shadow",
|
||||
value: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// AI policy
|
||||
ColumnLayout {
|
||||
// AI policy
|
||||
ContentSubsectionLabel {
|
||||
text: Translation.tr("AI")
|
||||
}
|
||||
|
||||
ConfigSelectionArray {
|
||||
currentValue: Config.options.policies.ai
|
||||
onSelected: newValue => {
|
||||
@@ -203,6 +175,38 @@ ContentPage {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Weeb policy
|
||||
ColumnLayout {
|
||||
|
||||
ContentSubsectionLabel {
|
||||
text: Translation.tr("Weeb")
|
||||
}
|
||||
|
||||
ConfigSelectionArray {
|
||||
currentValue: Config.options.policies.weeb
|
||||
onSelected: newValue => {
|
||||
Config.options.policies.weeb = newValue;
|
||||
}
|
||||
options: [
|
||||
{
|
||||
displayName: Translation.tr("No"),
|
||||
icon: "close",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
displayName: Translation.tr("Yes"),
|
||||
icon: "check",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
displayName: Translation.tr("Closet"),
|
||||
icon: "ev_shadow",
|
||||
value: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ ContentPage {
|
||||
icon: "add_triangle"
|
||||
text: Translation.tr("Sides")
|
||||
value: Config.options.background.clock.cookie.sides
|
||||
from: 1
|
||||
to: 36
|
||||
from: 0
|
||||
to: 40
|
||||
stepSize: 1
|
||||
onValueChanged: {
|
||||
Config.options.background.clock.cookie.sides = value;
|
||||
@@ -569,6 +569,15 @@ ContentPage {
|
||||
}
|
||||
}
|
||||
|
||||
ConfigSwitch {
|
||||
buttonIcon: "translate"
|
||||
text: Translation.tr('Enable translator')
|
||||
checked: Config.options.sidebar.translator.enable
|
||||
onCheckedChanged: {
|
||||
Config.options.sidebar.translator.enable = checked;
|
||||
}
|
||||
}
|
||||
|
||||
ContentSubsection {
|
||||
title: Translation.tr("Corner open")
|
||||
tooltip: Translation.tr("Allows you to open sidebars by clicking or hovering screen corners regardless of bar position")
|
||||
|
||||
@@ -336,10 +336,10 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
||||
|
||||
property int lastResponseLength: 0
|
||||
onContentHeightChanged: {
|
||||
if (atYEnd) positionViewAtEnd();
|
||||
if (atYEnd) Qt.callLater(positionViewAtEnd);
|
||||
}
|
||||
onCountChanged: { // Auto-scroll when new messages are added
|
||||
if (atYEnd) positionViewAtEnd();
|
||||
if (atYEnd) Qt.callLater(positionViewAtEnd);
|
||||
}
|
||||
|
||||
add: null // Prevent function calls from being janky
|
||||
@@ -374,10 +374,9 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
||||
anchors.centerIn: parent
|
||||
spacing: 5
|
||||
|
||||
MaterialSymbol {
|
||||
CookieWrappedMaterialSymbol {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
iconSize: 60
|
||||
color: Appearance.m3colors.m3outline
|
||||
text: "neurology"
|
||||
}
|
||||
StyledText {
|
||||
@@ -757,8 +756,8 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
||||
delegate: ApiCommandButton {
|
||||
property string commandRepresentation: `${root.commandPrefix}${modelData.name}`
|
||||
buttonText: commandRepresentation
|
||||
onClicked: {
|
||||
if(modelData.sendDirectly) {
|
||||
downAction: () => {
|
||||
if (modelData.sendDirectly) {
|
||||
root.handleInput(commandRepresentation)
|
||||
} else {
|
||||
messageInputField.text = commandRepresentation + (modelData.dontAddSpace ? "" : " ")
|
||||
@@ -778,4 +777,4 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,10 +198,9 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
spacing: 5
|
||||
|
||||
MaterialSymbol {
|
||||
CookieWrappedMaterialSymbol {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
iconSize: 60
|
||||
color: Appearance.m3colors.m3outline
|
||||
text: "bookmark_heart"
|
||||
}
|
||||
StyledText {
|
||||
@@ -525,9 +524,10 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
PointingHandInteraction {}
|
||||
onClicked: {
|
||||
onPressed: {
|
||||
nsfwSwitch.checked = !nsfwSwitch.checked
|
||||
}
|
||||
}
|
||||
@@ -566,8 +566,8 @@ Item {
|
||||
buttonText: commandRepresentation
|
||||
colBackground: Appearance.colors.colLayer2
|
||||
|
||||
onClicked: {
|
||||
if(modelData.sendDirectly) {
|
||||
downAction: () => {
|
||||
if (modelData.sendDirectly) {
|
||||
root.handleInput(commandRepresentation)
|
||||
} else {
|
||||
tagInputField.text = commandRepresentation + " "
|
||||
|
||||
@@ -10,7 +10,7 @@ GroupButton {
|
||||
verticalPadding: 6
|
||||
|
||||
baseWidth: contentItem.implicitWidth + horizontalPadding * 2
|
||||
clickedWidth: baseWidth + 20
|
||||
clickedWidth: baseWidth + 14
|
||||
baseHeight: contentItem.implicitHeight + verticalPadding * 2
|
||||
buttonRadius: down ? Appearance.rounding.verysmall : Appearance.rounding.small
|
||||
|
||||
|
||||
@@ -12,12 +12,17 @@ Item {
|
||||
id: root
|
||||
required property var scopeRoot
|
||||
anchors.fill: parent
|
||||
property bool aiChatEnabled: Config.options.policies.ai !== 0
|
||||
property bool translatorEnabled: Config.options.sidebar.translator.enable
|
||||
property bool animeEnabled: Config.options.policies.weeb !== 0
|
||||
property bool animeCloset: Config.options.policies.weeb === 2
|
||||
property var tabButtonList: [
|
||||
...(Config.options.policies.ai !== 0 ? [{"icon": "neurology", "name": Translation.tr("Intelligence")}] : []),
|
||||
{"icon": "translate", "name": Translation.tr("Translator")},
|
||||
...(Config.options.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": Translation.tr("Anime")}] : [])
|
||||
...(root.aiChatEnabled ? [{"icon": "neurology", "name": Translation.tr("Intelligence")}] : []),
|
||||
...(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() {
|
||||
swipeView.currentItem.forceActiveFocus()
|
||||
@@ -26,7 +31,7 @@ Item {
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.modifiers === Qt.ControlModifier) {
|
||||
if (event.key === Qt.Key_PageDown) {
|
||||
root.selectedTab = Math.min(root.selectedTab + 1, root.tabButtonList.length - 1)
|
||||
root.selectedTab = Math.min(root.selectedTab + 1, root.tabCount - 1)
|
||||
event.accepted = true;
|
||||
}
|
||||
else if (event.key === Qt.Key_PageUp) {
|
||||
@@ -34,11 +39,11 @@ Item {
|
||||
event.accepted = true;
|
||||
}
|
||||
else if (event.key === Qt.Key_Tab) {
|
||||
root.selectedTab = (root.selectedTab + 1) % root.tabButtonList.length;
|
||||
root.selectedTab = (root.selectedTab + 1) % root.tabCount;
|
||||
event.accepted = true;
|
||||
}
|
||||
else if (event.key === Qt.Key_Backtab) {
|
||||
root.selectedTab = (root.selectedTab - 1 + root.tabButtonList.length) % root.tabButtonList.length;
|
||||
root.selectedTab = (root.selectedTab - 1 + root.tabCount) % root.tabCount;
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +57,7 @@ Item {
|
||||
|
||||
PrimaryTabBar { // Tab strip
|
||||
id: tabBar
|
||||
visible: root.tabButtonList.length > 1
|
||||
tabButtonList: root.tabButtonList
|
||||
externalTrackedTab: root.selectedTab
|
||||
function onCurrentIndexChanged(currentIndex) {
|
||||
@@ -83,9 +89,9 @@ Item {
|
||||
}
|
||||
|
||||
contentChildren: [
|
||||
...(Config.options.policies.ai !== 0 ? [aiChat.createObject()] : []),
|
||||
translator.createObject(),
|
||||
...(Config.options.policies.weeb === 0 ? [] : [anime.createObject()])
|
||||
...((root.aiChatEnabled || (!root.translatorEnabled && !root.animeEnabled)) ? [aiChat.createObject()] : []),
|
||||
...(root.translatorEnabled ? [translator.createObject()] : []),
|
||||
...(root.animeEnabled ? [anime.createObject()] : [])
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -78,156 +78,165 @@ Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.margins: messagePadding
|
||||
spacing: root.contentSpacing
|
||||
|
||||
RowLayout { // Header
|
||||
spacing: 15
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
implicitWidth: headerRowLayout.implicitWidth + 4 * 2
|
||||
implicitHeight: headerRowLayout.implicitHeight + 4 * 2
|
||||
color: Appearance.colors.colSecondaryContainer
|
||||
radius: Appearance.rounding.small
|
||||
|
||||
RowLayout { // Header
|
||||
id: headerRowLayout
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 4
|
||||
}
|
||||
spacing: 18
|
||||
|
||||
Rectangle { // Name
|
||||
id: nameWrapper
|
||||
color: Appearance.colors.colSecondaryContainer
|
||||
// color: "transparent"
|
||||
radius: Appearance.rounding.small
|
||||
implicitHeight: Math.max(nameRowLayout.implicitHeight + 5 * 2, 30)
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Item { // Name
|
||||
id: nameWrapper
|
||||
implicitHeight: Math.max(nameRowLayout.implicitHeight + 5 * 2, 30)
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
RowLayout {
|
||||
id: nameRowLayout
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
spacing: 7
|
||||
RowLayout {
|
||||
id: nameRowLayout
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
spacing: 7
|
||||
|
||||
Item {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: messageData?.role == 'assistant' ? modelIcon.width : roleIcon.implicitWidth
|
||||
implicitHeight: messageData?.role == 'assistant' ? modelIcon.height : roleIcon.implicitHeight
|
||||
Item {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: messageData?.role == 'assistant' ? modelIcon.width : roleIcon.implicitWidth
|
||||
implicitHeight: messageData?.role == 'assistant' ? modelIcon.height : roleIcon.implicitHeight
|
||||
|
||||
CustomIcon {
|
||||
id: modelIcon
|
||||
anchors.centerIn: parent
|
||||
visible: messageData?.role == 'assistant' && Ai.models[messageData?.model].icon
|
||||
width: Appearance.font.pixelSize.large
|
||||
height: Appearance.font.pixelSize.large
|
||||
source: messageData?.role == 'assistant' ? Ai.models[messageData?.model].icon :
|
||||
messageData?.role == 'user' ? 'linux-symbolic' : 'desktop-symbolic'
|
||||
CustomIcon {
|
||||
id: modelIcon
|
||||
anchors.centerIn: parent
|
||||
visible: messageData?.role == 'assistant' && Ai.models[messageData?.model].icon
|
||||
width: Appearance.font.pixelSize.large
|
||||
height: Appearance.font.pixelSize.large
|
||||
source: messageData?.role == 'assistant' ? Ai.models[messageData?.model].icon :
|
||||
messageData?.role == 'user' ? 'linux-symbolic' : 'desktop-symbolic'
|
||||
|
||||
colorize: true
|
||||
colorize: true
|
||||
color: Appearance.m3colors.m3onSecondaryContainer
|
||||
}
|
||||
|
||||
MaterialSymbol {
|
||||
id: roleIcon
|
||||
anchors.centerIn: parent
|
||||
visible: !modelIcon.visible
|
||||
iconSize: Appearance.font.pixelSize.larger
|
||||
color: Appearance.m3colors.m3onSecondaryContainer
|
||||
text: messageData?.role == 'user' ? 'person' :
|
||||
messageData?.role == 'interface' ? 'settings' :
|
||||
messageData?.role == 'assistant' ? 'neurology' :
|
||||
'computer'
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: providerName
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: Appearance.font.pixelSize.normal
|
||||
color: Appearance.m3colors.m3onSecondaryContainer
|
||||
}
|
||||
|
||||
MaterialSymbol {
|
||||
id: roleIcon
|
||||
anchors.centerIn: parent
|
||||
visible: !modelIcon.visible
|
||||
iconSize: Appearance.font.pixelSize.larger
|
||||
color: Appearance.m3colors.m3onSecondaryContainer
|
||||
text: messageData?.role == 'user' ? 'person' :
|
||||
messageData?.role == 'interface' ? 'settings' :
|
||||
messageData?.role == 'assistant' ? 'neurology' :
|
||||
'computer'
|
||||
text: messageData?.role == 'assistant' ? Ai.models[messageData?.model].name :
|
||||
(messageData?.role == 'user' && SystemInfo.username) ? SystemInfo.username :
|
||||
Translation.tr("Interface")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: providerName
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: Appearance.font.pixelSize.normal
|
||||
color: Appearance.m3colors.m3onSecondaryContainer
|
||||
text: messageData?.role == 'assistant' ? Ai.models[messageData?.model].name :
|
||||
(messageData?.role == 'user' && SystemInfo.username) ? SystemInfo.username :
|
||||
Translation.tr("Interface")
|
||||
Button { // Not visible to model
|
||||
id: modelVisibilityIndicator
|
||||
visible: messageData?.role == 'interface'
|
||||
implicitWidth: 16
|
||||
implicitHeight: 30
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
background: Item
|
||||
|
||||
MaterialSymbol {
|
||||
id: notVisibleToModelText
|
||||
anchors.centerIn: parent
|
||||
iconSize: Appearance.font.pixelSize.small
|
||||
color: Appearance.colors.colSubtext
|
||||
text: "visibility_off"
|
||||
}
|
||||
StyledToolTip {
|
||||
text: Translation.tr("Not visible to model")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button { // Not visible to model
|
||||
id: modelVisibilityIndicator
|
||||
visible: messageData?.role == 'interface'
|
||||
implicitWidth: 16
|
||||
implicitHeight: 30
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
ButtonGroup {
|
||||
spacing: 5
|
||||
|
||||
background: Item
|
||||
AiMessageControlButton {
|
||||
id: copyButton
|
||||
buttonIcon: activated ? "inventory" : "content_copy"
|
||||
|
||||
MaterialSymbol {
|
||||
id: notVisibleToModelText
|
||||
anchors.centerIn: parent
|
||||
iconSize: Appearance.font.pixelSize.small
|
||||
color: Appearance.colors.colSubtext
|
||||
text: "visibility_off"
|
||||
}
|
||||
StyledToolTip {
|
||||
text: Translation.tr("Not visible to model")
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
Quickshell.clipboardText = root.messageData?.content
|
||||
copyButton.activated = true
|
||||
copyIconTimer.restart()
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
spacing: 5
|
||||
|
||||
AiMessageControlButton {
|
||||
id: copyButton
|
||||
buttonIcon: activated ? "inventory" : "content_copy"
|
||||
|
||||
onClicked: {
|
||||
Quickshell.clipboardText = root.messageData?.content
|
||||
copyButton.activated = true
|
||||
copyIconTimer.restart()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: copyIconTimer
|
||||
interval: 1500
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
copyButton.activated = false
|
||||
Timer {
|
||||
id: copyIconTimer
|
||||
interval: 1500
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
copyButton.activated = false
|
||||
}
|
||||
}
|
||||
|
||||
StyledToolTip {
|
||||
text: Translation.tr("Copy")
|
||||
}
|
||||
}
|
||||
|
||||
StyledToolTip {
|
||||
text: Translation.tr("Copy")
|
||||
}
|
||||
}
|
||||
AiMessageControlButton {
|
||||
id: editButton
|
||||
activated: root.editing
|
||||
enabled: root.messageData?.done ?? false
|
||||
buttonIcon: "edit"
|
||||
onClicked: {
|
||||
root.editing = !root.editing
|
||||
if (!root.editing) { // Save changes
|
||||
root.saveMessage()
|
||||
AiMessageControlButton {
|
||||
id: editButton
|
||||
activated: root.editing
|
||||
enabled: root.messageData?.done ?? false
|
||||
buttonIcon: "edit"
|
||||
onClicked: {
|
||||
root.editing = !root.editing
|
||||
if (!root.editing) { // Save changes
|
||||
root.saveMessage()
|
||||
}
|
||||
}
|
||||
StyledToolTip {
|
||||
text: root.editing ? Translation.tr("Save") : Translation.tr("Edit")
|
||||
}
|
||||
}
|
||||
StyledToolTip {
|
||||
text: root.editing ? Translation.tr("Save") : Translation.tr("Edit")
|
||||
AiMessageControlButton {
|
||||
id: toggleMarkdownButton
|
||||
activated: !root.renderMarkdown
|
||||
buttonIcon: "code"
|
||||
onClicked: {
|
||||
root.renderMarkdown = !root.renderMarkdown
|
||||
}
|
||||
StyledToolTip {
|
||||
text: Translation.tr("View Markdown source")
|
||||
}
|
||||
}
|
||||
}
|
||||
AiMessageControlButton {
|
||||
id: toggleMarkdownButton
|
||||
activated: !root.renderMarkdown
|
||||
buttonIcon: "code"
|
||||
onClicked: {
|
||||
root.renderMarkdown = !root.renderMarkdown
|
||||
}
|
||||
StyledToolTip {
|
||||
text: Translation.tr("View Markdown source")
|
||||
}
|
||||
}
|
||||
AiMessageControlButton {
|
||||
id: deleteButton
|
||||
buttonIcon: "close"
|
||||
onClicked: {
|
||||
Ai.removeMessage(root.messageIndex)
|
||||
}
|
||||
StyledToolTip {
|
||||
text: Translation.tr("Delete")
|
||||
AiMessageControlButton {
|
||||
id: deleteButton
|
||||
buttonIcon: "close"
|
||||
onClicked: {
|
||||
Ai.removeMessage(root.messageIndex)
|
||||
}
|
||||
StyledToolTip {
|
||||
text: Translation.tr("Delete")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,6 +271,8 @@ Rectangle {
|
||||
property bool thinking: root.messageData?.thinking ?? true
|
||||
property bool done: root.messageData?.done ?? false
|
||||
property bool completed: thisBlock.completed ?? false
|
||||
|
||||
property bool forceDisableChunkSplitting: root.messageData.content.includes("```")
|
||||
|
||||
source: thisBlock.type === "code" ? "MessageCodeBlock.qml" :
|
||||
thisBlock.type === "think" ? "MessageThinkBlock.qml" :
|
||||
|
||||
@@ -8,8 +8,9 @@ GroupButton {
|
||||
property string buttonIcon
|
||||
property bool activated: false
|
||||
toggled: activated
|
||||
|
||||
baseWidth: height
|
||||
colBackgroundHover: Appearance.colors.colSecondaryContainerHover
|
||||
colBackgroundActive: Appearance.colors.colSecondaryContainerActive
|
||||
|
||||
contentItem: MaterialSymbol {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.modules.common.functions
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
|
||||
ColumnLayout {
|
||||
@@ -22,6 +23,9 @@ ColumnLayout {
|
||||
property list<string> renderedLatexHashes: []
|
||||
|
||||
property string renderedSegmentContent: ""
|
||||
property string shownText: ""
|
||||
property bool forceDisableChunkSplitting: parent?.forceDisableChunkSplitting ?? false
|
||||
property bool fadeChunkSplitting: !forceDisableChunkSplitting && !editing && !/\n\|/.test(shownText) && Config.options.sidebar.ai.textFadeIn
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -73,7 +77,7 @@ ColumnLayout {
|
||||
renderLatex()
|
||||
} else {
|
||||
// console.log("Editing mode enabled", segmentContent)
|
||||
textArea.text = segmentContent
|
||||
root.shownText = segmentContent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +92,7 @@ ColumnLayout {
|
||||
onRenderedSegmentContentChanged: {
|
||||
// console.log("Rendered segment content changed: " + renderedSegmentContent);
|
||||
if (renderedSegmentContent) {
|
||||
textArea.text = renderedSegmentContent;
|
||||
root.shownText = renderedSegmentContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,39 +108,85 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: textArea
|
||||
|
||||
Layout.fillWidth: true
|
||||
readOnly: !editing
|
||||
selectByMouse: enableMouseSelection || editing
|
||||
renderType: Text.NativeRendering
|
||||
font.family: Appearance.font.family.reading
|
||||
font.hintingPreference: Font.PreferNoHinting // Prevent weird bold text
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
|
||||
selectionColor: Appearance.colors.colSecondaryContainer
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: messageData.thinking ? Appearance.colors.colSubtext : Appearance.colors.colOnLayer1
|
||||
textFormat: renderMarkdown ? TextEdit.MarkdownText : TextEdit.PlainText
|
||||
text: Translation.tr("Waiting for response...")
|
||||
|
||||
onTextChanged: {
|
||||
if (!root.editing) return
|
||||
segmentContent = text
|
||||
spacing: 0
|
||||
Repeater {
|
||||
id: textLinesRepeater
|
||||
property list<real> textLineOpacities: []
|
||||
model: ScriptModel {
|
||||
// Split by either double newlines or single newlines in a list
|
||||
values: root.fadeChunkSplitting ? root.shownText.split(/\n\n(?= {0,2})|\n(?= {0,2}[-\*])/g).filter(line => line.trim() !== "") : [root.shownText]
|
||||
onValuesChanged: {
|
||||
while (textLinesRepeater.textLineOpacities.length < values.length) {
|
||||
textLinesRepeater.textLineOpacities.push(root.messageData.done ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
delegate: TextArea {
|
||||
id: textArea
|
||||
required property int index
|
||||
required property string modelData
|
||||
|
||||
onLinkActivated: (link) => {
|
||||
Qt.openUrlExternally(link)
|
||||
GlobalStates.sidebarLeftOpen = false
|
||||
}
|
||||
// Fade in animation
|
||||
visible: opacity > 0
|
||||
opacity: fadeChunkSplitting ? (textLinesRepeater.textLineOpacities[index] ?? (root.messageData.done ? 1 : 0)) : 1
|
||||
Connections {
|
||||
target: root.messageData
|
||||
function onDoneChanged() {
|
||||
if (root.messageData.done) {
|
||||
textLinesRepeater.textLineOpacities[textArea.index] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: textLinesRepeater.model
|
||||
function onValuesChanged() {
|
||||
if (textLinesRepeater.model.values.length > textArea.index + 1) {
|
||||
textLinesRepeater.textLineOpacities[textArea.index] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
MouseArea { // Pointing hand for links
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton // Only for hover
|
||||
hoverEnabled: true
|
||||
cursorShape: parent.hoveredLink !== "" ? Qt.PointingHandCursor :
|
||||
(enableMouseSelection || editing) ? Qt.IBeamCursor : Qt.ArrowCursor
|
||||
Layout.fillWidth: true
|
||||
readOnly: !editing
|
||||
selectByMouse: enableMouseSelection || editing
|
||||
renderType: Text.NativeRendering
|
||||
font.family: Appearance.font.family.reading
|
||||
font.hintingPreference: Font.PreferNoHinting // Prevent weird bold text
|
||||
font.pixelSize: Appearance.font.pixelSize.small
|
||||
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
|
||||
selectionColor: Appearance.colors.colSecondaryContainer
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: messageData.thinking ? Appearance.colors.colSubtext : Appearance.colors.colOnLayer1
|
||||
textFormat: renderMarkdown ? TextEdit.MarkdownText : TextEdit.PlainText
|
||||
text: modelData
|
||||
|
||||
onTextChanged: {
|
||||
if (!root.editing) return
|
||||
segmentContent = text
|
||||
}
|
||||
|
||||
onLinkActivated: (link) => {
|
||||
Qt.openUrlExternally(link)
|
||||
GlobalStates.sidebarLeftOpen = false
|
||||
}
|
||||
|
||||
MouseArea { // Pointing hand for links
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton // Only for hover
|
||||
hoverEnabled: true
|
||||
cursorShape: parent.hoveredLink !== "" ? Qt.PointingHandCursor :
|
||||
(enableMouseSelection || editing) ? Qt.IBeamCursor : Qt.ArrowCursor
|
||||
}
|
||||
|
||||
// Rectangle {
|
||||
// anchors.fill: parent
|
||||
// color: "#22786378"
|
||||
// border.width: 1
|
||||
// border.color: "#7E7E7E"
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ Rectangle {
|
||||
Layout.margins: 10
|
||||
Layout.rightMargin: 0
|
||||
forceCircle: true
|
||||
onClicked: {
|
||||
downAction: () => {
|
||||
root.setCollapsed(false)
|
||||
}
|
||||
contentItem: MaterialSymbol {
|
||||
@@ -146,7 +146,7 @@ Rectangle {
|
||||
toggled: root.selectedTab == index
|
||||
buttonText: modelData.name
|
||||
buttonIcon: modelData.icon
|
||||
onClicked: {
|
||||
onPressed: {
|
||||
root.selectedTab = index
|
||||
Persistent.states.sidebar.bottomGroup.tab = index
|
||||
}
|
||||
@@ -158,7 +158,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
forceCircle: true
|
||||
onClicked: {
|
||||
downAction: () => {
|
||||
root.setCollapsed(true)
|
||||
}
|
||||
contentItem: MaterialSymbol {
|
||||
|
||||
@@ -70,7 +70,6 @@ Scope {
|
||||
|
||||
function toggle(): void {
|
||||
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen;
|
||||
if(GlobalStates.sidebarRightOpen) Notifications.timeoutAll();
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
@@ -79,7 +78,6 @@ Scope {
|
||||
|
||||
function open(): void {
|
||||
GlobalStates.sidebarRightOpen = true;
|
||||
Notifications.timeoutAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +87,6 @@ Scope {
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen;
|
||||
if(GlobalStates.sidebarRightOpen) Notifications.timeoutAll();
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
@@ -98,7 +95,6 @@ Scope {
|
||||
|
||||
onPressed: {
|
||||
GlobalStates.sidebarRightOpen = true;
|
||||
Notifications.timeoutAll();
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
|
||||
@@ -50,7 +50,7 @@ Item {
|
||||
clip: true
|
||||
buttonText: `${monthShift != 0 ? "• " : ""}${viewingDate.toLocaleDateString(Qt.locale(), "MMMM yyyy")}`
|
||||
tooltipText: (monthShift === 0) ? "" : Translation.tr("Jump to current month")
|
||||
onClicked: {
|
||||
downAction: () => {
|
||||
monthShift = 0;
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ Item {
|
||||
}
|
||||
CalendarHeaderButton {
|
||||
forceCircle: true
|
||||
onClicked: {
|
||||
downAction: () => {
|
||||
monthShift--;
|
||||
}
|
||||
contentItem: MaterialSymbol {
|
||||
@@ -72,7 +72,7 @@ Item {
|
||||
}
|
||||
CalendarHeaderButton {
|
||||
forceCircle: true
|
||||
onClicked: {
|
||||
downAction: () => {
|
||||
monthShift++;
|
||||
}
|
||||
contentItem: MaterialSymbol {
|
||||
|
||||
@@ -11,6 +11,7 @@ import Quickshell.Hyprland
|
||||
|
||||
QuickToggleButton {
|
||||
id: root
|
||||
visible: BluetoothStatus.available
|
||||
toggled: BluetoothStatus.enabled
|
||||
buttonIcon: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled"
|
||||
onClicked: {
|
||||
|
||||
@@ -109,12 +109,12 @@ Item {
|
||||
AudioDeviceSelectorButton {
|
||||
Layout.fillWidth: true
|
||||
input: false
|
||||
onClicked: root.showDeviceSelectorDialog(input)
|
||||
downAction: () => root.showDeviceSelectorDialog(input)
|
||||
}
|
||||
AudioDeviceSelectorButton {
|
||||
Layout.fillWidth: true
|
||||
input: true
|
||||
onClicked: root.showDeviceSelectorDialog(input)
|
||||
downAction: () => root.showDeviceSelectorDialog(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,6 +280,7 @@ Item { // Bar content region
|
||||
color: rightSidebarButton.colText
|
||||
}
|
||||
MaterialSymbol {
|
||||
visible: BluetoothStatus.available
|
||||
text: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled"
|
||||
iconSize: Appearance.font.pixelSize.larger
|
||||
color: rightSidebarButton.colText
|
||||
|
||||
@@ -12,6 +12,7 @@ import QtQuick
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property bool available: Bluetooth.adapters.values.length > 0
|
||||
readonly property bool enabled: Bluetooth.defaultAdapter?.enabled ?? false
|
||||
readonly property BluetoothDevice firstActiveDevice: Bluetooth.defaultAdapter?.devices.values.find(device => device.connected) ?? null
|
||||
readonly property int activeDeviceCount: Bluetooth.defaultAdapter?.devices.values.filter(device => device.connected).length ?? 0
|
||||
|
||||
@@ -40,7 +40,7 @@ Singleton {
|
||||
id: resetFilePathNextWallpaperChange
|
||||
enabled: false
|
||||
target: Config.options.background
|
||||
onWallpaperPathChanged: {
|
||||
function onWallpaperPathChanged() {
|
||||
root.filePath = ""
|
||||
root.filePath = Directories.generatedMaterialThemePath
|
||||
resetFilePathNextWallpaperChange.enabled = false
|
||||
|
||||
@@ -69,6 +69,7 @@ Singleton {
|
||||
}
|
||||
|
||||
property bool silent: false
|
||||
property int unread: 0
|
||||
property var filePath: Directories.notificationsPath
|
||||
property list<Notif> list: []
|
||||
property var popupList: list.filter((notif) => notif.popup);
|
||||
@@ -173,12 +174,17 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
root.unread++;
|
||||
root.notify(newNotifObject);
|
||||
// console.log(notifToString(newNotifObject));
|
||||
notifFileView.setText(stringifyList(root.list));
|
||||
}
|
||||
}
|
||||
|
||||
function markAllRead() {
|
||||
root.unread = 0;
|
||||
}
|
||||
|
||||
function discardNotification(id) {
|
||||
console.log("[Notifications] Discarding notification with ID: " + id);
|
||||
const index = root.list.findIndex((notif) => notif.notificationId === id);
|
||||
|
||||
@@ -172,7 +172,7 @@ ApplicationWindow {
|
||||
iconText: "edit"
|
||||
buttonText: Translation.tr("Config file")
|
||||
expanded: navRail.expanded
|
||||
onClicked: {
|
||||
downAction: () => {
|
||||
Qt.openUrlExternally(`${Directories.config}/illogical-impulse/config.json`);
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ ApplicationWindow {
|
||||
required property var index
|
||||
required property var modelData
|
||||
toggled: root.currentPage === index
|
||||
onClicked: root.currentPage = index;
|
||||
onPressed: root.currentPage = index;
|
||||
expanded: navRail.expanded
|
||||
buttonIcon: modelData.icon
|
||||
buttonIconRotation: modelData.iconRotation || 0
|
||||
|
||||
@@ -63,7 +63,7 @@ install-local-pkgbuild() {
|
||||
x pushd $location
|
||||
|
||||
source ./PKGBUILD
|
||||
x yay -S $installflags --asdeps "${depends[@]}"
|
||||
x yay -S --sudoloop $installflags --asdeps "${depends[@]}"
|
||||
x makepkg -Asi --noconfirm
|
||||
|
||||
x popd
|
||||
|
||||
Reference in New Issue
Block a user