chore: move sidebar directory to modules
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import qs.Components
|
||||
import ZShell.Config
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import qs.Services
|
||||
|
||||
ShapePath {
|
||||
id: root
|
||||
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real rounding: Config.bar.rounding
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
required property var sidebar
|
||||
required property Wrapper wrapper
|
||||
|
||||
fillColor: Colors.palette.m3surface
|
||||
strokeWidth: -1
|
||||
|
||||
Behavior on fillColor {
|
||||
CAnim {
|
||||
}
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: -(root.wrapper.width + root.rounding)
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
direction: PathArc.Counterclockwise
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: -(root.wrapper.height - root.roundingY * 2)
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.sidebar.utilsRoundingX
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
relativeX: root.sidebar.utilsRoundingX
|
||||
relativeY: -root.roundingY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.utilsRoundingX : root.wrapper.width
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
direction: PathArc.Counterclockwise
|
||||
radiusX: root.rounding
|
||||
radiusY: root.rounding
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.rounding
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Components
|
||||
import ZShell.Config
|
||||
import qs.Helpers
|
||||
import qs.Services
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
|
||||
required property ScreenState screenState
|
||||
|
||||
Layout.fillWidth: true
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
|
||||
radius: Tokens.rounding.small
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Tokens.padding.large
|
||||
spacing: Tokens.spacing.medium
|
||||
|
||||
RowLayout {
|
||||
spacing: Tokens.spacing.medium
|
||||
z: 1
|
||||
|
||||
CustomRect {
|
||||
color: Recorder.running ? Colors.palette.m3secondary : Colors.palette.m3secondaryContainer
|
||||
implicitHeight: {
|
||||
const h = icon.implicitHeight + Tokens.padding.small * 2;
|
||||
return h - (h % 2);
|
||||
}
|
||||
implicitWidth: implicitHeight
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: -0.5
|
||||
anchors.verticalCenterOffset: 1.5
|
||||
color: Recorder.running ? Colors.palette.m3onSecondary : Colors.palette.m3onSecondaryContainer
|
||||
fontStyle: Tokens.font.icon.large
|
||||
text: "screen_record"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font: Tokens.font.body.medium
|
||||
text: qsTr("Screen Recorder")
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
elide: Text.ElideRight
|
||||
font: Tokens.font.body.small
|
||||
text: Recorder.paused ? qsTr("Recording paused") : Recorder.running ? qsTr("Recording running") : qsTr("Recording off")
|
||||
}
|
||||
}
|
||||
|
||||
SplitButton {
|
||||
active: menuItems.find(m => root.screenState.recordingMode === m.icon + m.text) ?? menuItems[0]
|
||||
enabled: !Recorder.running
|
||||
menuOnTop: true
|
||||
|
||||
menuItems: [
|
||||
MenuItem {
|
||||
activeText: qsTr("Fullscreen")
|
||||
icon: "fullscreen"
|
||||
text: qsTr("Record fullscreen")
|
||||
|
||||
onClicked: Recorder.start()
|
||||
},
|
||||
MenuItem {
|
||||
activeText: qsTr("Region")
|
||||
icon: "screenshot_region"
|
||||
text: qsTr("Record region")
|
||||
|
||||
onClicked: Recorder.start(["-r"])
|
||||
},
|
||||
MenuItem {
|
||||
activeText: qsTr("Fullscreen")
|
||||
icon: "select_to_speak"
|
||||
text: qsTr("Record fullscreen with sound")
|
||||
|
||||
onClicked: Recorder.start(["-s"])
|
||||
},
|
||||
MenuItem {
|
||||
activeText: qsTr("Region")
|
||||
icon: "volume_up"
|
||||
text: qsTr("Record region with sound")
|
||||
|
||||
onClicked: Recorder.start(["-s", "-r"])
|
||||
}
|
||||
]
|
||||
|
||||
menu.onItemSelected: item => root.screenState.recordingMode = item.icon + item.text
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: listOrControls
|
||||
|
||||
property bool running: Recorder.running
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: implicitHeight
|
||||
asynchronous: true
|
||||
sourceComponent: running ? recordingControls : recordingList
|
||||
|
||||
Behavior on Layout.preferredHeight {
|
||||
id: locHeightAnim
|
||||
|
||||
enabled: false
|
||||
|
||||
Anim {}
|
||||
}
|
||||
Behavior on running {
|
||||
SequentialAnimation {
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.small
|
||||
easing: Tokens.anim.standardAccel
|
||||
property: "scale"
|
||||
target: listOrControls
|
||||
to: 0.7
|
||||
}
|
||||
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.small
|
||||
easing: Tokens.anim.standardAccel
|
||||
property: "opacity"
|
||||
target: listOrControls
|
||||
to: 0
|
||||
}
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
property: "enabled"
|
||||
target: locHeightAnim
|
||||
value: true
|
||||
}
|
||||
|
||||
PropertyAction {}
|
||||
|
||||
PropertyAction {
|
||||
property: "enabled"
|
||||
target: locHeightAnim
|
||||
value: false
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.small
|
||||
easing: Tokens.anim.standardDecel
|
||||
property: "scale"
|
||||
target: listOrControls
|
||||
to: 1
|
||||
}
|
||||
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.small
|
||||
easing: Tokens.anim.standardDecel
|
||||
property: "opacity"
|
||||
target: listOrControls
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: recordingList
|
||||
|
||||
RecordingList {
|
||||
screenState: root.screenState
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: recordingControls
|
||||
|
||||
RowLayout {
|
||||
spacing: Tokens.spacing.medium
|
||||
|
||||
CustomRect {
|
||||
color: Recorder.paused ? Colors.palette.m3tertiary : Colors.palette.m3error
|
||||
implicitHeight: recText.implicitHeight + Tokens.padding.small * 2
|
||||
implicitWidth: recText.implicitWidth + Tokens.padding.small * 2
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
Behavior on implicitWidth {
|
||||
Anim {}
|
||||
}
|
||||
SequentialAnimation on opacity {
|
||||
alwaysRunToEnd: true
|
||||
loops: Animation.Infinite
|
||||
running: !Recorder.paused
|
||||
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.large
|
||||
easing: Tokens.anim.emphasizedAccel
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.extraLarge
|
||||
easing: Tokens.anim.emphasizedDecel
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: recText
|
||||
|
||||
anchors.centerIn: parent
|
||||
animate: true
|
||||
color: Recorder.paused ? Colors.palette.m3onTertiary : Colors.palette.m3onError
|
||||
font: Tokens.font.mono.small
|
||||
text: Recorder.paused ? "PAUSED" : "REC"
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
font: Tokens.font.body.medium
|
||||
text: {
|
||||
const elapsed = Recorder.elapsed;
|
||||
|
||||
const hours = Math.floor(elapsed / 3600);
|
||||
const mins = Math.floor((elapsed % 3600) / 60);
|
||||
const secs = Math.floor(elapsed % 60).toString().padStart(2, "0");
|
||||
|
||||
let time;
|
||||
if (hours > 0)
|
||||
time = `${hours}:${mins.toString().padStart(2, "0")}:${secs}`;
|
||||
else
|
||||
time = `${mins}:${secs}`;
|
||||
|
||||
return qsTr("Recording for %1").arg(time);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
IconButton {
|
||||
checked: Recorder.paused
|
||||
font: Tokens.font.icon.medium
|
||||
icon: Recorder.paused ? "play_arrow" : "pause"
|
||||
isRound: true
|
||||
isToggle: true
|
||||
label.animate: true
|
||||
type: IconButton.Tonal
|
||||
|
||||
onClicked: {
|
||||
Recorder.togglePause();
|
||||
internalChecked = Recorder.paused;
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
font: Tokens.font.icon.medium
|
||||
icon: "stop"
|
||||
isRound: true
|
||||
inactiveColor: Colors.palette.m3error
|
||||
inactiveOnColor: Colors.palette.m3onError
|
||||
|
||||
onClicked: Recorder.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import ZShell.Models
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Paths
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
required property ScreenState screenState
|
||||
|
||||
spacing: 0
|
||||
|
||||
WrapperMouseArea {
|
||||
Layout.fillWidth: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: root.screenState.recordingListExpanded = !root.screenState.recordingListExpanded
|
||||
|
||||
RowLayout {
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
MaterialIcon {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
fontStyle: Tokens.font.icon.large
|
||||
text: "list"
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
font: Tokens.font.body.medium
|
||||
text: qsTr("Recordings")
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: root.screenState.recordingListExpanded ? "unfold_less" : "unfold_more"
|
||||
label.animate: true
|
||||
type: IconButton.Text
|
||||
|
||||
onClicked: root.screenState.recordingListExpanded = !root.screenState.recordingListExpanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomListView {
|
||||
id: list
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: -Tokens.spacing.small
|
||||
clip: true
|
||||
implicitHeight: (Tokens.font.body.large.pointSize + Tokens.padding.extraSmall) * (root.screenState.recordingListExpanded ? 10 : 3)
|
||||
|
||||
CustomScrollBar.vertical: CustomScrollBar {
|
||||
flickable: list
|
||||
}
|
||||
add: Transition {
|
||||
Anim {
|
||||
from: 0
|
||||
property: "opacity"
|
||||
to: 1
|
||||
}
|
||||
|
||||
Anim {
|
||||
from: 0.5
|
||||
property: "scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
delegate: RowLayout {
|
||||
id: recording
|
||||
|
||||
property string baseName
|
||||
required property FileSystemEntry modelData
|
||||
|
||||
anchors.left: list.contentItem.left
|
||||
anchors.right: list.contentItem.right
|
||||
anchors.rightMargin: Tokens.spacing.small
|
||||
spacing: Tokens.spacing.small / 2
|
||||
|
||||
Component.onCompleted: baseName = modelData.baseName
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: Tokens.spacing.small / 2
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
elide: Text.ElideRight
|
||||
text: {
|
||||
const time = recording.baseName;
|
||||
const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/);
|
||||
if (!matches)
|
||||
return time;
|
||||
const date = new Date(...matches.slice(1));
|
||||
date.setMonth(date.getMonth() - 1);
|
||||
return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale()));
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: "play_arrow"
|
||||
type: IconButton.Text
|
||||
|
||||
onClicked: {
|
||||
root.screenState.sidebar = false;
|
||||
if (Config.launcher.uwsm)
|
||||
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
|
||||
else
|
||||
Quickshell.execDetached([...Config.general.apps.playback, recording.modelData.path]);
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: "folder"
|
||||
type: IconButton.Text
|
||||
|
||||
onClicked: {
|
||||
root.screenState.sidebar = false;
|
||||
if (Config.launcher.uwsm)
|
||||
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
|
||||
else
|
||||
Quickshell.execDetached([...Config.general.apps.explorer, recording.modelData.path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
displaced: Transition {
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
}
|
||||
Behavior on implicitHeight {
|
||||
Anim {}
|
||||
}
|
||||
model: FileSystemModel {
|
||||
nameFilters: ["recording_*.mp4"]
|
||||
path: Paths.recsdir
|
||||
sortReverse: true
|
||||
}
|
||||
remove: Transition {
|
||||
Anim {
|
||||
property: "opacity"
|
||||
to: 0
|
||||
}
|
||||
|
||||
Anim {
|
||||
property: "scale"
|
||||
to: 0.5
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
asynchronous: true
|
||||
opacity: list.count === 0 ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
sourceComponent: ColumnLayout {
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
MaterialIcon {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredHeight: root.screenState.recordingListExpanded ? implicitHeight : 0
|
||||
color: Colors.palette.m3outline
|
||||
fontStyle: Tokens.font.icon.extraLarge
|
||||
opacity: root.screenState.recordingListExpanded ? 1 : 0
|
||||
scale: root.screenState.recordingListExpanded ? 1 : 0
|
||||
text: "scan_delete"
|
||||
|
||||
Behavior on Layout.preferredHeight {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
MaterialIcon {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: !root.screenState.recordingListExpanded ? implicitWidth : 0
|
||||
color: Colors.palette.m3outline
|
||||
opacity: !root.screenState.recordingListExpanded ? 1 : 0
|
||||
scale: !root.screenState.recordingListExpanded ? 1 : 0
|
||||
text: "scan_delete"
|
||||
|
||||
Behavior on Layout.preferredWidth {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
color: Colors.palette.m3outline
|
||||
text: qsTr("No recordings found")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Bluetooth
|
||||
import Quickshell.Networking as QSNetwork
|
||||
import ZShell.Components
|
||||
import ZShell.Config
|
||||
import qs.Components
|
||||
import qs.Services
|
||||
import qs.Helpers
|
||||
import qs.Daemons
|
||||
import qs.Modules.Settings
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
|
||||
readonly property bool needExtraRow: quickToggles.length > 6
|
||||
readonly property var quickToggles: {
|
||||
const seenIds = new Set();
|
||||
|
||||
return Config.utilities.quickToggles.values.filter(item => {
|
||||
if (!item.enabled)
|
||||
return false;
|
||||
|
||||
if (seenIds.has(item.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.id === "bluetooth" && !Bluetooth.defaultAdapter)
|
||||
return false;
|
||||
|
||||
if (item.id === "wifi" && !QSNetwork.Networking.devices.values.some(n => n.type === QSNetwork.DeviceType.Wifi))
|
||||
return false;
|
||||
|
||||
seenIds.add(item.id);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
required property ScreenState screenState
|
||||
readonly property int splitIndex: Math.ceil(quickToggles.length / 2)
|
||||
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
implicitHeight: layout.implicitHeight + Tokens.padding.extraLargeIncreased
|
||||
radius: Tokens.rounding.small
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Tokens.padding.large
|
||||
spacing: Tokens.spacing.medium
|
||||
|
||||
CustomText {
|
||||
font: Tokens.font.body.medium
|
||||
text: qsTr("Quick Toggles")
|
||||
}
|
||||
|
||||
QuickToggleRow {
|
||||
model: root.needExtraRow ? root.quickToggles.slice(0, root.splitIndex) : root.quickToggles
|
||||
}
|
||||
|
||||
QuickToggleRow {
|
||||
model: root.needExtraRow ? root.quickToggles.slice(root.splitIndex) : []
|
||||
visible: root.needExtraRow
|
||||
}
|
||||
}
|
||||
|
||||
component QuickToggleRow: ButtonRow {
|
||||
property alias model: repeater.model
|
||||
|
||||
Layout.fillWidth: true
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
delegate: DelegateChooser {
|
||||
role: "id"
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "wifi"
|
||||
|
||||
delegate: Toggle {
|
||||
checked: Network.wifiEnabled
|
||||
icon: checked ? "wifi" : "wifi_off"
|
||||
|
||||
onClicked: Network.toggleWifi()
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "bluetooth"
|
||||
|
||||
delegate: Toggle {
|
||||
checked: Bluetooth.defaultAdapter?.enabled ?? false // qmllint disable unresolved-type
|
||||
icon: "bluetooth"
|
||||
|
||||
onClicked: {
|
||||
const adapter = Bluetooth.defaultAdapter; // qmllint disable unresolved-type
|
||||
if (adapter)
|
||||
adapter.enabled = !adapter.enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "mic"
|
||||
|
||||
delegate: Toggle {
|
||||
checked: !Audio.sourceMuted
|
||||
icon: checked ? "mic" : "mic_off"
|
||||
|
||||
onClicked: {
|
||||
const audio = Audio.source?.audio;
|
||||
if (audio)
|
||||
audio.muted = !audio.muted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "audio"
|
||||
|
||||
delegate: Toggle {
|
||||
checked: !Audio.muted
|
||||
icon: checked ? "volume_up" : "volume_off"
|
||||
|
||||
onClicked: {
|
||||
const audio = Audio.sink?.audio;
|
||||
if (audio)
|
||||
audio.muted = !audio.muted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "gameMode"
|
||||
|
||||
delegate: Toggle {
|
||||
checked: GameMode.enabled
|
||||
icon: "gamepad"
|
||||
|
||||
onClicked: GameMode.enabled = !GameMode.enabled
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "dnd"
|
||||
|
||||
delegate: Toggle {
|
||||
checked: NotifServer.dnd
|
||||
icon: "notifications_off"
|
||||
|
||||
onClicked: NotifServer.dnd = !NotifServer.dnd
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "settings"
|
||||
|
||||
delegate: Toggle {
|
||||
icon: "settings"
|
||||
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
||||
isToggle: false
|
||||
|
||||
onClicked: {
|
||||
root.screenState.sidebar = false;
|
||||
root.screenState.settings = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
component Toggle: IconButton {
|
||||
fillWidth: true
|
||||
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 2)
|
||||
isRound: true
|
||||
isToggle: true
|
||||
shapeMorph: true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ZShell.Config
|
||||
import qs.Components
|
||||
import qs.Modules.Sidebar.Utils.Cards
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property ScreenState screenState
|
||||
|
||||
implicitHeight: layout.implicitHeight
|
||||
implicitWidth: layout.implicitWidth
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
IdleInhibit {}
|
||||
|
||||
Record {
|
||||
screenState: root.screenState
|
||||
z: 1
|
||||
}
|
||||
|
||||
Toggles {
|
||||
Layout.fillWidth: true
|
||||
screenState: root.screenState
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import qs.Components
|
||||
import ZShell.Config
|
||||
import qs.Helpers
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Services
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
implicitHeight: layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2
|
||||
radius: Tokens.rounding.small
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 18
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
spacing: 10
|
||||
|
||||
CustomRect {
|
||||
color: IdleInhibitor.enabled ? Colors.palette.m3secondary : Colors.palette.m3secondaryContainer
|
||||
implicitHeight: icon.implicitHeight + 7 * 2
|
||||
implicitWidth: implicitHeight
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: IdleInhibitor.enabled ? Colors.palette.m3onSecondary : Colors.palette.m3onSecondaryContainer
|
||||
fontStyle: Tokens.font.icon.large
|
||||
text: "coffee"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font: Tokens.font.body.medium
|
||||
text: qsTr("Keep Awake")
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
elide: Text.ElideRight
|
||||
font: Tokens.font.body.small
|
||||
text: IdleInhibitor.enabled ? qsTr("Preventing sleep mode") : qsTr("Normal power management")
|
||||
}
|
||||
}
|
||||
|
||||
CustomSwitch {
|
||||
checked: IdleInhibitor.enabled
|
||||
|
||||
onToggled: IdleInhibitor.enabled = checked
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: activeChip
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: IdleInhibitor.enabled ? 18 : -implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 18
|
||||
anchors.topMargin: 20
|
||||
opacity: IdleInhibitor.enabled ? 1 : 0
|
||||
scale: IdleInhibitor.enabled ? 1 : 0.5
|
||||
|
||||
Behavior on anchors.bottomMargin {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
sourceComponent: CustomRect {
|
||||
color: Colors.palette.m3primary
|
||||
implicitHeight: activeText.implicitHeight + 10 * 2
|
||||
implicitWidth: activeText.implicitWidth + 10 * 2
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
CustomText {
|
||||
id: activeText
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: Colors.palette.m3onPrimary
|
||||
font: Tokens.font.body.builders.small.size(Math.round(Tokens.font.body.small.pointSize * 0.9)).build()
|
||||
text: qsTr("Active since %1").arg(Qt.formatTime(IdleInhibitor.enabledSince, Config.services.useTwelveHourClock ? "hh:mm a" : "hh:mm"))
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: active = Qt.binding(() => opacity > 0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import ZShell.Config
|
||||
import qs.Components
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real offsetScale: shouldBeActive ? 0 : 1
|
||||
required property ScreenState screenState
|
||||
readonly property bool shouldBeActive: screenState.sidebar && !sidebar.chatActive
|
||||
required property Item sidebar
|
||||
|
||||
anchors.bottomMargin: (-implicitHeight - 5) * offsetScale
|
||||
implicitHeight: content.implicitHeight + Tokens.padding.small * 2
|
||||
implicitWidth: sidebar.width * (1 - sidebar.offsetScale)
|
||||
opacity: 1 - offsetScale
|
||||
visible: offsetScale < 1
|
||||
|
||||
Behavior on offsetScale {
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.expressiveDefaultSpatial
|
||||
easing: Tokens.anim.expressiveDefaultSpatial
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: content
|
||||
|
||||
active: root.shouldBeActive || root.visible
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 8
|
||||
anchors.top: parent.top
|
||||
|
||||
sourceComponent: Content {
|
||||
implicitWidth: root.implicitWidth - 8 * 2
|
||||
screenState: root.screenState
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user