mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
Revert "refactor: Add Drag & Drop to Control Center"
This reverts commit a207ed74ff.
This commit is contained in:
@@ -1,76 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import qs.Common
|
|
||||||
import qs.Modules.ControlCenter.Details
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property string expandedSection: ""
|
|
||||||
property var expandedWidgetData: null
|
|
||||||
|
|
||||||
height: active ? 250 : 0
|
|
||||||
visible: active
|
|
||||||
|
|
||||||
readonly property bool active: expandedSection !== ""
|
|
||||||
|
|
||||||
Behavior on height {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.mediumDuration
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.topMargin: Theme.spacingS
|
|
||||||
sourceComponent: {
|
|
||||||
if (!root.active) return null
|
|
||||||
|
|
||||||
if (expandedSection.startsWith("diskUsage_")) {
|
|
||||||
return diskUsageDetailComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (expandedSection) {
|
|
||||||
case "wifi": return networkDetailComponent
|
|
||||||
case "bluetooth": return bluetoothDetailComponent
|
|
||||||
case "audioOutput": return audioOutputDetailComponent
|
|
||||||
case "audioInput": return audioInputDetailComponent
|
|
||||||
case "battery": return batteryDetailComponent
|
|
||||||
default: return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: networkDetailComponent
|
|
||||||
NetworkDetail {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: bluetoothDetailComponent
|
|
||||||
BluetoothDetail {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: audioOutputDetailComponent
|
|
||||||
AudioOutputDetail {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: audioInputDetailComponent
|
|
||||||
AudioInputDetail {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: batteryDetailComponent
|
|
||||||
BatteryDetail {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: diskUsageDetailComponent
|
|
||||||
DiskUsageDetail {
|
|
||||||
currentMountPath: root.expandedWidgetData?.currentMountPath || "/"
|
|
||||||
instanceId: root.expandedWidgetData?.instanceId || ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,703 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import qs.Common
|
|
||||||
import qs.Services
|
|
||||||
import qs.Modules.ControlCenter.Widgets
|
|
||||||
import qs.Modules.ControlCenter.Components
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property bool editMode: false
|
|
||||||
property string expandedSection: ""
|
|
||||||
property int expandedWidgetIndex: -1
|
|
||||||
property var model: null
|
|
||||||
property var expandedWidgetData: null
|
|
||||||
|
|
||||||
signal expandClicked(var widgetData, int globalIndex)
|
|
||||||
signal removeWidget(int index)
|
|
||||||
signal moveWidget(int fromIndex, int toIndex)
|
|
||||||
signal toggleWidgetSize(int index)
|
|
||||||
|
|
||||||
readonly property int gridColumns: 4
|
|
||||||
readonly property real cellWidth: (width - (gridSpacing + 1) * (gridColumns - 1)) / gridColumns
|
|
||||||
readonly property real cellHeight: 60
|
|
||||||
readonly property real gridSpacing: 4
|
|
||||||
|
|
||||||
height: {
|
|
||||||
const dummy = [SettingsData.controlCenterWidgets?.length, widgetPositions.length]
|
|
||||||
return calculateGridHeight() + (detailHost.active ? detailHost.height + Theme.spacingL : 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateGridHeight() {
|
|
||||||
const widgets = SettingsData.controlCenterWidgets || []
|
|
||||||
if (widgets.length === 0)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
let rows = []
|
|
||||||
let currentRow = []
|
|
||||||
let currentWidth = 0
|
|
||||||
const spacing = gridSpacing
|
|
||||||
const baseWidth = width
|
|
||||||
|
|
||||||
for (var i = 0; i < widgets.length; i++) {
|
|
||||||
const widget = widgets[i]
|
|
||||||
const widgetWidth = widget.width || 50
|
|
||||||
|
|
||||||
let itemWidth
|
|
||||||
if (widgetWidth <= 25) {
|
|
||||||
itemWidth = (baseWidth - spacing * 3) / 4
|
|
||||||
} else if (widgetWidth <= 50) {
|
|
||||||
itemWidth = (baseWidth - spacing) / 2
|
|
||||||
} else if (widgetWidth <= 75) {
|
|
||||||
itemWidth = (baseWidth - spacing * 2) * 0.75
|
|
||||||
} else {
|
|
||||||
itemWidth = baseWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentRow.length > 0 && (currentWidth + spacing + itemWidth > baseWidth)) {
|
|
||||||
rows.push([...currentRow])
|
|
||||||
currentRow = [widget]
|
|
||||||
currentWidth = itemWidth
|
|
||||||
} else {
|
|
||||||
currentRow.push(widget)
|
|
||||||
currentWidth += (currentRow.length > 1 ? spacing : 0) + itemWidth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentRow.length > 0) {
|
|
||||||
rows.push(currentRow)
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows.length * cellHeight + (rows.length > 0 ? (rows.length - 1) * spacing : 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
DragDropDetailHost {
|
|
||||||
id: detailHost
|
|
||||||
y: calculateGridHeight()
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
expandedSection: root.expandedSection
|
|
||||||
expandedWidgetData: root.expandedWidgetData
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveToTop(item) {
|
|
||||||
const children = root.children
|
|
||||||
for (var i = 0; i < children.length; i++) {
|
|
||||||
if (children[i] === item)
|
|
||||||
continue
|
|
||||||
if (children[i].z)
|
|
||||||
children[i].z = Math.min(children[i].z, 999)
|
|
||||||
}
|
|
||||||
item.z = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: widgetRepeater
|
|
||||||
model: SettingsData.controlCenterWidgets || []
|
|
||||||
|
|
||||||
DragDropWidgetWrapper {
|
|
||||||
id: widgetWrapper
|
|
||||||
|
|
||||||
editMode: root.editMode
|
|
||||||
widgetData: modelData
|
|
||||||
widgetIndex: index
|
|
||||||
gridCellWidth: root.cellWidth
|
|
||||||
gridCellHeight: root.cellHeight
|
|
||||||
gridColumns: root.gridColumns
|
|
||||||
gridLayout: root
|
|
||||||
isSlider: {
|
|
||||||
const id = modelData.id || ""
|
|
||||||
return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"
|
|
||||||
}
|
|
||||||
|
|
||||||
widgetComponent: {
|
|
||||||
const id = modelData.id || ""
|
|
||||||
if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") {
|
|
||||||
return compoundPillComponent
|
|
||||||
} else if (id === "volumeSlider") {
|
|
||||||
return audioSliderComponent
|
|
||||||
} else if (id === "brightnessSlider") {
|
|
||||||
return brightnessSliderComponent
|
|
||||||
} else if (id === "inputVolumeSlider") {
|
|
||||||
return inputAudioSliderComponent
|
|
||||||
} else if (id === "battery") {
|
|
||||||
const widgetWidth = modelData.width || 50
|
|
||||||
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
|
|
||||||
} else if (id === "diskUsage") {
|
|
||||||
return diskUsagePillComponent
|
|
||||||
} else {
|
|
||||||
const widgetWidth = modelData.width || 50
|
|
||||||
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x: calculateWidgetX(index)
|
|
||||||
y: calculateWidgetY(index)
|
|
||||||
|
|
||||||
onWidgetMoved: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
|
||||||
onRemoveWidget: index => root.removeWidget(index)
|
|
||||||
onToggleWidgetSize: index => root.toggleWidgetSize(index)
|
|
||||||
|
|
||||||
Behavior on x {
|
|
||||||
enabled: !editMode
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.mediumDuration
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on y {
|
|
||||||
enabled: !editMode
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.mediumDuration
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property var widgetPositions: calculateAllWidgetPositions()
|
|
||||||
|
|
||||||
function calculateAllWidgetPositions() {
|
|
||||||
const widgets = SettingsData.controlCenterWidgets || []
|
|
||||||
let positions = []
|
|
||||||
let currentX = 0
|
|
||||||
let currentY = 0
|
|
||||||
|
|
||||||
for (var i = 0; i < widgets.length; i++) {
|
|
||||||
const widget = widgets[i]
|
|
||||||
const widgetWidth = widget.width || 50
|
|
||||||
let cellsNeeded = 1
|
|
||||||
|
|
||||||
if (widgetWidth <= 25)
|
|
||||||
cellsNeeded = 1
|
|
||||||
else if (widgetWidth <= 50)
|
|
||||||
cellsNeeded = 2
|
|
||||||
else if (widgetWidth <= 75)
|
|
||||||
cellsNeeded = 3
|
|
||||||
else
|
|
||||||
cellsNeeded = 4
|
|
||||||
|
|
||||||
if (currentX + cellsNeeded > gridColumns) {
|
|
||||||
currentX = 0
|
|
||||||
currentY++
|
|
||||||
}
|
|
||||||
|
|
||||||
const horizontalSpacing = gridSpacing
|
|
||||||
positions[i] = {
|
|
||||||
"x": currentX * cellWidth + (currentX > 0 ? currentX * horizontalSpacing : 0),
|
|
||||||
"y": currentY * cellHeight + (currentY > 0 ? currentY * gridSpacing : 0),
|
|
||||||
"cellsUsed": cellsNeeded
|
|
||||||
}
|
|
||||||
|
|
||||||
currentX += cellsNeeded
|
|
||||||
|
|
||||||
if (currentX >= gridColumns) {
|
|
||||||
currentX = 0
|
|
||||||
currentY++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return positions
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateWidgetX(widgetIndex) {
|
|
||||||
if (widgetIndex < 0 || widgetIndex >= widgetPositions.length)
|
|
||||||
return 0
|
|
||||||
return widgetPositions[widgetIndex].x
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateWidgetY(widgetIndex) {
|
|
||||||
if (widgetIndex < 0 || widgetIndex >= widgetPositions.length)
|
|
||||||
return 0
|
|
||||||
return widgetPositions[widgetIndex].y
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: SettingsData
|
|
||||||
function onControlCenterWidgetsChanged() {
|
|
||||||
widgetPositions = calculateAllWidgetPositions()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: compoundPillComponent
|
|
||||||
CompoundPill {
|
|
||||||
property var widgetData: parent.widgetData || {}
|
|
||||||
property int widgetIndex: parent.widgetIndex || 0
|
|
||||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
|
||||||
width: parent.width
|
|
||||||
height: cellHeight
|
|
||||||
iconName: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "wifi":
|
|
||||||
{
|
|
||||||
if (NetworkService.wifiToggling)
|
|
||||||
return "sync"
|
|
||||||
if (NetworkService.networkStatus === "ethernet")
|
|
||||||
return "settings_ethernet"
|
|
||||||
if (NetworkService.networkStatus === "wifi")
|
|
||||||
return NetworkService.wifiSignalIcon
|
|
||||||
if (NetworkService.wifiEnabled)
|
|
||||||
return "wifi_off"
|
|
||||||
return "wifi_off"
|
|
||||||
}
|
|
||||||
case "bluetooth":
|
|
||||||
{
|
|
||||||
if (!BluetoothService.available)
|
|
||||||
return "bluetooth_disabled"
|
|
||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
|
|
||||||
return "bluetooth_disabled"
|
|
||||||
const primaryDevice = (() => {
|
|
||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
|
||||||
return null
|
|
||||||
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
|
||||||
for (let device of devices) {
|
|
||||||
if (device && device.connected)
|
|
||||||
return device
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
})()
|
|
||||||
if (primaryDevice)
|
|
||||||
return BluetoothService.getDeviceIcon(primaryDevice)
|
|
||||||
return "bluetooth"
|
|
||||||
}
|
|
||||||
case "audioOutput":
|
|
||||||
{
|
|
||||||
if (!AudioService.sink)
|
|
||||||
return "volume_off"
|
|
||||||
let volume = AudioService.sink.audio.volume
|
|
||||||
let muted = AudioService.sink.audio.muted
|
|
||||||
if (muted || volume === 0.0)
|
|
||||||
return "volume_off"
|
|
||||||
if (volume <= 0.33)
|
|
||||||
return "volume_down"
|
|
||||||
if (volume <= 0.66)
|
|
||||||
return "volume_up"
|
|
||||||
return "volume_up"
|
|
||||||
}
|
|
||||||
case "audioInput":
|
|
||||||
{
|
|
||||||
if (!AudioService.source)
|
|
||||||
return "mic_off"
|
|
||||||
let muted = AudioService.source.audio.muted
|
|
||||||
return muted ? "mic_off" : "mic"
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return widgetDef?.icon || "help"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
primaryText: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "wifi":
|
|
||||||
{
|
|
||||||
if (NetworkService.wifiToggling)
|
|
||||||
return NetworkService.wifiEnabled ? "Disabling WiFi..." : "Enabling WiFi..."
|
|
||||||
if (NetworkService.networkStatus === "ethernet")
|
|
||||||
return "Ethernet"
|
|
||||||
if (NetworkService.networkStatus === "wifi" && NetworkService.currentWifiSSID)
|
|
||||||
return NetworkService.currentWifiSSID
|
|
||||||
if (NetworkService.wifiEnabled)
|
|
||||||
return "Not connected"
|
|
||||||
return "WiFi off"
|
|
||||||
}
|
|
||||||
case "bluetooth":
|
|
||||||
{
|
|
||||||
if (!BluetoothService.available)
|
|
||||||
return "Bluetooth"
|
|
||||||
if (!BluetoothService.adapter)
|
|
||||||
return "No adapter"
|
|
||||||
if (!BluetoothService.adapter.enabled)
|
|
||||||
return "Disabled"
|
|
||||||
return "Enabled"
|
|
||||||
}
|
|
||||||
case "audioOutput":
|
|
||||||
return AudioService.sink?.description || "No output device"
|
|
||||||
case "audioInput":
|
|
||||||
return AudioService.source?.description || "No input device"
|
|
||||||
default:
|
|
||||||
return widgetDef?.text || "Unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
secondaryText: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "wifi":
|
|
||||||
{
|
|
||||||
if (NetworkService.wifiToggling)
|
|
||||||
return "Please wait..."
|
|
||||||
if (NetworkService.networkStatus === "ethernet")
|
|
||||||
return "Connected"
|
|
||||||
if (NetworkService.networkStatus === "wifi")
|
|
||||||
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected"
|
|
||||||
if (NetworkService.wifiEnabled)
|
|
||||||
return "Select network"
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
case "bluetooth":
|
|
||||||
{
|
|
||||||
if (!BluetoothService.available)
|
|
||||||
return "No adapters"
|
|
||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
|
|
||||||
return "Off"
|
|
||||||
const primaryDevice = (() => {
|
|
||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
|
||||||
return null
|
|
||||||
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
|
||||||
for (let device of devices) {
|
|
||||||
if (device && device.connected)
|
|
||||||
return device
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
})()
|
|
||||||
if (primaryDevice)
|
|
||||||
return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || "Connected Device"
|
|
||||||
return "No devices"
|
|
||||||
}
|
|
||||||
case "audioOutput":
|
|
||||||
{
|
|
||||||
if (!AudioService.sink)
|
|
||||||
return "Select device"
|
|
||||||
if (AudioService.sink.audio.muted)
|
|
||||||
return "Muted"
|
|
||||||
return Math.round(AudioService.sink.audio.volume * 100) + "%"
|
|
||||||
}
|
|
||||||
case "audioInput":
|
|
||||||
{
|
|
||||||
if (!AudioService.source)
|
|
||||||
return "Select device"
|
|
||||||
if (AudioService.source.audio.muted)
|
|
||||||
return "Muted"
|
|
||||||
return Math.round(AudioService.source.audio.volume * 100) + "%"
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return widgetDef?.description || ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isActive: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "wifi":
|
|
||||||
{
|
|
||||||
if (NetworkService.wifiToggling)
|
|
||||||
return false
|
|
||||||
if (NetworkService.networkStatus === "ethernet")
|
|
||||||
return true
|
|
||||||
if (NetworkService.networkStatus === "wifi")
|
|
||||||
return true
|
|
||||||
return NetworkService.wifiEnabled
|
|
||||||
}
|
|
||||||
case "bluetooth":
|
|
||||||
return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled)
|
|
||||||
case "audioOutput":
|
|
||||||
return !!(AudioService.sink && !AudioService.sink.audio.muted)
|
|
||||||
case "audioInput":
|
|
||||||
return !!(AudioService.source && !AudioService.source.audio.muted)
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enabled: !root.editMode && (widgetDef?.enabled ?? true)
|
|
||||||
onToggled: {
|
|
||||||
if (root.editMode)
|
|
||||||
return
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "wifi":
|
|
||||||
{
|
|
||||||
if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) {
|
|
||||||
NetworkService.toggleWifiRadio()
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "bluetooth":
|
|
||||||
{
|
|
||||||
if (BluetoothService.available && BluetoothService.adapter) {
|
|
||||||
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "audioOutput":
|
|
||||||
{
|
|
||||||
if (AudioService.sink && AudioService.sink.audio) {
|
|
||||||
AudioService.sink.audio.muted = !AudioService.sink.audio.muted
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "audioInput":
|
|
||||||
{
|
|
||||||
if (AudioService.source && AudioService.source.audio) {
|
|
||||||
AudioService.source.audio.muted = !AudioService.source.audio.muted
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onExpandClicked: {
|
|
||||||
if (!root.editMode)
|
|
||||||
root.expandClicked(widgetData, widgetIndex)
|
|
||||||
}
|
|
||||||
onWheelEvent: function (wheelEvent) {
|
|
||||||
if (root.editMode)
|
|
||||||
return
|
|
||||||
const id = widgetData.id || ""
|
|
||||||
if (id === "audioOutput") {
|
|
||||||
if (!AudioService.sink || !AudioService.sink.audio)
|
|
||||||
return
|
|
||||||
let delta = wheelEvent.angleDelta.y
|
|
||||||
let currentVolume = AudioService.sink.audio.volume * 100
|
|
||||||
let newVolume
|
|
||||||
if (delta > 0)
|
|
||||||
newVolume = Math.min(100, currentVolume + 5)
|
|
||||||
else
|
|
||||||
newVolume = Math.max(0, currentVolume - 5)
|
|
||||||
AudioService.sink.audio.muted = false
|
|
||||||
AudioService.sink.audio.volume = newVolume / 100
|
|
||||||
wheelEvent.accepted = true
|
|
||||||
} else if (id === "audioInput") {
|
|
||||||
if (!AudioService.source || !AudioService.source.audio)
|
|
||||||
return
|
|
||||||
let delta = wheelEvent.angleDelta.y
|
|
||||||
let currentVolume = AudioService.source.audio.volume * 100
|
|
||||||
let newVolume
|
|
||||||
if (delta > 0)
|
|
||||||
newVolume = Math.min(100, currentVolume + 5)
|
|
||||||
else
|
|
||||||
newVolume = Math.max(0, currentVolume - 5)
|
|
||||||
AudioService.source.audio.muted = false
|
|
||||||
AudioService.source.audio.volume = newVolume / 100
|
|
||||||
wheelEvent.accepted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: audioSliderComponent
|
|
||||||
AudioSliderRow {
|
|
||||||
width: parent.width
|
|
||||||
height: 14
|
|
||||||
enabled: !root.editMode
|
|
||||||
property color sliderTrackColor: Theme.surfaceContainerHigh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: brightnessSliderComponent
|
|
||||||
BrightnessSliderRow {
|
|
||||||
width: parent.width
|
|
||||||
height: 14
|
|
||||||
enabled: !root.editMode
|
|
||||||
property color sliderTrackColor: Theme.surfaceContainerHigh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: inputAudioSliderComponent
|
|
||||||
InputAudioSliderRow {
|
|
||||||
width: parent.width
|
|
||||||
height: 14
|
|
||||||
enabled: !root.editMode
|
|
||||||
property color sliderTrackColor: Theme.surfaceContainerHigh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: batteryPillComponent
|
|
||||||
BatteryPill {
|
|
||||||
width: parent.width
|
|
||||||
height: cellHeight
|
|
||||||
enabled: !root.editMode
|
|
||||||
onExpandClicked: {
|
|
||||||
if (!root.editMode)
|
|
||||||
root.expandClicked(parent.widgetData, parent.widgetIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: smallBatteryComponent
|
|
||||||
SmallBatteryButton {
|
|
||||||
width: parent.width
|
|
||||||
height: 48
|
|
||||||
enabled: !root.editMode
|
|
||||||
onClicked: {
|
|
||||||
if (!root.editMode)
|
|
||||||
root.expandClicked(parent.widgetData, parent.widgetIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: toggleButtonComponent
|
|
||||||
ToggleButton {
|
|
||||||
property var widgetData: parent.widgetData || {}
|
|
||||||
property int widgetIndex: parent.widgetIndex || 0
|
|
||||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
|
||||||
width: parent.width
|
|
||||||
height: cellHeight
|
|
||||||
|
|
||||||
iconName: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "nightMode":
|
|
||||||
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
|
|
||||||
case "darkMode":
|
|
||||||
return "contrast"
|
|
||||||
case "doNotDisturb":
|
|
||||||
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
|
|
||||||
case "idleInhibitor":
|
|
||||||
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
|
|
||||||
default:
|
|
||||||
return widgetDef?.icon || "help"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
text: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "nightMode":
|
|
||||||
return "Night Mode"
|
|
||||||
case "darkMode":
|
|
||||||
return SessionData.isLightMode ? "Light Mode" : "Dark Mode"
|
|
||||||
case "doNotDisturb":
|
|
||||||
return "Do Not Disturb"
|
|
||||||
case "idleInhibitor":
|
|
||||||
return SessionService.idleInhibited ? "Keeping Awake" : "Keep Awake"
|
|
||||||
default:
|
|
||||||
return widgetDef?.text || "Unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
|
|
||||||
|
|
||||||
isActive: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "nightMode":
|
|
||||||
return DisplayService.nightModeEnabled || false
|
|
||||||
case "darkMode":
|
|
||||||
return !SessionData.isLightMode
|
|
||||||
case "doNotDisturb":
|
|
||||||
return SessionData.doNotDisturb || false
|
|
||||||
case "idleInhibitor":
|
|
||||||
return SessionService.idleInhibited || false
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled: !root.editMode && (widgetDef?.enabled ?? true)
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (root.editMode)
|
|
||||||
return
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "nightMode":
|
|
||||||
{
|
|
||||||
if (DisplayService.automationAvailable)
|
|
||||||
DisplayService.toggleNightMode()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "darkMode":
|
|
||||||
{
|
|
||||||
Theme.toggleLightMode()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "doNotDisturb":
|
|
||||||
{
|
|
||||||
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "idleInhibitor":
|
|
||||||
{
|
|
||||||
SessionService.toggleIdleInhibit()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: smallToggleComponent
|
|
||||||
SmallToggleButton {
|
|
||||||
property var widgetData: parent.widgetData || {}
|
|
||||||
property int widgetIndex: parent.widgetIndex || 0
|
|
||||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
|
||||||
width: parent.width
|
|
||||||
height: 48
|
|
||||||
|
|
||||||
iconName: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "nightMode":
|
|
||||||
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
|
|
||||||
case "darkMode":
|
|
||||||
return "contrast"
|
|
||||||
case "doNotDisturb":
|
|
||||||
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
|
|
||||||
case "idleInhibitor":
|
|
||||||
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
|
|
||||||
default:
|
|
||||||
return widgetDef?.icon || "help"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
|
|
||||||
|
|
||||||
isActive: {
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "nightMode":
|
|
||||||
return DisplayService.nightModeEnabled || false
|
|
||||||
case "darkMode":
|
|
||||||
return !SessionData.isLightMode
|
|
||||||
case "doNotDisturb":
|
|
||||||
return SessionData.doNotDisturb || false
|
|
||||||
case "idleInhibitor":
|
|
||||||
return SessionService.idleInhibited || false
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled: !root.editMode && (widgetDef?.enabled ?? true)
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (root.editMode)
|
|
||||||
return
|
|
||||||
switch (widgetData.id || "") {
|
|
||||||
case "nightMode":
|
|
||||||
{
|
|
||||||
if (DisplayService.automationAvailable)
|
|
||||||
DisplayService.toggleNightMode()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "darkMode":
|
|
||||||
{
|
|
||||||
Theme.toggleLightMode()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "doNotDisturb":
|
|
||||||
{
|
|
||||||
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "idleInhibitor":
|
|
||||||
{
|
|
||||||
SessionService.toggleIdleInhibit()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: diskUsagePillComponent
|
|
||||||
DiskUsagePill {
|
|
||||||
width: parent.width
|
|
||||||
height: cellHeight
|
|
||||||
enabled: !root.editMode
|
|
||||||
mountPath: parent.widgetData?.mountPath || "/"
|
|
||||||
instanceId: parent.widgetData?.instanceId || ""
|
|
||||||
onExpandClicked: {
|
|
||||||
if (!root.editMode)
|
|
||||||
root.expandClicked(parent.widgetData, parent.widgetIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import qs.Common
|
|
||||||
import qs.Services
|
|
||||||
import qs.Widgets
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property bool editMode: false
|
|
||||||
property var widgetData: null
|
|
||||||
property int widgetIndex: -1
|
|
||||||
property bool isSlider: false
|
|
||||||
property Component widgetComponent: null
|
|
||||||
property real gridCellWidth: 100
|
|
||||||
property real gridCellHeight: 60
|
|
||||||
property int gridColumns: 4
|
|
||||||
property var gridLayout: null
|
|
||||||
|
|
||||||
signal widgetMoved(int fromIndex, int toIndex)
|
|
||||||
signal removeWidget(int index)
|
|
||||||
signal toggleWidgetSize(int index)
|
|
||||||
|
|
||||||
width: {
|
|
||||||
const widgetWidth = widgetData?.width || 50
|
|
||||||
if (widgetWidth <= 25) return gridCellWidth
|
|
||||||
else if (widgetWidth <= 50) return gridCellWidth * 2
|
|
||||||
else if (widgetWidth <= 75) return gridCellWidth * 3
|
|
||||||
else return gridCellWidth * 4
|
|
||||||
}
|
|
||||||
height: gridCellHeight
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: dragIndicator
|
|
||||||
anchors.fill: parent
|
|
||||||
color: "transparent"
|
|
||||||
border.color: Theme.primary
|
|
||||||
border.width: dragArea.drag.active ? 2 : 0
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
opacity: dragArea.drag.active ? 0.8 : 1.0
|
|
||||||
z: dragArea.drag.active ? 1000 : 1
|
|
||||||
|
|
||||||
Behavior on border.width {
|
|
||||||
NumberAnimation { duration: 150 }
|
|
||||||
}
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation { duration: 150 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: widgetLoader
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: widgetComponent
|
|
||||||
property var widgetData: root.widgetData
|
|
||||||
property int widgetIndex: root.widgetIndex
|
|
||||||
property int globalWidgetIndex: root.widgetIndex
|
|
||||||
property int widgetWidth: root.widgetData?.width || 50
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: editModeBlocker
|
|
||||||
anchors.fill: parent
|
|
||||||
enabled: root.editMode
|
|
||||||
acceptedButtons: Qt.AllButtons
|
|
||||||
onPressed: mouse.accepted = true
|
|
||||||
onWheel: wheel.accepted = true
|
|
||||||
z: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: dragArea
|
|
||||||
anchors.fill: parent
|
|
||||||
enabled: editMode
|
|
||||||
cursorShape: editMode ? Qt.OpenHandCursor : Qt.ArrowCursor
|
|
||||||
drag.target: editMode ? root : null
|
|
||||||
drag.axis: Drag.XAndYAxis
|
|
||||||
drag.smoothed: true
|
|
||||||
|
|
||||||
onPressed: {
|
|
||||||
if (editMode) {
|
|
||||||
cursorShape = Qt.ClosedHandCursor
|
|
||||||
root.z = 1000
|
|
||||||
root.parent.moveToTop(root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onReleased: {
|
|
||||||
if (editMode) {
|
|
||||||
cursorShape = Qt.OpenHandCursor
|
|
||||||
root.z = 1
|
|
||||||
root.snapToGrid()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Drag.active: dragArea.drag.active
|
|
||||||
Drag.hotSpot.x: width / 2
|
|
||||||
Drag.hotSpot.y: height / 2
|
|
||||||
|
|
||||||
function snapToGrid() {
|
|
||||||
if (!editMode || !gridLayout) return
|
|
||||||
|
|
||||||
const globalPos = root.mapToItem(gridLayout, 0, 0)
|
|
||||||
const cellWidth = gridLayout.width / gridColumns
|
|
||||||
const cellHeight = gridCellHeight + Theme.spacingS
|
|
||||||
|
|
||||||
let targetCol = Math.max(0, Math.round(globalPos.x / cellWidth))
|
|
||||||
let targetRow = Math.max(0, Math.round(globalPos.y / cellHeight))
|
|
||||||
|
|
||||||
const widgetCells = Math.ceil(root.width / cellWidth)
|
|
||||||
|
|
||||||
if (targetCol + widgetCells > gridColumns) {
|
|
||||||
targetCol = Math.max(0, gridColumns - widgetCells)
|
|
||||||
}
|
|
||||||
|
|
||||||
const newIndex = findBestInsertionIndex(targetRow, targetCol)
|
|
||||||
|
|
||||||
if (newIndex !== widgetIndex && newIndex >= 0 && newIndex < (SettingsData.controlCenterWidgets?.length || 0)) {
|
|
||||||
widgetMoved(widgetIndex, newIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findBestInsertionIndex(targetRow, targetCol) {
|
|
||||||
const widgets = SettingsData.controlCenterWidgets || []
|
|
||||||
if (!widgets.length) return 0
|
|
||||||
|
|
||||||
const targetPosition = targetRow * gridColumns + targetCol
|
|
||||||
|
|
||||||
// Find the widget position closest to our target
|
|
||||||
let bestIndex = 0
|
|
||||||
let bestDistance = Infinity
|
|
||||||
|
|
||||||
for (let i = 0; i <= widgets.length; i++) {
|
|
||||||
if (i === widgetIndex) continue
|
|
||||||
|
|
||||||
let currentPos = calculatePositionForIndex(i)
|
|
||||||
let distance = Math.abs(currentPos - targetPosition)
|
|
||||||
|
|
||||||
if (distance < bestDistance) {
|
|
||||||
bestDistance = distance
|
|
||||||
bestIndex = i > widgetIndex ? i - 1 : i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.max(0, Math.min(bestIndex, widgets.length - 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculatePositionForIndex(index) {
|
|
||||||
const widgets = SettingsData.controlCenterWidgets || []
|
|
||||||
let currentX = 0
|
|
||||||
let currentY = 0
|
|
||||||
|
|
||||||
for (let i = 0; i < index && i < widgets.length; i++) {
|
|
||||||
if (i === widgetIndex) continue
|
|
||||||
|
|
||||||
const widget = widgets[i]
|
|
||||||
const widgetWidth = widget.width || 50
|
|
||||||
let cellsNeeded = widgetWidth <= 25 ? 1 : widgetWidth <= 50 ? 2 : widgetWidth <= 75 ? 3 : 4
|
|
||||||
|
|
||||||
if (currentX + cellsNeeded > gridColumns) {
|
|
||||||
currentX = 0
|
|
||||||
currentY++
|
|
||||||
}
|
|
||||||
|
|
||||||
currentX += cellsNeeded
|
|
||||||
if (currentX >= gridColumns) {
|
|
||||||
currentX = 0
|
|
||||||
currentY++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentY * gridColumns + currentX
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWidgetWidth(widgetWidth) {
|
|
||||||
const cellWidth = gridLayout ? gridLayout.width / gridColumns : gridCellWidth
|
|
||||||
if (widgetWidth <= 25) return cellWidth
|
|
||||||
else if (widgetWidth <= 50) return cellWidth * 2
|
|
||||||
else if (widgetWidth <= 75) return cellWidth * 3
|
|
||||||
else return cellWidth * 4
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: 16
|
|
||||||
height: 16
|
|
||||||
radius: 8
|
|
||||||
color: Theme.error
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.margins: -4
|
|
||||||
visible: editMode
|
|
||||||
z: 10
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
name: "close"
|
|
||||||
size: 12
|
|
||||||
color: Theme.primaryText
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: removeWidget(widgetIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PieChartSizeControl {
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.margins: -6
|
|
||||||
visible: editMode
|
|
||||||
z: 10
|
|
||||||
currentSize: root.widgetData?.width || 50
|
|
||||||
isSlider: root.isSlider
|
|
||||||
widgetIndex: root.widgetIndex
|
|
||||||
onSizeChanged: (newSize) => {
|
|
||||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
|
||||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
|
||||||
widgets[widgetIndex].width = newSize
|
|
||||||
SettingsData.setControlCenterWidgets(widgets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: dragHandle
|
|
||||||
width: 16
|
|
||||||
height: 12
|
|
||||||
radius: 2
|
|
||||||
color: Theme.primary
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.margins: 4
|
|
||||||
visible: editMode
|
|
||||||
z: 15
|
|
||||||
opacity: dragArea.drag.active ? 1.0 : 0.7
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
name: "drag_indicator"
|
|
||||||
size: 10
|
|
||||||
color: Theme.primaryText
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation { duration: 150 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
color: editMode ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
border.color: "transparent"
|
|
||||||
border.width: 0
|
|
||||||
z: -1
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation { duration: Theme.shortDuration }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
241
Modules/ControlCenter/Components/EditModeOverlay.qml
Normal file
241
Modules/ControlCenter/Components/EditModeOverlay.qml
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool editMode: false
|
||||||
|
property var widgetData: null
|
||||||
|
property int widgetIndex: -1
|
||||||
|
property bool showSizeControls: true
|
||||||
|
property bool isSlider: false
|
||||||
|
|
||||||
|
signal removeWidget(int index)
|
||||||
|
signal toggleWidgetSize(int index)
|
||||||
|
signal moveWidget(int fromIndex, int toIndex)
|
||||||
|
|
||||||
|
// Delete button in top-right
|
||||||
|
Rectangle {
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
radius: 8
|
||||||
|
color: Theme.error
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: -4
|
||||||
|
visible: editMode
|
||||||
|
z: 10
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "close"
|
||||||
|
size: 12
|
||||||
|
color: Theme.primaryText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.removeWidget(widgetIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size control buttons in bottom-right
|
||||||
|
Row {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: -8
|
||||||
|
spacing: 4
|
||||||
|
visible: editMode && showSizeControls
|
||||||
|
z: 10
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
radius: 12
|
||||||
|
color: (widgetData?.width || 50) === 25 ? Theme.primary : Theme.primaryContainer
|
||||||
|
border.color: Theme.primary
|
||||||
|
border.width: 0
|
||||||
|
visible: !isSlider
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "25"
|
||||||
|
font.pixelSize: 10
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: (widgetData?.width || 50) === 25 ? Theme.primaryText : Theme.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||||
|
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||||
|
widgets[widgetIndex].width = 25
|
||||||
|
SettingsData.setControlCenterWidgets(widgets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
radius: 12
|
||||||
|
color: (widgetData?.width || 50) === 50 ? Theme.primary : Theme.primaryContainer
|
||||||
|
border.color: Theme.primary
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "50"
|
||||||
|
font.pixelSize: 10
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: (widgetData?.width || 50) === 50 ? Theme.primaryText : Theme.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||||
|
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||||
|
widgets[widgetIndex].width = 50
|
||||||
|
SettingsData.setControlCenterWidgets(widgets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
radius: 12
|
||||||
|
color: (widgetData?.width || 50) === 75 ? Theme.primary : Theme.primaryContainer
|
||||||
|
border.color: Theme.primary
|
||||||
|
border.width: 0
|
||||||
|
visible: !isSlider
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "75"
|
||||||
|
font.pixelSize: 10
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: (widgetData?.width || 50) === 75 ? Theme.primaryText : Theme.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||||
|
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||||
|
widgets[widgetIndex].width = 75
|
||||||
|
SettingsData.setControlCenterWidgets(widgets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
radius: 12
|
||||||
|
color: (widgetData?.width || 50) === 100 ? Theme.primary : Theme.primaryContainer
|
||||||
|
border.color: Theme.primary
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "100"
|
||||||
|
font.pixelSize: 9
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: (widgetData?.width || 50) === 100 ? Theme.primaryText : Theme.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||||
|
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||||
|
widgets[widgetIndex].width = 100
|
||||||
|
SettingsData.setControlCenterWidgets(widgets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrow buttons for reordering in top-left
|
||||||
|
Row {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: 4
|
||||||
|
spacing: 2
|
||||||
|
visible: editMode
|
||||||
|
z: 20
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
radius: 8
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
border.color: Theme.outline
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "keyboard_arrow_left"
|
||||||
|
size: 12
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: widgetIndex > 0
|
||||||
|
opacity: enabled ? 1.0 : 0.5
|
||||||
|
onClicked: root.moveWidget(widgetIndex, widgetIndex - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
radius: 8
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
border.color: Theme.outline
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "keyboard_arrow_right"
|
||||||
|
size: 12
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: widgetIndex < ((SettingsData.controlCenterWidgets?.length ?? 0) - 1)
|
||||||
|
opacity: enabled ? 1.0 : 0.5
|
||||||
|
onClicked: root.moveWidget(widgetIndex, widgetIndex + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Border highlight
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
border.color: Theme.primary
|
||||||
|
border.width: editMode ? 1 : 0
|
||||||
|
visible: editMode
|
||||||
|
z: -1
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
NumberAnimation { duration: Theme.shortDuration }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -178,6 +178,21 @@ Column {
|
|||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
|
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
|
||||||
return "bluetooth_disabled"
|
return "bluetooth_disabled"
|
||||||
}
|
}
|
||||||
|
const primaryDevice = (() => {
|
||||||
|
if (!BluetoothService.adapter || !BluetoothService.adapter.devices) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
||||||
|
for (let device of devices) {
|
||||||
|
if (device && device.connected) {
|
||||||
|
return device
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})()
|
||||||
|
if (primaryDevice) {
|
||||||
|
return BluetoothService.getDeviceIcon(primaryDevice)
|
||||||
|
}
|
||||||
return "bluetooth"
|
return "bluetooth"
|
||||||
}
|
}
|
||||||
case "audioOutput": {
|
case "audioOutput": {
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ DankPopout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DragDropGrid {
|
WidgetGrid {
|
||||||
id: widgetGrid
|
id: widgetGrid
|
||||||
width: parent.width
|
width: parent.width
|
||||||
editMode: root.editMode
|
editMode: root.editMode
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import qs.Common
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property int currentSize: 50
|
|
||||||
property bool isSlider: false
|
|
||||||
property int widgetIndex: -1
|
|
||||||
|
|
||||||
signal sizeChanged(int newSize)
|
|
||||||
|
|
||||||
width: 28
|
|
||||||
height: 28
|
|
||||||
|
|
||||||
readonly property var availableSizes: isSlider ? [50, 100] : [25, 50, 75, 100]
|
|
||||||
readonly property int currentSizeIndex: availableSizes.indexOf(currentSize)
|
|
||||||
|
|
||||||
Canvas {
|
|
||||||
id: pieCanvas
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
onPaint: {
|
|
||||||
const ctx = getContext("2d")
|
|
||||||
const centerX = width / 2
|
|
||||||
const centerY = height / 2
|
|
||||||
const radius = Math.min(width, height) / 2 - 2
|
|
||||||
|
|
||||||
ctx.clearRect(0, 0, width, height)
|
|
||||||
|
|
||||||
ctx.strokeStyle = Theme.primary
|
|
||||||
ctx.lineWidth = 1.5
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI)
|
|
||||||
ctx.stroke()
|
|
||||||
|
|
||||||
if (availableSizes.length > 0 && currentSizeIndex >= 0) {
|
|
||||||
const segmentAngle = (2 * Math.PI) / availableSizes.length
|
|
||||||
const startAngle = -Math.PI / 2
|
|
||||||
const endAngle = startAngle + segmentAngle * (currentSizeIndex + 1)
|
|
||||||
|
|
||||||
ctx.fillStyle = Theme.primary
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(centerX, centerY)
|
|
||||||
ctx.arc(centerX, centerY, radius - 1, startAngle, endAngle)
|
|
||||||
ctx.closePath()
|
|
||||||
ctx.fill()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: 12
|
|
||||||
height: 12
|
|
||||||
radius: 6
|
|
||||||
color: Theme.surfaceContainer
|
|
||||||
border.color: Theme.outline
|
|
||||||
border.width: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
const nextIndex = (currentSizeIndex + 1) % availableSizes.length
|
|
||||||
const newSize = availableSizes[nextIndex]
|
|
||||||
currentSize = newSize
|
|
||||||
pieCanvas.requestPaint()
|
|
||||||
sizeChanged(newSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onCurrentSizeChanged: {
|
|
||||||
pieCanvas.requestPaint()
|
|
||||||
}
|
|
||||||
|
|
||||||
onIsSliderChanged: {
|
|
||||||
if (isSlider && currentSize !== 50 && currentSize !== 100) {
|
|
||||||
currentSize = 50
|
|
||||||
}
|
|
||||||
pieCanvas.requestPaint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user