shift-shell/components/mobileshell/qml/actiondrawer/quicksettings/QuickSettings.qml
Devin Lin 7d3bf39750 mobileshell: Refactor and extract state to mobileshellstate plugin
This avoids mixing plasmashell state with our MobileShell component library (which really shouldn't have state at all).
2022-11-12 11:15:36 -05:00

304 lines
11 KiB
QML

/*
* SPDX-FileCopyrightText: 2014 Marco Martin <notmart@gmail.com>
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
import "../../components" as Components
import "../../components/util.js" as Util
/**
* Quick settings elements layout, change the height to clip.
*/
Item {
id: root
clip: true
required property var actionDrawer
readonly property real columns: Math.round(Util.applyMinMaxRange(3, 6, width / intendedColumnWidth))
readonly property real columnWidth: Math.floor(width / columns)
readonly property int minimizedColumns: Math.round(Util.applyMinMaxRange(5, 8, width / intendedMinimizedColumnWidth))
readonly property real minimizedColumnWidth: Math.floor(width / minimizedColumns)
readonly property real rowHeight: columnWidth * 0.7
readonly property real fullHeight: fullView.implicitHeight
readonly property real intendedColumnWidth: 120
readonly property real intendedMinimizedColumnWidth: PlasmaCore.Units.gridUnit * 3 + PlasmaCore.Units.largeSpacing
readonly property real minimizedRowHeight: PlasmaCore.Units.gridUnit * 3 + PlasmaCore.Units.largeSpacing
property real minimizedViewProgress: 0
property real fullViewProgress: 1
readonly property MobileShell.QuickSettingsModel quickSettingsModel: MobileShell.QuickSettingsModel {}
readonly property int columnCount: Math.floor(width/columnWidth)
readonly property int rowCount: {
let totalRows = Math.ceil(quickSettingsCount / columnCount);
let isPortrait = MobileShellState.Shell.orientation === MobileShellState.Shell.Portrait;
let maxRows = 5; // more than 5 is just disorienting
let targetRows = Math.floor(Window.height * (isPortrait ? 0.65 : 0.8) / rowHeight);
return Math.min(maxRows, Math.min(totalRows, targetRows));
}
readonly property int pageSize: rowCount * columnCount
readonly property int quickSettingsCount: quickSettingsModel.count
function resetSwipeView() {
if (MobileShellState.Shell.orientation === MobileShellState.Shell.Portrait) {
pageLoader.item.view.currentIndex = 0;
}
}
// return to the first page when the action drawer is closed
Connections {
target: actionDrawer
function onOpenedChanged() {
if (!actionDrawer.opened) {
resetSwipeView();
}
}
}
// view when fully open
ColumnLayout {
id: fullView
opacity: root.fullViewProgress
visible: opacity !== 0
transform: Translate { y: (1 - fullView.opacity) * root.rowHeight }
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
// Dynamically loads the appropriate view
Loader {
id: pageLoader
Layout.fillWidth: true
Layout.minimumHeight: rowCount * rowHeight
asynchronous: true
sourceComponent: MobileShellState.Shell.orientation === MobileShellState.Shell.Portrait ? swipeViewComponent : scrollViewComponent
}
BrightnessItem {
id: brightnessItem
Layout.bottomMargin: PlasmaCore.Units.smallSpacing * 2
Layout.leftMargin: PlasmaCore.Units.smallSpacing
Layout.rightMargin: PlasmaCore.Units.smallSpacing
Layout.fillWidth: true
}
}
// view when in minimized mode
RowLayout {
id: minimizedView
spacing: 0
opacity: root.minimizedViewProgress
visible: opacity !== 0
transform: Translate { y: (1 - minimizedView.opacity) * -root.rowHeight }
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Repeater {
model: MobileShell.PaginateModel {
sourceModel: quickSettingsModel
pageSize: minimizedColumns
}
delegate: Components.BaseItem {
required property var modelData
implicitHeight: root.minimizedRowHeight
implicitWidth: root.minimizedColumnWidth
horizontalPadding: (width - PlasmaCore.Units.gridUnit * 3) / 2
verticalPadding: (height - PlasmaCore.Units.gridUnit * 3) / 2
contentItem: QuickSettingsMinimizedDelegate {
restrictedPermissions: actionDrawer.restrictedPermissions
text: modelData.text
status: modelData.status
icon: modelData.icon
enabled: modelData.enabled
settingsCommand: modelData.settingsCommand
toggleFunction: modelData.toggle
onCloseRequested: {
actionDrawer.close();
}
}
}
}
}
// Loads portrait quick settings view
Component {
id: swipeViewComponent
ColumnLayout {
readonly property var view: swipeView
SwipeView {
id: swipeView
Layout.fillWidth: true
Layout.preferredHeight: rowCount * rowHeight
Repeater {
model: Math.ceil(quickSettingsCount / pageSize)
delegate: Flow {
id: flow
spacing: 0
required property int index
Repeater {
model: MobileShell.PaginateModel {
sourceModel: quickSettingsModel
pageSize: root.pageSize
firstItem: pageSize * flow.index
}
delegate: Loader {
required property var modelData
asynchronous: true
sourceComponent: quickSettingComponent
}
}
}
}
}
Loader {
id: indicatorLoader
Layout.alignment: Qt.AlignCenter
Layout.topMargin: PlasmaCore.Units.smallSpacing
Layout.leftMargin: PlasmaCore.Units.smallSpacing
Layout.rightMargin: PlasmaCore.Units.smallSpacing
// Avoid wasting space when not loaded
Layout.maximumHeight: active ? item.implicitHeight : 0
active: swipeView.count > 1 ? true: false
asynchronous: true
sourceComponent: PageIndicator {
count: swipeView.count
currentIndex: swipeView.currentIndex
delegate: Rectangle {
implicitWidth: 8
implicitHeight: count > 1 ? 8 : 0
radius: parent.width / 2
color: PlasmaCore.Theme.disabledTextColor
opacity: index === currentIndex ? 0.95 : 0.45
}
}
}
}
}
// Loads landscape quick settings view
Component {
id: scrollViewComponent
Item {
width: parent.width
height: rowCount * rowHeight
Flickable {
id: flickable
anchors.fill: parent
contentWidth: width
contentHeight: flow.height
clip: true
ScrollIndicator.vertical: ScrollIndicator {
id: scrollIndicator
visible: quickSettingsCount > pageSize ? true : false
position: 0.1
contentItem: Item {
implicitWidth: PlasmaCore.Units.smallSpacing / 4
Rectangle {
// shift over the indicator a bit to the right
anchors.fill: parent
anchors.leftMargin: 2
anchors.rightMargin: -2
color: PlasmaCore.Theme.textColor
opacity: scrollIndicator.active ? 0.5 : 0
Behavior on opacity { NumberAnimation {} }
}
}
}
Flow {
id: flow
width: parent.width
height: Math.ceil(quickSettingsCount / columnCount) * rowHeight
spacing: 0
Repeater {
model: quickSettingsModel
delegate: Loader {
required property var modelData
asynchronous: true
sourceComponent: quickSettingComponent
}
}
}
}
}
}
// Quick setting component
Component {
id: quickSettingComponent
Components.BaseItem {
height: root.rowHeight
width: root.columnWidth
padding: PlasmaCore.Units.smallSpacing
contentItem: QuickSettingsFullDelegate {
restrictedPermissions: actionDrawer.restrictedPermissions
text: modelData.text
status: modelData.status
icon: modelData.icon
enabled: modelData.enabled
settingsCommand: modelData.settingsCommand
toggleFunction: modelData.toggle
onCloseRequested: {
actionDrawer.close();
}
}
}
}
}