Rework top panel and improve appearance

This commit is contained in:
Devin Lin 2021-04-09 20:59:05 +00:00
parent 2154671058
commit 0ed2053e79
22 changed files with 1326 additions and 1056 deletions

View file

@ -7,12 +7,16 @@
import QtQuick 2.6 import QtQuick 2.6
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import QtQuick.Controls 2.4 as QQC2 import QtQuick.Controls 2.4 as QQC2
import QtGraphicalEffects 1.12
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kirigami 2.12 as Kirigami import org.kde.kirigami 2.12 as Kirigami
QQC2.Control { QQC2.Control {
id: root id: root
required property color backgroundColor
leftPadding: units.largeSpacing leftPadding: units.largeSpacing
topPadding: units.largeSpacing topPadding: units.largeSpacing
rightPadding: units.largeSpacing rightPadding: units.largeSpacing
@ -22,9 +26,15 @@ QQC2.Control {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
} }
PlasmaCore.FrameSvgItem {
imagePath: "widgets/panel-background"
prefix: "shadow"
anchors.fill: container
anchors.margins: -PlasmaCore.Units.smallSpacing
}
Rectangle { Rectangle {
id: container id: container
color: Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.backgroundColor, {"alpha": 0.85*255}) color: backgroundColor
anchors { anchors {
fill: parent fill: parent
leftMargin: PlasmaCore.Units.smallSpacing leftMargin: PlasmaCore.Units.smallSpacing

View file

@ -8,6 +8,7 @@ import QtQuick 2.12
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import QtQml.Models 2.12 import QtQml.Models 2.12
import org.kde.kirigami 2.12 as Kirigami
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
DrawerBackground { DrawerBackground {
@ -15,8 +16,12 @@ DrawerBackground {
property Item applet property Item applet
property ObjectModel fullRepresentationModel property ObjectModel fullRepresentationModel
property ListView fullRepresentationView property ListView fullRepresentationView
backgroundColor: (applet.backgroundHints === PlasmaCore.Types.NoBackground) ? "transparent" : Kirigami.ColorUtils.adjustColor(PlasmaCore.Theme.backgroundColor, {"alpha": 0.8*255})
visible: shouldBeVisible visible: shouldBeVisible
property bool shouldBeVisible: applet && (applet.status != PlasmaCore.Types.HiddenStatus && applet.status != PlasmaCore.Types.PassiveStatus) property bool shouldBeVisible: applet && (applet.status != PlasmaCore.Types.HiddenStatus && applet.status != PlasmaCore.Types.PassiveStatus)
height: parent.height height: parent.height
width: visible ? quickSettings.width : 0 width: visible ? quickSettings.width : 0
Layout.minimumHeight: applet && applet.switchHeight Layout.minimumHeight: applet && applet.switchHeight

View file

@ -20,5 +20,6 @@ FullContainer {
id: historyModel id: historyModel
showExpired: true showExpired: true
showDismissed: true showDismissed: true
expandUnread: true
} }
} }

View file

@ -0,0 +1,147 @@
/*
* SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.12
import QtQuick.Layouts 1.3
import QtQml.Models 2.12
import QtGraphicalEffects 1.12
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.workspace.components 2.0 as PlasmaWorkspace
import org.kde.taskmanager 0.1 as TaskManager
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import "LayoutManager.js" as LayoutManager
import "indicators" as Indicators
Item {
id: indicatorsRow
required property var colorGroup
required property bool showGradientBackground
required property bool showDropShadow
required property color backgroundColor
property alias colorScopeColor: icons.backgroundColor
property alias applets: appletIconsRow
PlasmaCore.DataSource {
id: timeSource
engine: "time"
connectedSources: ["Local"]
interval: 60 * 1000
}
DropShadow {
anchors.fill: icons
visible: showDropShadow
cached: true
horizontalOffset: 0
verticalOffset: 1
radius: 4.0
samples: 17
color: Qt.rgba(0,0,0,0.8)
source: icons
}
// screen top panel
PlasmaCore.ColorScope {
id: icons
z: 1
colorGroup: indicatorsRow.colorGroup
anchors.fill: parent
// background
Rectangle {
anchors.fill: parent
color: backgroundColor
}
Rectangle {
visible: showGradientBackground
anchors.fill: parent
gradient: Gradient {
GradientStop {
position: 1.0
color: "transparent"
}
GradientStop {
position: 0.0
color: Qt.rgba(0, 0, 0, 0.1)
}
}
}
Loader {
id: strengthLoader
height: parent.height
width: item ? item.width : 0
active: signalStrengthProvider
sourceComponent: Indicators.SignalStrength {
provider: signalStrengthProvider
}
}
Row {
id: statusNotifierIndicatorsRow
anchors.left: strengthLoader.right
height: parent.height
Repeater {
id: statusNotifierRepeater
model: PlasmaCore.SortFilterModel {
id: filteredStatusNotifiers
filterRole: "Title"
sourceModel: PlasmaCore.DataModel {
dataSource: statusNotifierSource
}
}
delegate: TaskWidget {}
}
}
PlasmaComponents.Label {
id: clock
property bool is24HourTime: plasmoid.nativeInterface.isSystem24HourFormat
anchors.fill: parent
text: Qt.formatTime(timeSource.data.Local.DateTime, is24HourTime ? "h:mm" : "h:mm ap")
color: PlasmaCore.ColorScope.textColor
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
font.pixelSize: height / 2
}
RowLayout {
id: appletIconsRow
anchors {
bottom: parent.bottom
right: simpleIndicatorsLayout.left
}
height: parent.height
}
RowLayout {
id: simpleIndicatorsLayout
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
rightMargin: units.smallSpacing
}
Indicators.Bluetooth { provider: bluetoothProvider }
Indicators.Wifi { provider: wifiProvider }
Indicators.Volume { provider: volumeProvider }
Indicators.Battery { provider: batteryProvider }
}
}
}

View file

@ -0,0 +1,216 @@
/*
* SPDX-FileCopyrightText: 2014 Marco Martin <notmart@gmail.com>
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
*
* 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.nanoshell 2.0 as NanoShell
NanoShell.FullScreenOverlay {
id: window
property int offset: 0 // slide progress
property int openThreshold: PlasmaCore.Units.gridUnit * 2
property bool userInteracting: false
property bool initiallyOpened: false // whether the panel is already open after a touch release (then don't restrict to collapsed height)
// height when quicksettings is fully open
required property int fullyOpenHeight
// flickable contentY
readonly property int openedContentY: wideScreen || offset > (collapsedHeight + openThreshold) ? -topEmptyAreaHeight : offsetToContentY(collapsedHeight)
readonly property int closedContentY: mainFlickable.contentHeight
readonly property bool wideScreen: width > height || width > units.gridUnit * 45
readonly property int drawerWidth: wideScreen ? contentItem.implicitWidth : width
property int drawerX: 0
property alias fixedArea: mainScope
property alias flickable: mainFlickable
color: "transparent"
property alias contentItem: contentArea.contentItem
property int topPanelHeight
property int collapsedHeight
property real topEmptyAreaHeight
property bool appletsShown: false // whether notifications or media player applets are shown
signal closed
width: Screen.width
height: Screen.height
onInitiallyOpenedChanged: {
if (initiallyOpened) mainFlickable.focus = true;
}
function offsetToContentY(num) { return -num + window.fullyOpenHeight; }
function contentYToOffset(num) { return offsetToContentY(num); }
// avoids binding loops
function updateOffset(delta) {
// only go to collapsed height for mousearea when not widescreen
let maximum = window.wideScreen ? window.fullyOpenHeight : collapsedHeight + openThreshold / 2;
offset = Math.max(0, Math.min(maximum, offset + delta));
if (!mainFlickable.moving && !mainFlickable.dragging && !mainFlickable.flicking) {
mainFlickable.contentY = offsetToContentY(window.offset);
}
}
enum MovementDirection {
None = 0,
Up,
Down
}
property int direction: SlidingContainer.MovementDirection.None
function cancelAnimations() {
closeAnim.stop();
openAnim.stop();
}
function open() {
cancelAnimations();
openAnim.restart();
initiallyOpened = true;
}
function close() {
cancelAnimations();
closeAnim.restart();
initiallyOpened = false;
}
function updateState() {
cancelAnimations();
if (window.offset <= 0) {
// close immediately, so that we don't have to wait units.longDuration
window.visible = false;
window.closed();
close();
} else if (window.direction === SlidingContainer.MovementDirection.None) {
if (window.offset < openThreshold) {
close();
} else {
open();
}
} else if (offset > openThreshold && window.direction === SlidingContainer.MovementDirection.Down) {
open();
} else if (mainFlickable.contentY > openThreshold) {
close();
} else {
open();
}
}
Timer {
id: updateStateTimer
interval: 0
onTriggered: updateState()
}
onActiveChanged: {
if (!active) {
close();
}
}
PropertyAnimation {
id: closeAnim
target: mainFlickable
properties: "contentY"
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
to: window.closedContentY
onFinished: {
window.visible = false;
window.closed();
}
}
PropertyAnimation {
id: openAnim
target: mainFlickable
properties: "contentY"
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
to: window.openedContentY
}
// fullscreen background
Rectangle {
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.75)
opacity: (appletsShown ? 0.85 : 0.6) * Math.max(0, Math.min(1, offset / window.collapsedHeight))
Behavior on opacity { // smooth opacity changes
NumberAnimation { duration: 70 }
}
}
PlasmaCore.ColorScope {
id: mainScope
colorGroup: PlasmaCore.Theme.ViewColorGroup
anchors.fill: parent
Flickable {
id: mainFlickable
anchors.fill: parent
property real oldContentY
contentY: contentHeight
onContentYChanged: {
if (contentY === oldContentY) {
window.direction = SlidingContainer.MovementDirection.None;
} else {
window.direction = contentY > oldContentY ? SlidingContainer.MovementDirection.Up : SlidingContainer.MovementDirection.Down;
}
window.offset = contentYToOffset(contentY);
oldContentY = contentY;
// close panel immediately after panel is not shown, and the flickable is not being dragged
if (initiallyOpened && window.offset <= 0 && !mainFlickable.dragging && !closeAnim.running && !openAnim.running) {
window.updateState();
focus = false;
}
}
boundsMovement: Flickable.StopAtBounds
contentWidth: window.width
contentHeight: window.height
bottomMargin: window.height
onMovementStarted: {
window.cancelAnimations();
window.userInteracting = true;
}
onFlickStarted: window.userInteracting = true;
onMovementEnded: {
window.userInteracting = false;
window.updateState();
}
onFlickEnded: {
window.userInteracting = true;
window.updateState();
}
MouseArea {
id: dismissArea
z: 2
width: parent.width
height: mainFlickable.contentHeight
onClicked: window.close();
// actual sliding contents
PlasmaComponents.Control {
id: contentArea
z: 1
x: drawerX
width: drawerWidth
}
}
}
}
}

View file

@ -1,225 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Marco Martin <notmart@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.14
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.nanoshell 2.0 as NanoShell
NanoShell.FullScreenOverlay {
id: window
property int offset: 0
property int openThreshold
property bool userInteracting: false
readonly property bool wideScreen: width > height || width > units.gridUnit * 45
readonly property int drawerWidth: wideScreen ? contentItem.implicitWidth : width
property int drawerX: 0
property alias fixedArea: mainScope
property alias flickable: mainFlickable
color: "transparent"
property alias contentItem: contentArea.contentItem
property int headerHeight
property real topEmptyAreaHeight
signal closed
width: Screen.width
height: Screen.height
enum MovementDirection {
None = 0,
Up,
Down
}
property int direction: SlidingPanel.MovementDirection.None
function cancelAnimations() {
closeAnim.stop();
openAnim.stop();
}
function open() {
cancelAnimations();
window.showFullScreen();
openAnim.restart();
}
function close() {
cancelAnimations();
closeAnim.restart();
}
function updateState() {
cancelAnimations();
if (window.offset <= -headerHeight) {
// close immediately, so that we don't have to wait units.longDuration
window.visible = false;
window.closed();
} else if (window.direction === SlidingPanel.MovementDirection.None) {
if (offset < openThreshold) {
close();
} else {
openAnim.restart();
}
} else if (offset > openThreshold && window.direction === SlidingPanel.MovementDirection.Down) {
openAnim.restart();
} else if (mainFlickable.contentY > openThreshold) {
close();
} else {
openAnim.restart();
}
}
Timer {
id: updateStateTimer
interval: 0
onTriggered: updateState()
}
onActiveChanged: {
if (!active) {
close();
}
}
/*onVisibleChanged: {
if (visible) {
window.width = Screen.width;
window.height = Screen.height;
window.requestActivate();
}
}*/
SequentialAnimation {
id: closeAnim
PropertyAnimation {
target: window
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "offset"
from: window.offset
to: -headerHeight
}
ScriptAction {
script: {
window.visible = false;
window.closed();
}
}
}
PropertyAnimation {
id: openAnim
target: window
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "offset"
from: window.offset
to: contentArea.height - topEmptyAreaHeight
}
Rectangle {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: parent.height - headerHeight // don't layer on top panel indicators (area is darkened separately)
color: "black"
opacity: 0.6 * Math.min(1, offset/contentArea.height)
Rectangle {
height: headerHeight
anchors {
left: parent.left
right: parent.right
bottom: parent.top
}
color: "black"
opacity: 0.2
}
Rectangle {
height: units.smallSpacing
anchors {
left: parent.left
right: parent.right
top: parent.top
}
gradient: Gradient {
GradientStop {
position: 1.0
color: Qt.rgba(0, 0, 0, 0.0)
}
GradientStop {
position: 0.5
color: Qt.rgba(0, 0, 0, 0.4)
}
GradientStop {
position: 1.0
color: "transparent"
}
}
}
}
PlasmaCore.ColorScope {
id: mainScope
anchors.fill: parent
Flickable {
id: mainFlickable
anchors {
fill: parent
topMargin: headerHeight
}
Binding {
target: mainFlickable
property: "contentY"
value: -window.offset + contentArea.height
when: !mainFlickable.moving && !mainFlickable.dragging && !mainFlickable.flicking
}
//no loop as those 2 values compute to exactly the same
onContentYChanged: {
if (contentY === oldContentY) {
window.direction = SlidingPanel.MovementDirection.None;
} else {
window.direction = contentY > oldContentY ? SlidingPanel.MovementDirection.Up : SlidingPanel.MovementDirection.Down;
}
window.offset = -contentY + contentArea.height
oldContentY = contentY;
}
property real oldContentY
boundsMovement: Flickable.StopAtBounds
contentWidth: window.width
contentHeight: window.height*2 - headerHeight*2
bottomMargin: window.height
onMovementStarted: {
window.cancelAnimations();
window.userInteracting = true;
}
onFlickStarted: window.userInteracting = true;
onMovementEnded: {
window.userInteracting = false;
window.updateState();
}
onFlickEnded: {
window.userInteracting = true;
window.updateState();
}
MouseArea {
id: dismissArea
z: 2
width: parent.width
height: mainFlickable.contentHeight
onClicked: window.close();
PlasmaComponents.Control {
id: contentArea
z: 1
y: 0
x: drawerX
width: drawerWidth
}
}
}
}
}

View file

@ -1,4 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
* SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org> * SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
* *
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
@ -11,31 +12,27 @@ import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.workspace.components 2.0 as PW import org.kde.plasma.workspace.components 2.0 as PW
import "providers"
RowLayout { RowLayout {
visible: pmSource.data["Battery"]["Has Cumulative"] required property BatteryProvider provider
visible: provider.isVisible
PW.BatteryIcon { PW.BatteryIcon {
id: battery id: battery
Layout.preferredWidth: height Layout.preferredWidth: height
Layout.fillHeight: true Layout.fillHeight: true
hasBattery: true hasBattery: true
percent: pmSource.data["Battery"]["Percent"] percent: provider.percent
pluggedIn: pmSource.data["AC Adapter"] ? pmSource.data["AC Adapter"]["Plugged in"] : false pluggedIn: provider.pluggedIn
height: batteryLabel.height height: batteryLabel.height
width: batteryLabel.height width: batteryLabel.height
PlasmaCore.DataSource {
id: pmSource
engine: "powermanagement"
connectedSources: ["Battery", "AC Adapter"]
}
} }
PlasmaComponents.Label { PlasmaComponents.Label {
id: batteryLabel id: batteryLabel
text: i18n("%1%", battery.percent) text: i18n("%1%", provider.percent)
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: PlasmaCore.ColorScope.textColor color: PlasmaCore.ColorScope.textColor

View file

@ -1,4 +1,5 @@
/* /*
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org> SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com> SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
@ -11,38 +12,17 @@ import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.bluezqt 1.0 as BluezQt import org.kde.bluezqt 1.0 as BluezQt
import "providers"
PlasmaCore.IconItem { PlasmaCore.IconItem {
id: connectionIcon id: connectionIcon
required property BluetoothProvider provider
property bool deviceConnected : false source: provider.icon;
source: deviceConnected ? "preferences-system-bluetooth-activated" : "preferences-system-bluetooth";
colorGroup: PlasmaCore.ColorScope.colorGroup colorGroup: PlasmaCore.ColorScope.colorGroup
visible: BluezQt.Manager.bluetoothOperational visible: provider.isVisible
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: height Layout.preferredWidth: height
function updateStatus()
{
var connectedDevices = [];
for (var i = 0; i < BluezQt.Manager.devices.length; ++i) {
var device = BluezQt.Manager.devices[i];
if (device.connected) {
connectedDevices.push(device);
}
}
deviceConnected = connectedDevices.length > 0;
}
Component.onCompleted: {
BluezQt.Manager.deviceAdded.connect(updateStatus);
BluezQt.Manager.deviceRemoved.connect(updateStatus);
BluezQt.Manager.deviceChanged.connect(updateStatus);
BluezQt.Manager.bluetoothBlockedChanged.connect(updateStatus);
BluezQt.Manager.bluetoothOperationalChanged.connect(updateStatus);
updateStatus();
}
} }

View file

@ -1,4 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
* SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org> * SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
* *
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
@ -7,34 +8,19 @@
import QtQuick 2.1 import QtQuick 2.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import MeeGo.QOfono 0.2
import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 2.0 as PlasmaComponents
import "providers"
Item { Item {
// we can't use SignalStrengthProvider as the var type as it would import ofono (which may cause it to break if ofono is not installed)
required property QtObject provider
width: strengthIcon.height + strengthLabel.width width: strengthIcon.height + strengthLabel.width
Layout.minimumWidth: strengthIcon.height + strengthLabel.width Layout.minimumWidth: strengthIcon.height + strengthLabel.width
OfonoManager {
id: ofonoManager
}
OfonoNetworkRegistration {
id: netreg
Component.onCompleted: {
netreg.scan()
}
modemPath: ofonoManager.modems.length ? ofonoManager.modems[0] : ""
}
OfonoSimManager {
id: simManager
modemPath: ofonoManager.modems.length ? ofonoManager.modems[0] : ""
}
PlasmaCore.IconItem { PlasmaCore.IconItem {
id: strengthIcon id: strengthIcon
colorGroup: PlasmaCore.ColorScope.colorGroup colorGroup: PlasmaCore.ColorScope.colorGroup
@ -43,12 +29,7 @@ Item {
width: height width: height
height: parent.height height: parent.height
source: netreg.strength == 100 ? "network-mobile-100" source: provider.icon
: netreg.strength >= 80 ? "network-mobile-80"
: netreg.strength >= 60 ? "network-mobile-60"
: netreg.strength >= 40 ? "network-mobile-40"
: netreg.strength >= 20 ? "network-mobile-20"
: "network-mobile-0"
} }
PlasmaComponents.Label { PlasmaComponents.Label {
@ -56,7 +37,7 @@ Item {
anchors.left: strengthIcon.right anchors.left: strengthIcon.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: simManager.pinRequired !== OfonoSimManager.NoPin ? i18n("Sim locked") : netreg.name text: provider.label
color: PlasmaCore.ColorScope.textColor color: PlasmaCore.ColorScope.textColor
font.pixelSize: parent.height / 2 font.pixelSize: parent.height / 2
} }

View file

@ -1,4 +1,5 @@
/* /*
SPDX-FileCopyrightText: 2021 Devin Lin <eespidev@gmail.com>
SPDX-FileCopyrightText: 2019 Aditya Mehra <Aix.m@outlook.com> SPDX-FileCopyrightText: 2019 Aditya Mehra <Aix.m@outlook.com>
SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org> SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org>
@ -11,152 +12,17 @@ import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.private.volume 0.1 import org.kde.plasma.private.volume 0.1
PlasmaCore.IconItem { import "providers"
PlasmaCore.IconItem {
id: paIcon id: paIcon
required property VolumeProvider provider
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: height Layout.preferredWidth: height
property bool volumeFeedback: true source: provider.icon
property int maxVolumeValue: Math.round(100 * PulseAudio.NormalVolume / 100.0)
property int volumeStep: Math.round(5 * PulseAudio.NormalVolume / 100.0)
readonly property string dummyOutputName: "auto_null"
source: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)
? iconName(paSinkModel.preferredSink.volume, paSinkModel.preferredSink.muted)
: iconName(0, true)
colorGroup: PlasmaCore.ColorScope.colorGroup colorGroup: PlasmaCore.ColorScope.colorGroup
visible: paSinkModel.preferredSink && paSinkModel.preferredSink.muted visible: provider.isVisible
function iconName(volume, muted, prefix) {
if (!prefix) {
prefix = "audio-volume";
}
var icon = null;
var percent = volume / maxVolumeValue;
if (percent <= 0.0 || muted) {
icon = prefix + "-muted";
} else if (percent <= 0.25) {
icon = prefix + "-low";
} else if (percent <= 0.75) {
icon = prefix + "-medium";
} else {
icon = prefix + "-high";
}
return icon;
}
function isDummyOutput(output) {
return output && output.name === dummyOutputName;
}
function boundVolume(volume) {
return Math.max(PulseAudio.MinimalVolume, Math.min(volume, maxVolumeValue));
}
function volumePercent(volume, max){
if(!max) {
max = PulseAudio.NormalVolume;
}
return Math.round(volume / max * 100.0);
}
function playFeedback(sinkIndex) {
if(!volumeFeedback){
return;
}
if(sinkIndex == undefined) {
sinkIndex = paSinkModel.preferredSink.index;
}
feedback.play(sinkIndex)
}
function increaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume + volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
osd.show(percent);
playFeedback();
}
function decreaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume - volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
osd.show(percent);
playFeedback();
}
function muteVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var toMute = !paSinkModel.preferredSink.muted;
paSinkModel.preferredSink.muted = toMute;
osd.show(toMute ? 0 : volumePercent(paSinkModel.preferredSink.volume, maxVolumeValue));
if (!toMute) {
playFeedback();
}
}
SinkModel {
id: paSinkModel
}
VolumeOSD {
id: osd
}
VolumeFeedback {
id: feedback
}
GlobalActionCollection {
// KGlobalAccel cannot transition from kmix to something else, so if
// the user had a custom shortcut set for kmix those would get lost.
// To avoid this we hijack kmix name and actions. Entirely mental but
// best we can do to not cause annoyance for the user.
// The display name actually is updated to whatever registered last
// though, so as far as user visible strings go we should be fine.
// As of 2015-07-21:
// componentName: kmix
// actions: increase_volume, decrease_volume, mute
name: "kmix"
displayName: i18n("Audio")
GlobalAction {
objectName: "increase_volume"
text: i18n("Increase Volume")
shortcut: Qt.Key_VolumeUp
onTriggered: increaseVolume()
}
GlobalAction {
objectName: "decrease_volume"
text: i18n("Decrease Volume")
shortcut: Qt.Key_VolumeDown
onTriggered: decreaseVolume()
}
GlobalAction {
objectName: "mute"
text: i18n("Mute")
shortcut: Qt.Key_VolumeMute
onTriggered: muteVolume()
}
}
} }

View file

@ -1,4 +1,5 @@
/* /*
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org> SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com> SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
@ -11,10 +12,13 @@ import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
import "providers"
PlasmaCore.IconItem { PlasmaCore.IconItem {
id: connectionIcon id: connectionIcon
required property WifiProvider provider
source: connectionIconProvider.connectionIcon source: provider.icon
colorGroup: PlasmaCore.ColorScope.colorGroup colorGroup: PlasmaCore.ColorScope.colorGroup
Layout.fillHeight: true Layout.fillHeight: true
@ -24,23 +28,7 @@ PlasmaCore.IconItem {
id: connectingIndicator id: connectingIndicator
anchors.fill: parent anchors.fill: parent
running: connectionIconProvider.connecting running: provider.indicatorRunning
visible: running visible: running
} }
PlasmaNM.NetworkStatus {
id: networkStatus
}
PlasmaNM.NetworkModel {
id: connectionModel
}
PlasmaNM.Handler {
id: handler
}
PlasmaNM.ConnectionIcon {
id: connectionIconProvider
}
} }

View file

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
* SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.6
import QtQuick.Layouts 1.4
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.workspace.components 2.0 as PW
Item {
property bool isVisible: pmSource.data["Battery"]["Has Cumulative"]
property int percent: pmSource.data["Battery"]["Percent"]
property bool pluggedIn: pmSource.data["AC Adapter"] ? pmSource.data["AC Adapter"]["Plugged in"] : false
property PlasmaCore.DataSource pmSource: PlasmaCore.DataSource {
engine: "powermanagement"
connectedSources: ["Battery", "AC Adapter"]
}
}

View file

@ -0,0 +1,43 @@
/*
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
import QtQuick 2.2
import QtQuick.Layouts 1.4
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.bluezqt 1.0 as BluezQt
QtObject {
property bool isVisible: BluezQt.Manager.bluetoothOperational
property string icon: deviceConnected ? "preferences-system-bluetooth-activated" : "preferences-system-bluetooth"
property bool deviceConnected : false
function updateStatus() {
var connectedDevices = [];
for (var i = 0; i < BluezQt.Manager.devices.length; ++i) {
var device = BluezQt.Manager.devices[i];
if (device.connected) {
connectedDevices.push(device);
}
}
deviceConnected = connectedDevices.length > 0;
}
Component.onCompleted: {
BluezQt.Manager.deviceAdded.connect(updateStatus);
BluezQt.Manager.deviceRemoved.connect(updateStatus);
BluezQt.Manager.deviceChanged.connect(updateStatus);
BluezQt.Manager.bluetoothBlockedChanged.connect(updateStatus);
BluezQt.Manager.bluetoothOperationalChanged.connect(updateStatus);
updateStatus();
}
}

View file

@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
* SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.1
import QtQuick.Layouts 1.1
import MeeGo.QOfono 0.2
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
QtObject {
property string icon: netreg.strength == 100 ? "network-mobile-100"
: netreg.strength >= 80 ? "network-mobile-80"
: netreg.strength >= 60 ? "network-mobile-60"
: netreg.strength >= 40 ? "network-mobile-40"
: netreg.strength >= 20 ? "network-mobile-20"
: "network-mobile-0"
property string label: simManager.pinRequired !== OfonoSimManager.NoPin ? i18n("Sim locked") : netreg.name
property OfonoManager ofonoManager: OfonoManager {}
property OfonoNetworkRegistration netreg: OfonoNetworkRegistration {
Component.onCompleted: {
netreg.scan()
}
modemPath: ofonoManager.modems.length ? ofonoManager.modems[0] : ""
}
property OfonoSimManager simManager: OfonoSimManager {
modemPath: ofonoManager.modems.length ? ofonoManager.modems[0] : ""
}
}

View file

@ -0,0 +1,151 @@
/*
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
SPDX-FileCopyrightText: 2019 Aditya Mehra <Aix.m@outlook.com>
SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
import QtQuick 2.2
import QtQuick.Layouts 1.4
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.private.volume 0.1
QtObject {
property bool isVisible: paSinkModel.preferredSink && paSinkModel.preferredSink.muted
property string icon: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)
? iconName(paSinkModel.preferredSink.volume, paSinkModel.preferredSink.muted)
: iconName(0, true)
property bool volumeFeedback: true
property int maxVolumeValue: Math.round(100 * PulseAudio.NormalVolume / 100.0)
property int volumeStep: Math.round(5 * PulseAudio.NormalVolume / 100.0)
readonly property string dummyOutputName: "auto_null"
function iconName(volume, muted, prefix) {
if (!prefix) {
prefix = "audio-volume";
}
var icon = null;
var percent = volume / maxVolumeValue;
if (percent <= 0.0 || muted) {
icon = prefix + "-muted";
} else if (percent <= 0.25) {
icon = prefix + "-low";
} else if (percent <= 0.75) {
icon = prefix + "-medium";
} else {
icon = prefix + "-high";
}
return icon;
}
function isDummyOutput(output) {
return output && output.name === dummyOutputName;
}
function boundVolume(volume) {
return Math.max(PulseAudio.MinimalVolume, Math.min(volume, maxVolumeValue));
}
function volumePercent(volume, max){
if(!max) {
max = PulseAudio.NormalVolume;
}
return Math.round(volume / max * 100.0);
}
function playFeedback(sinkIndex) {
if(!volumeFeedback){
return;
}
if(sinkIndex == undefined) {
sinkIndex = paSinkModel.preferredSink.index;
}
feedback.play(sinkIndex)
}
function increaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume + volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
osd.show(percent);
playFeedback();
}
function decreaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume - volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
osd.show(percent);
playFeedback();
}
function muteVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var toMute = !paSinkModel.preferredSink.muted;
paSinkModel.preferredSink.muted = toMute;
osd.show(toMute ? 0 : volumePercent(paSinkModel.preferredSink.volume, maxVolumeValue));
if (!toMute) {
playFeedback();
}
}
property SinkModel paSinkModel: SinkModel {}
property VolumeOSD osd: VolumeOSD {}
property VolumeFeedback feedback: VolumeFeedback {}
property GlobalActionCollection actionCollection: GlobalActionCollection {
// KGlobalAccel cannot transition from kmix to something else, so if
// the user had a custom shortcut set for kmix those would get lost.
// To avoid this we hijack kmix name and actions. Entirely mental but
// best we can do to not cause annoyance for the user.
// The display name actually is updated to whatever registered last
// though, so as far as user visible strings go we should be fine.
// As of 2015-07-21:
// componentName: kmix
// actions: increase_volume, decrease_volume, mute
name: "kmix"
displayName: i18n("Audio")
GlobalAction {
objectName: "increase_volume"
text: i18n("Increase Volume")
shortcut: Qt.Key_VolumeUp
onTriggered: increaseVolume()
}
GlobalAction {
objectName: "decrease_volume"
text: i18n("Decrease Volume")
shortcut: Qt.Key_VolumeDown
onTriggered: decreaseVolume()
}
GlobalAction {
objectName: "mute"
text: i18n("Mute")
shortcut: Qt.Key_VolumeMute
onTriggered: muteVolume()
}
}
}

View file

@ -0,0 +1,36 @@
/*
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
import QtQuick 2.2
import QtQuick.Layouts 1.4
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
Item {
visible: false
property string icon: connectionIconProvider.connectionIcon
property bool indicatorRunning: connectionIconProvider.connecting
PlasmaNM.NetworkStatus {
id: networkStatus
}
PlasmaNM.NetworkModel {
id: connectionModel
}
PlasmaNM.Handler {
id: handler
}
PlasmaNM.ConnectionIcon {
id: connectionIconProvider
}
}

View file

@ -1,4 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
* SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org> * SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
* *
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
@ -9,6 +10,8 @@ import QtQuick.Layouts 1.3
import QtQml.Models 2.12 import QtQml.Models 2.12
import QtGraphicalEffects 1.12 import QtGraphicalEffects 1.12
import org.kde.kirigami 2.12 as Kirigami
import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
@ -23,7 +26,7 @@ import "LayoutManager.js" as LayoutManager
import "quicksettings" import "quicksettings"
import "indicators" as Indicators import "indicators" as Indicators
import "indicators/providers" as IndicatorProviders
Item { Item {
id: root id: root
@ -37,7 +40,7 @@ Item {
property bool reorderingApps: false property bool reorderingApps: false
property var layoutManager: LayoutManager property var layoutManager: LayoutManager
readonly property color backgroundColor: NanoShell.StartupFeedback.visible ? NanoShell.StartupFeedback.backgroundColor : icons.backgroundColor readonly property color backgroundColor: NanoShell.StartupFeedback.visible ? NanoShell.StartupFeedback.backgroundColor : topPanel.colorScopeColor
readonly property bool showingApp: !MobileShell.HomeScreenControls.homeScreenVisible readonly property bool showingApp: !MobileShell.HomeScreenControls.homeScreenVisible
readonly property bool hasTasks: tasksModel.count > 0 readonly property bool hasTasks: tasksModel.count > 0
@ -48,7 +51,7 @@ Item {
} }
function addApplet(applet, x, y) { function addApplet(applet, x, y) {
var compactContainer = compactContainerComponent.createObject(appletIconsRow) var compactContainer = compactContainerComponent.createObject(topPanel.applets)
print("Applet added: " + applet + " " + applet.title) print("Applet added: " + applet + " " + applet.title)
applet.parent = compactContainer; applet.parent = compactContainer;
@ -115,138 +118,59 @@ Item {
property Item applet property Item applet
visible: applet && (applet.status != PlasmaCore.Types.HiddenStatus && applet.status != PlasmaCore.Types.PassiveStatus) visible: applet && (applet.status != PlasmaCore.Types.HiddenStatus && applet.status != PlasmaCore.Types.PassiveStatus)
Layout.fillHeight: true Layout.fillHeight: true
Layout.minimumWidth: applet && applet.compactRepresentationItem ? Math.max(applet.compactRepresentationItem.Layout.minimumWidth, appletIconsRow.height) : appletIconsRow.height Layout.minimumWidth: applet && applet.compactRepresentationItem ? Math.max(applet.compactRepresentationItem.Layout.minimumWidth, topPanel.applets.height) : topPanel.applets.height
Layout.maximumWidth: Layout.minimumWidth Layout.maximumWidth: Layout.minimumWidth
} }
} }
Component { Component {
id: fullContainerComponent id: fullContainerComponent
FullContainer { FullContainer {}
}
} }
Component { Component {
id: fullNotificationsContainerComponent id: fullNotificationsContainerComponent
FullNotificationsContainer { FullNotificationsContainer {}
}
} }
PlasmaCore.DataSource { // indicator providers
id: timeSource IndicatorProviders.BatteryProvider {
engine: "time" id: batteryProvider
connectedSources: ["Local"] }
interval: 60 * 1000 IndicatorProviders.BluetoothProvider {
id: bluetoothProvider
}
property alias signalStrengthProvider: signalStrengthProviderLoader.item
Loader {
id: signalStrengthProviderLoader
source: Qt.resolvedUrl("indicators/providers/SignalStrengthProvider.qml")
}
IndicatorProviders.VolumeProvider {
id: volumeProvider
}
IndicatorProviders.WifiProvider {
id: wifiProvider
} }
DropShadow { // top panel component
anchors.fill: icons IndicatorsRow {
visible: !showingApp id: topPanel
cached: true anchors.fill: parent
horizontalOffset: 0
verticalOffset: 1
radius: 4.0
samples: 17
color: Qt.rgba(0,0,0,0.8)
source: icons
}
// screen top panel
PlasmaCore.ColorScope {
id: icons
z: 1 z: 1
colorGroup: showingApp ? PlasmaCore.Theme.HeaderColorGroup : PlasmaCore.Theme.ComplementaryColorGroup colorGroup: showingApp ? PlasmaCore.Theme.HeaderColorGroup : PlasmaCore.Theme.ComplementaryColorGroup
//parent: slidingPanel.visible && !slidingPanel.wideScreen ? panelContents : root backgroundColor: !showingApp ? "transparent" : root.backgroundColor
anchors { showGradientBackground: !showingApp
left: parent.left showDropShadow: !showingApp
right: parent.right
bottom: parent.bottom
} }
height: root.height
// top panel background (background for the rest of the screen in SlidingPanel.qml)
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
gradient: Gradient { color: PlasmaCore.Theme.backgroundColor
GradientStop {
position: 1.0
color: showingApp ? root.backgroundColor : "transparent"
}
GradientStop {
position: 0.0
color: showingApp ? root.backgroundColor : Qt.rgba(0, 0, 0, 0.1)
}
}
}
Loader {
id: strengthLoader
height: parent.height
width: item ? item.width : 0
source: Qt.resolvedUrl("indicators/SignalStrength.qml")
}
Row {
id: sniRow
anchors.left: strengthLoader.right
height: parent.height
Repeater {
id: statusNotifierRepeater
model: PlasmaCore.SortFilterModel {
id: filteredStatusNotifiers
filterRole: "Title"
sourceModel: PlasmaCore.DataModel {
dataSource: statusNotifierSource
}
}
delegate: TaskWidget {
}
}
}
PlasmaComponents.Label {
id: clock
property bool is24HourTime: plasmoid.nativeInterface.isSystem24HourFormat
anchors.fill: parent
text: Qt.formatTime(timeSource.data.Local.DateTime, is24HourTime ? "h:mm" : "h:mm ap")
color: PlasmaCore.ColorScope.textColor
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
font.pixelSize: height / 2
}
RowLayout {
id: appletIconsRow
anchors {
bottom: parent.bottom
right: simpleIndicatorsLayout.left
}
height: parent.height
}
//TODO: pluggable
RowLayout {
id: simpleIndicatorsLayout
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
rightMargin: units.smallSpacing
}
Indicators.Bluetooth {}
Indicators.Wifi {}
Indicators.Volume {}
Indicators.Battery {}
}
}
// screen top panel background (background for the rest of the screen in SlidingPanel.qml)
Rectangle {
anchors.fill: parent
color: "black"
opacity: 0.6 * Math.min(1, slidingPanel.offset/panelContents.height) opacity: 0.6 * Math.min(1, slidingPanel.offset/panelContents.height)
} }
// initial swipe down
MouseArea { MouseArea {
z: 99 z: 99
property int oldMouseY: 0 property int oldMouseY: 0
@ -256,13 +180,12 @@ Item {
slidingPanel.cancelAnimations(); slidingPanel.cancelAnimations();
slidingPanel.drawerX = Math.min(Math.max(0, mouse.x - slidingPanel.drawerWidth/2), slidingPanel.width - slidingPanel.contentItem.width) slidingPanel.drawerX = Math.min(Math.max(0, mouse.x - slidingPanel.drawerWidth/2), slidingPanel.width - slidingPanel.contentItem.width)
slidingPanel.userInteracting = true; slidingPanel.userInteracting = true;
slidingPanel.flickable.contentY = slidingPanel.closedContentY;
oldMouseY = mouse.y; oldMouseY = mouse.y;
slidingPanel.offset = 0//units.gridUnit * 2;
slidingPanel.showFullScreen(); slidingPanel.showFullScreen();
} }
onPositionChanged: { onPositionChanged: {
slidingPanel.offset = Math.min(slidingPanel.contentItem.height, slidingPanel.offset + (mouse.y - oldMouseY)); slidingPanel.updateOffset(mouse.y - oldMouseY);
oldMouseY = mouse.y; oldMouseY = mouse.y;
} }
onReleased: { onReleased: {
@ -275,61 +198,65 @@ Item {
} }
} }
SlidingPanel { // sliding component
SlidingContainer {
id: slidingPanel id: slidingPanel
width: plasmoid.availableScreenRect.width width: plasmoid.availableScreenRect.width
height: plasmoid.availableScreenRect.height height: plasmoid.availableScreenRect.height
openThreshold: units.gridUnit * 2 topPanelHeight: topPanel.height
headerHeight: root.height
topEmptyAreaHeight: quickSettings.topEmptyAreaHeight topEmptyAreaHeight: quickSettings.topEmptyAreaHeight
collapsedHeight: quickSettings.collapsedHeight
fullyOpenHeight: quickSettings.implicitHeight
appletsShown: fullRepresentationView.count > 0
offset: quickSettings.height offset: quickSettings.height
onClosed: quickSettings.closed() onClosed: quickSettings.closed()
contentItem: Item { contentItem: MouseArea {
implicitWidth: panelContents.implicitWidth // mousearea captures touch presses so that the flickable picks them up for swiping
implicitWidth: slidingPanel.width
implicitHeight: Math.min(slidingPanel.height, quickSettings.implicitHeight) implicitHeight: Math.min(slidingPanel.height, quickSettings.implicitHeight)
GridLayout { GridLayout {
id: panelContents id: panelContents
anchors.fill: parent anchors.fill: parent
implicitWidth: quickSettings.implicitWidth
implicitHeight: Math.min(slidingPanel.height, quickSettings.implicitHeight)
columns: slidingPanel.wideScreen ? 2 : 1 columns: slidingPanel.wideScreen ? 2 : 1
rows: slidingPanel.wideScreen ? 1 : 2 rows: slidingPanel.wideScreen ? 1 : 2
QuickSettings { QuickSettingsPanel {
id: quickSettings id: quickSettings
property int trueHeight: height + Math.round(Kirigami.Units.gridUnit * 1.5) // add height of bottom bar
z: 4
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, units.gridUnit * 25) : panelContents.width Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, units.gridUnit * 25) : panelContents.width
z: 4
parentSlidingPanel: slidingPanel parentSlidingPanel: slidingPanel
onCloseRequested: { onCloseRequested: slidingPanel.hide()
slidingPanel.hide()
}
background: DrawerBackground {}
} }
// notifications
ListView { ListView {
id: fullRepresentationView id: fullRepresentationView
z: 1 implicitHeight: units.gridUnit * 20
interactive: width < contentWidth Layout.topMargin: slidingPanel.wideScreen ? 0 : Math.round(Kirigami.Units.gridUnit * 1.5) // add height of bottom bar
//parent: slidingPanel.wideScreen ? slidingPanel.flickable.contentItem : panelContents
Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, quickSettings.width*fullRepresentationModel.count) : panelContents.width Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, quickSettings.width*fullRepresentationModel.count) : panelContents.width
Layout.preferredHeight: Math.min(plasmoid.screenGeometry.height - quickSettings.implicitHeight - bottomBar.height + slidingPanel.topEmptyAreaHeight, implicitHeight)
z: 1
interactive: count > 0 && width < contentWidth
//Layout.fillWidth: true
clip: slidingPanel.wideScreen clip: slidingPanel.wideScreen
y: slidingPanel.wideScreen ? 0 : quickSettings.height - (quickSettings.height + height) * (1-opacity) y: slidingPanel.wideScreen ? 0 : quickSettings.trueHeight
opacity: slidingPanel.wideScreen ? 1 : fullRepresentationModel.count > 0 && (slidingPanel.offset + slidingPanel.headerHeight)/(quickSettings.height -slidingPanel.topEmptyAreaHeight) opacity: {
Layout.preferredHeight: Math.min(plasmoid.screenGeometry.height - slidingPanel.headerHeight - quickSettings.height - bottomBar.height + slidingPanel.topEmptyAreaHeight, implicitHeight) if (slidingPanel.wideScreen) {
//leftMargin: slidingPanel.drawerX return 1;
} else {
return fullRepresentationModel.count > 0 && slidingPanel.offset / slidingPanel.collapsedHeight;
}
}
preferredHighlightBegin: slidingPanel.drawerX preferredHighlightBegin: slidingPanel.drawerX
implicitHeight: units.gridUnit * 20
cacheBuffer: width * 100 cacheBuffer: width * 100
highlightFollowsCurrentItem: true highlightFollowsCurrentItem: true
highlightRangeMode: ListView.StrictlyEnforceRange highlightRangeMode: ListView.StrictlyEnforceRange
@ -346,10 +273,6 @@ Item {
z: -1 z: -1
onClicked: slidingPanel.close() onClicked: slidingPanel.close()
} }
//implicitHeight: fullRepresentationLayout.implicitHeight
//clip: true
} }
} }
} }
@ -360,11 +283,11 @@ Item {
right: parent.right right: parent.right
bottom: parent.bottom bottom: parent.bottom
} }
backgroundColor: Kirigami.ColorUtils.adjustColor(PlasmaCore.Theme.backgroundColor, {"alpha": 0.8*255})
parent: slidingPanel.fixedArea parent: slidingPanel.fixedArea
opacity: fullRepresentationView.opacity opacity: fullRepresentationView.opacity
visible: !slidingPanel.wideScreen && fullRepresentationModel.count > 1 visible: !slidingPanel.wideScreen && fullRepresentationModel.count > 1
//height: 40
z: 100 z: 100
contentItem: RowLayout { contentItem: RowLayout {
PlasmaComponents.TabBar { PlasmaComponents.TabBar {

View file

@ -9,23 +9,68 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import org.kde.kirigami 2.12 as Kirigami
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
RowLayout { Item {
id: brightnessRoot id: brightnessRoot
property alias value: brightnessSlider.value
property alias maximumValue: brightnessSlider.to
signal moved implicitHeight: brightnessRow.implicitHeight
spacing: units.smallSpacing property int screenBrightness
property bool disableBrightnessUpdate: true
readonly property int maximumScreenBrightness: pmSource.data["PowerDevil"] ? pmSource.data["PowerDevil"]["Maximum Screen Brightness"] || 0 : 0
PlasmaCore.IconItem { onScreenBrightnessChanged: {
brightnessSlider.value = brightnessRoot.screenBrightness
if (!disableBrightnessUpdate) {
var service = pmSource.serviceForSource("PowerDevil");
var operation = service.operationDescription("setBrightness");
operation.brightness = screenBrightness;
operation.silent = true
service.startOperationCall(operation);
}
}
PlasmaCore.DataSource {
id: pmSource
engine: "powermanagement"
connectedSources: ["PowerDevil"]
onSourceAdded: {
if (source === "PowerDevil") {
disconnectSource(source);
connectSource(source);
}
}
onDataChanged: {
disableBrightnessUpdate = true;
brightnessRoot.screenBrightness = pmSource.data["PowerDevil"]["Screen Brightness"];
disableBrightnessUpdate = false;
}
}
Component.onCompleted: {
brightnessSlider.moved.connect(function() {
brightnessRoot.screenBrightness = brightnessSlider.value;
});
disableBrightnessUpdate = false;
}
RowLayout {
id: brightnessRow
spacing: PlasmaCore.Units.smallSpacing * 2
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
Kirigami.Icon {
color: PlasmaCore.Theme.textColor
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: Kirigami.Units.largeSpacing Layout.leftMargin: PlasmaCore.Units.smallSpacing
Layout.preferredWidth: units.iconSizes.medium Layout.preferredWidth: Math.round(PlasmaCore.Units.gridUnit * 1.75)
Layout.preferredHeight: width Layout.preferredHeight: width
source: "low-brightness" source: "low-brightness"
} }
@ -34,15 +79,19 @@ RowLayout {
id: brightnessSlider id: brightnessSlider
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onMoved: brightnessRoot.moved() value: screenBrightness
from: 1 from: 1
to: maximumScreenBrightness
} }
PlasmaCore.IconItem { Kirigami.Icon {
color: PlasmaCore.Theme.textColor
isMask: true
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Kirigami.Units.largeSpacing Layout.rightMargin: PlasmaCore.Units.smallSpacing
Layout.preferredWidth: units.iconSizes.medium Layout.preferredWidth: Math.round(PlasmaCore.Units.gridUnit * 1.75)
Layout.preferredHeight: width Layout.preferredHeight: width
source: "high-brightness" source: "high-brightness"
} }
}
} }

View file

@ -1,5 +1,6 @@
/* /*
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com> * SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
* *
* SPDX-License-Identifier: LGPL-2.0-or-later * SPDX-License-Identifier: LGPL-2.0-or-later
*/ */
@ -14,6 +15,9 @@ import org.kde.plasma.private.nanoshell 2.0 as NanoShell
ColumnLayout { ColumnLayout {
id: delegateRoot id: delegateRoot
spacing: units.smallSpacing spacing: units.smallSpacing
required property var settingsModel
signal closeRequested signal closeRequested
signal panelClosed signal panelClosed
@ -25,34 +29,36 @@ ColumnLayout {
required property var toggleFunction required property var toggleFunction
property alias labelOpacity: label.opacity property alias labelOpacity: label.opacity
property color disabledButtonColor: PlasmaCore.Theme.backgroundColor
property color disabledPressedButtonColor: Qt.darker(disabledButtonColor, 1.1)
property color enabledButtonColor: Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.highlightColor, {"alpha": 0.4*255})
property color enabledPressedButtonColor: Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.highlightColor, {"alpha": 0.6*255});
Rectangle { Rectangle {
Layout.preferredWidth: units.iconSizes.large + units.smallSpacing Layout.preferredWidth: PlasmaCore.Units.iconSizes.large + PlasmaCore.Units.smallSpacing
Layout.minimumHeight: width Layout.minimumHeight: width
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
radius: units.smallSpacing radius: PlasmaCore.Units.smallSpacing
border.color: delegateRoot.enabled ? border.color: delegateRoot.enabled ?
Qt.darker(Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.highlightColor, {}), 1.25) : Qt.darker(Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.highlightColor, {}), 1.25) :
Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.textColor, {"alpha": 0.2*255}) Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.textColor, {"alpha": 0.2*255})
color: { color: {
if (delegateRoot.enabled) { if (delegateRoot.enabled) {
return Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.highlightColor, {"alpha": iconMouseArea.pressed ? 0.5*255 : 0.3*255}); return iconMouseArea.pressed ? enabledPressedButtonColor : enabledButtonColor
} else { } else {
if (iconMouseArea.pressed) { return iconMouseArea.pressed ? disabledPressedButtonColor : disabledButtonColor
return Qt.darker(Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.backgroundColor, {"alpha": 0.9*255}), 1.25);
} else {
return Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.backgroundColor, {"alpha": 0.3*255});
}
} }
} }
PlasmaCore.IconItem { Kirigami.Icon {
id: icon id: icon
colorGroup: PlasmaCore.ColorScope.colorGroup color: PlasmaCore.Theme.textColor
anchors { anchors.centerIn: parent
fill: parent implicitWidth: Math.round(parent.width * 0.6)
margins: units.smallSpacing implicitHeight: width
}
source: delegateRoot.icon source: delegateRoot.icon
}
MouseArea { MouseArea {
id: iconMouseArea id: iconMouseArea
anchors.fill: parent anchors.fill: parent
@ -60,7 +66,7 @@ ColumnLayout {
if (delegateRoot.toggle) { if (delegateRoot.toggle) {
delegateRoot.toggle(); delegateRoot.toggle();
} else if (delegateRoot.toggleFunction) { } else if (delegateRoot.toggleFunction) {
root[delegateRoot.toggleFunction](); settingsModel[delegateRoot.toggleFunction]();
} else if (delegateRoot.settingsCommand) { } else if (delegateRoot.settingsCommand) {
NanoShell.StartupFeedback.open( NanoShell.StartupFeedback.open(
delegateRoot.icon, delegateRoot.icon,
@ -88,7 +94,6 @@ ColumnLayout {
} }
} }
} }
}
PlasmaComponents.Label { PlasmaComponents.Label {
id: label id: label
@ -131,7 +136,7 @@ ColumnLayout {
plasmoid.nativeInterface.executeCommand(delegateRoot.settingsCommand); plasmoid.nativeInterface.executeCommand(delegateRoot.settingsCommand);
closeRequested(); closeRequested();
} else if (delegateRoot.toggleFunction) { } else if (delegateRoot.toggleFunction) {
root[delegateRoot.toggleFunction](); settingsModel[delegateRoot.toggleFunction]();
} }
} }
} }

View file

@ -1,385 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.14
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
import org.kde.bluezqt 1.0 as BluezQt
import org.kde.colorcorrect 0.1 as CC
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.components 3.0 as PC3
Item {
id: root
implicitWidth: column.implicitWidth + units.smallSpacing * 6
implicitHeight: column.implicitHeight + units.smallSpacing * 2
signal closeRequested
signal closed
property bool expandedMode: parentSlidingPanel.wideScreen
readonly property real expandedRatio: expandedMode ? 1 : Math.max(0, Math.min(1, (parentSlidingPanel.offset - firstRowHeight - parentSlidingPanel.headerHeight) / otherRowsHeight))
readonly property real topEmptyAreaHeight: parentSlidingPanel.userInteracting
? (root.height - collapsedHeight) * (1 - expandedRatio)
: (expandedMode ? 0 : root.height - collapsedHeight)
readonly property real collapsedHeight: firstRowHeight + PlasmaCore.Units.smallSpacing * 2
readonly property real firstRowHeight: flow.children[0].height
readonly property real otherRowsHeight: column.height - firstRowHeight
Connections {
target: root.parentSlidingPanel
function onUserInteractingChanged() {
if (!parentSlidingPanel.userInteracting) {
if (root.expandedRatio > 0.7) {
root.expandedMode = true;
}
}
}
}
property bool screenshotRequested: false
property NanoShell.FullScreenOverlay parentSlidingPanel
property Item background
onBackgroundChanged: {
background.parent = backgroundParent
background.anchors.fill = backgroundParent
}
PlasmaNM.Handler {
id: nmHandler
}
PlasmaNM.EnabledConnections {
id: enabledConnections
}
Connections {
target: root.Window.window
function onVisibilityChanged() {
root.expandedMode = parentSlidingPanel.wideScreen;
}
}
Connections {
target: BluezQt.Manager
function onBluetoothOperationalChanged() {
settingsModel.get(2).enabled = BluezQt.Manager.bluetoothOperational
}
}
function toggleAirplane() {
print("toggle airplane mode")
}
function toggleTorch() {
plasmoid.nativeInterface.toggleTorch()
settingsModel.get(6).enabled = plasmoid.nativeInterface.torchEnabled
}
function toggleWifi() {
nmHandler.enableWireless(!enabledConnections.wirelessEnabled)
settingsModel.get(1).enabled = !enabledConnections.wirelessEnabled
}
function toggleWwan() {
nmHandler.enableWwan(!enabledConnections.wwanEnabled)
settingsModel.get(3).enabled = !enabledConnections.wwanEnabled
}
function toggleRotation() {
const enable = !plasmoid.nativeInterface.autoRotateEnabled
plasmoid.nativeInterface.autoRotateEnabled = enable
settingsModel.get(9).enabled = enable
}
function toggleBluetooth() {
var enable = !BluezQt.Manager.bluetoothOperational;
BluezQt.Manager.bluetoothBlocked = !enable;
for (var i = 0; i < BluezQt.Manager.adapters.length; ++i) {
var adapter = BluezQt.Manager.adapters[i];
adapter.powered = enable;
}
}
function toggleNightColor() {
if (compositorAdaptor.active) {
compositorAdaptor.activeStaged = false;
} else {
compositorAdaptor.activeStaged = true;
compositorAdaptor.modeStaged = 3; // always on
}
compositorAdaptor.sendConfigurationAll();
settingsModel.get(10).enabled = compositorAdaptor.active;
}
function requestShutdown() {
print("Shutdown requested, depends on ksmserver running");
var service = pmSource.serviceForSource("PowerDevil");
//note the strange camelCasing is intentional
var operation = service.operationDescription("requestShutDown");
return service.startOperationCall(operation);
}
signal plasmoidTriggered(var applet, var id)
Layout.minimumHeight: flow.implicitHeight + units.largeSpacing*2
property int screenBrightness
property bool disableBrightnessUpdate: true
readonly property int maximumScreenBrightness: pmSource.data["PowerDevil"] ? pmSource.data["PowerDevil"]["Maximum Screen Brightness"] || 0 : 0
onScreenBrightnessChanged: {
if(!disableBrightnessUpdate) {
var service = pmSource.serviceForSource("PowerDevil");
var operation = service.operationDescription("setBrightness");
operation.brightness = screenBrightness;
operation.silent = true
service.startOperationCall(operation);
}
}
function requestScreenshot() {
screenshotRequested = true;
root.closeRequested();
}
onClosed: {
if (screenshotRequested) {
plasmoid.nativeInterface.takeScreenshot();
screenshotRequested = false;
}
}
PlasmaCore.DataSource {
id: pmSource
engine: "powermanagement"
connectedSources: ["PowerDevil"]
onSourceAdded: {
if (source === "PowerDevil") {
disconnectSource(source);
connectSource(source);
}
}
onDataChanged: {
disableBrightnessUpdate = true;
root.screenBrightness = pmSource.data["PowerDevil"]["Screen Brightness"];
disableBrightnessUpdate = false;
}
}
// night color
CC.CompositorAdaptor {
id: compositorAdaptor
}
//HACK: make the list know about the applet delegate which is a qtobject
QtObject {
id: nullApplet
}
Component.onCompleted: {
//NOTE: add all in javascript as the static decl of listelements can't have scripts
settingsModel.append({
"text": i18n("Settings"),
"icon": "configure",
"enabled": false,
"settingsCommand": "plasma-settings",
"toggleFunction": "",
"applet": null
});
settingsModel.append({
"text": i18n("Wifi"),
"icon": "network-wireless-signal",
"settingsCommand": "plasma-settings -m kcm_mobile_wifi",
"toggleFunction": "toggleWifi",
"enabled": enabledConnections.wirelessEnabled,
"applet": null
});
settingsModel.append({
"text": i18n("Bluetooth"),
"icon": "network-bluetooth",
"settingsCommand": "plasma-settings -m kcm_bluetooth",
"toggleFunction": "toggleBluetooth",
"delegate": "",
"enabled": BluezQt.Manager.bluetoothOperational,
"applet": null
});
settingsModel.append({
"text": i18n("Mobile Data"),
"icon": "network-modem",
"settingsCommand": "plasma-settings -m kcm_mobile_broadband",
"toggleFunction": "toggleWwan",
"enabled": enabledConnections.wwanEnabled,
"applet": null
});
settingsModel.append({
"text": i18n("Battery"),
"icon": "battery-full",
"enabled": false,
"settingsCommand": "plasma-settings -m kcm_mobile_power",
"toggleFunction": "",
"applet": null
});
settingsModel.append({
"text": i18n("Sound"),
"icon": "audio-speakers-symbolic",
"enabled": false,
"settingsCommand": "plasma-settings -m kcm_pulseaudio",
"toggleFunction": "",
"applet": null
});
settingsModel.append({
"text": i18n("Flashlight"),
"icon": "flashlight-on",
"enabled": plasmoid.nativeInterface.torchEnabled,
"settingsCommand": "",
"toggleFunction": "toggleTorch",
"applet": null
});
settingsModel.append({
"text": i18n("Location"),
"icon": "gps",
"enabled": false,
"settingsCommand": "",
"applet": null
});
settingsModel.append({
"text": i18n("Screenshot"),
"icon": "spectacle",
"enabled": false,
"settingsCommand": "",
"toggleFunction": "requestScreenshot",
"applet": null
});
settingsModel.append({
"text": i18n("Auto-rotate"),
"icon": "rotation-allowed",
"enabled": plasmoid.nativeInterface.autoRotateEnabled,
"settingsCommand": "",
"toggleFunction": "toggleRotation",
"applet": null
});
settingsModel.append({
"text": i18n("Night Color"),
"icon": "redshift-status-on",
"enabled": compositorAdaptor.active,
"settingsCommand": "", // change once night color kcm is added
"toggleFunction": "toggleNightColor",
"applet": null
});
brightnessSlider.moved.connect(function() {
root.screenBrightness = brightnessSlider.value;
});
disableBrightnessUpdate = false;
}
ListModel {
id: settingsModel
}
Item {
id: backgroundParent
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: firstRowHeight + otherRowsHeight * root.expandedRatio
}
Item {
anchors {
fill: parent
margins: units.smallSpacing
}
readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6
readonly property real columnWidth: Math.floor(width / Math.floor(width / cellSizeHint))
ColumnLayout {
id: column
anchors.fill: parent
spacing: 0
Flow {
id: flow
Layout.fillWidth: true
Layout.leftMargin: units.smallSpacing + (units.largeSpacing - units.smallSpacing) * root.expandedRatio
Layout.rightMargin: units.largeSpacing
Layout.topMargin: units.largeSpacing
readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6
readonly property real columnWidth: Math.floor(width / Math.floor(width / cellSizeHint))
spacing: 0
Repeater {
model: settingsModel
delegate: Delegate {
id: delegateItem
//FIXME: why this is needed?
width: flow.columnWidth - (y > 0 ? 0 : (flow.columnWidth/Math.floor(flow.width / flow.columnWidth)) * (1 - root.expandedRatio))
height: item ? item.implicitHeight : 0
labelOpacity: y > 0 ? 1 : root.expandedRatio
opacity: y <= 0 ? 1 : root.expandedRatio
transform: Translate {
y: otherRowsHeight * (1 - root.expandedRatio)
}
Connections {
target: delegateItem
onCloseRequested: root.closeRequested();
}
Connections {
target: root
onClosed: delegateItem.panelClosed();
}
}
}
move: Transition {
NumberAnimation {
duration: units.shortDuration
//Here a linear easing actually looks better
//easing.type: Easing.InOutQuad
properties: "x,y"
}
}
}
BrightnessItem {
id: brightnessSlider
Layout.bottomMargin: units.largeSpacing
Layout.leftMargin: units.largeSpacing
Layout.rightMargin: units.largeSpacing
Layout.fillWidth: true
value: root.screenBrightness
maximumValue: root.maximumScreenBrightness
opacity: root.expandedRatio
transform: Translate {
y: otherRowsHeight * (1 - root.expandedRatio)
}
Connections {
target: root
onScreenBrightnessChanged: brightnessSlider.value = root.screenBrightness
}
}
}
}
}

View file

@ -0,0 +1,190 @@
/*
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.14
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
import org.kde.bluezqt 1.0 as BluezQt
import org.kde.colorcorrect 0.1 as CC
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.components 3.0 as PC3
Item {
property alias model: settingsModel
property bool screenshotRequested: false
signal panelClosed()
onPanelClosed: {
if (screenshotRequested) {
plasmoid.nativeInterface.takeScreenshot();
screenshotRequested = false;
}
}
ListModel {
id: settingsModel
}
PlasmaNM.Handler {
id: nmHandler
}
PlasmaNM.EnabledConnections {
id: enabledConnections
}
// night color
CC.CompositorAdaptor {
id: compositorAdaptor
}
Connections {
target: BluezQt.Manager
function onBluetoothOperationalChanged() {
settingsModel.get(2).enabled = BluezQt.Manager.bluetoothOperational
}
}
function toggleAirplane() {
print("toggle airplane mode")
}
function toggleTorch() {
plasmoid.nativeInterface.toggleTorch()
settingsModel.get(6).enabled = plasmoid.nativeInterface.torchEnabled
}
function toggleWifi() {
nmHandler.enableWireless(!enabledConnections.wirelessEnabled)
settingsModel.get(1).enabled = !enabledConnections.wirelessEnabled
}
function toggleWwan() {
nmHandler.enableWwan(!enabledConnections.wwanEnabled)
settingsModel.get(3).enabled = !enabledConnections.wwanEnabled
}
function toggleRotation() {
const enable = !plasmoid.nativeInterface.autoRotateEnabled
plasmoid.nativeInterface.autoRotateEnabled = enable
settingsModel.get(9).enabled = enable
}
function toggleBluetooth() {
var enable = !BluezQt.Manager.bluetoothOperational;
BluezQt.Manager.bluetoothBlocked = !enable;
for (var i = 0; i < BluezQt.Manager.adapters.length; ++i) {
var adapter = BluezQt.Manager.adapters[i];
adapter.powered = enable;
}
}
function toggleNightColor() {
if (compositorAdaptor.active) {
compositorAdaptor.activeStaged = false;
} else {
compositorAdaptor.activeStaged = true;
compositorAdaptor.modeStaged = 3; // always on
}
compositorAdaptor.sendConfigurationAll();
settingsModel.get(10).enabled = compositorAdaptor.active;
}
// components needed for quick settings
function requestScreenshot() {
screenshotRequested = true;
root.closeRequested();
}
// initialize quick settings
Component.onCompleted: {
//NOTE: add all in javascript as the static decl of listelements can't have scripts
settingsModel.append({
"text": i18n("Settings"),
"icon": "configure",
"enabled": false,
"settingsCommand": "plasma-settings",
"toggleFunction": ""
});
settingsModel.append({
"text": i18n("Wifi"),
"icon": "network-wireless-signal",
"settingsCommand": "plasma-settings -m kcm_mobile_wifi",
"toggleFunction": "toggleWifi",
"enabled": enabledConnections.wirelessEnabled
});
settingsModel.append({
"text": i18n("Bluetooth"),
"icon": "network-bluetooth",
"settingsCommand": "plasma-settings -m kcm_bluetooth",
"toggleFunction": "toggleBluetooth",
"delegate": "",
"enabled": BluezQt.Manager.bluetoothOperational
});
settingsModel.append({
"text": i18n("Mobile Data"),
"icon": "network-modem",
"settingsCommand": "plasma-settings -m kcm_mobile_broadband",
"toggleFunction": "toggleWwan",
"enabled": enabledConnections.wwanEnabled
});
settingsModel.append({
"text": i18n("Battery"),
"icon": "battery-full",
"enabled": false,
"settingsCommand": "plasma-settings -m kcm_mobile_power",
"toggleFunction": ""
});
settingsModel.append({
"text": i18n("Sound"),
"icon": "audio-speakers-symbolic",
"enabled": false,
"settingsCommand": "plasma-settings -m kcm_pulseaudio",
"toggleFunction": ""
});
settingsModel.append({
"text": i18n("Flashlight"),
"icon": "flashlight-on",
"enabled": plasmoid.nativeInterface.torchEnabled,
"settingsCommand": "",
"toggleFunction": "toggleTorch"
});
settingsModel.append({
"text": i18n("Location"),
"icon": "gps",
"enabled": false,
"settingsCommand": ""
});
settingsModel.append({
"text": i18n("Screenshot"),
"icon": "spectacle",
"enabled": false,
"settingsCommand": "",
"toggleFunction": "requestScreenshot"
});
settingsModel.append({
"text": i18n("Auto-rotate"),
"icon": "rotation-allowed",
"enabled": plasmoid.nativeInterface.autoRotateEnabled,
"settingsCommand": "",
"toggleFunction": "toggleRotation"
});
settingsModel.append({
"text": i18n("Night Color"),
"icon": "redshift-status-on",
"enabled": compositorAdaptor.active,
"settingsCommand": "", // change once night color kcm is added
"toggleFunction": "toggleNightColor"
});
}
}

View file

@ -0,0 +1,226 @@
/*
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.14
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import QtGraphicalEffects 1.12
import org.kde.kirigami 2.12 as Kirigami
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
import org.kde.bluezqt 1.0 as BluezQt
import org.kde.colorcorrect 0.1 as CC
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.components 3.0 as PC3
import "../"
Item {
id: root
implicitWidth: column.implicitWidth + PlasmaCore.Units.smallSpacing * 6
implicitHeight: column.implicitHeight + PlasmaCore.Units.smallSpacing * 2
signal closeRequested
signal closed
property bool expandedMode: parentSlidingPanel.wideScreen
readonly property real expandedRatio: expandedMode ? 1 : Math.max(0, Math.min(1, (parentSlidingPanel.offset - (parentSlidingPanel.topPanelHeight + firstRowHeight) - parentSlidingPanel.topPanelHeight) / otherRowsHeight + 0.05)) // HACK: add 0.05 to prevent jumping since this height isn't exact
readonly property real topEmptyAreaHeight: parentSlidingPanel.userInteracting
? (root.height - collapsedHeight) * (1 - expandedRatio)
: (expandedMode ? 0 : root.height - collapsedHeight)
readonly property real collapsedHeight: parentSlidingPanel.topPanelHeight + firstRowHeight + PlasmaCore.Units.smallSpacing * 2
readonly property real firstRowHeight: flow.children[0].height
readonly property real otherRowsHeight: column.implicitHeight - firstRowHeight - parentSlidingPanel.topPanelHeight
Connections {
target: root.parentSlidingPanel
function onUserInteractingChanged() {
if (!parentSlidingPanel.userInteracting) {
if (root.expandedRatio > 0.7) {
root.expandedMode = true;
}
}
}
}
property NanoShell.FullScreenOverlay parentSlidingPanel
Connections {
target: root.Window.window
function onVisibilityChanged() {
root.expandedMode = parentSlidingPanel.wideScreen;
}
}
signal plasmoidTriggered(var applet, var id)
Layout.minimumHeight: flow.implicitHeight + units.largeSpacing*2
onClosed: quickSettingsModel.panelClosed()
property QuickSettingsModel quickSettingsModel: QuickSettingsModel {}
// shadow below panel (only if not widescreen)
Rectangle {
visible: !parentSlidingPanel.wideScreen
anchors.bottom: background.bottom
anchors.left: background.left
anchors.right: background.right
height: PlasmaCore.Units.gridUnit
gradient: Gradient {
GradientStop {
position: 0.0
color: Qt.rgba(0, 0, 0, 0.05)
}
GradientStop {
position: 1.0
color: "transparent"
}
}
}
// shadow for bottom bar
RectangularGlow {
z: 1
anchors.topMargin: 1
anchors.fill: bottomBar
cached: true
glowRadius: 4
spread: 0.2
color: Qt.rgba(0, 0, 0, 0.1)
}
// shadow for whole panel (only if widescreen)
RectangularGlow {
visible: parentSlidingPanel.wideScreen
anchors.topMargin: 1
anchors.top: background.top
anchors.left: background.left
anchors.right: background.right
anchors.bottom: bottomBar.bottom
cached: true
glowRadius: 4
spread: 0.2
color: Qt.rgba(0, 0, 0, 0.1)
}
// bottom "handle bar"
Rectangle {
id: bottomBar
anchors.top: background.bottom
anchors.left: background.left
anchors.right: background.right
color: PlasmaCore.Theme.backgroundColor
height: Math.round(PlasmaCore.Units.gridUnit * 1.3)
z: 1
Kirigami.Icon {
visible: !parentSlidingPanel.wideScreen
color: PlasmaCore.Theme.disabledTextColor
source: expandedRatio >= 1 ? "go-up-symbolic" : "go-down-symbolic"
implicitWidth: PlasmaCore.Units.gridUnit
implicitHeight: width
anchors.centerIn: parent
}
}
Rectangle {
id: background
color: PlasmaCore.Theme.backgroundColor
anchors.fill: parent
ColumnLayout {
id: column
anchors.leftMargin: PlasmaCore.Units.smallSpacing
anchors.rightMargin: PlasmaCore.Units.smallSpacing
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
spacing: 0
clip: expandedRatio > 0 && expandedRatio < 1 // only clip when necessary to improve performance
readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6
readonly property real columnWidth: Math.floor(width / Math.floor(width / cellSizeHint))
IndicatorsRow {
id: indicatorsRow
z: 1
Layout.fillWidth: true
Layout.preferredHeight: parentSlidingPanel.topPanelHeight
colorGroup: PlasmaCore.Theme.NormalColorGroup
backgroundColor: "transparent"
showGradientBackground: false
showDropShadow: false
transform: Translate {
y: otherRowsHeight * (1 - root.expandedRatio) - PlasmaCore.Units.smallSpacing
}
}
Flow {
id: flow
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.leftMargin: units.smallSpacing + (units.largeSpacing - units.smallSpacing) * root.expandedRatio
Layout.rightMargin: units.smallSpacing + (units.largeSpacing - units.smallSpacing) * root.expandedRatio
Layout.topMargin: units.largeSpacing
readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6
readonly property real columns: Math.floor(width / cellSizeHint)
readonly property real columnsWhenCollapsed: 1.05 // .05 to account for the fact that we have an overshoot on the panel on first flick, we don't want the movement to be jarring
readonly property real columnWidth: Math.floor(width / (columns + (columnsWhenCollapsed - columnsWhenCollapsed * root.expandedRatio)))
spacing: 0
Repeater {
model: quickSettingsModel.model
delegate: Delegate {
id: delegateItem
settingsModel: quickSettingsModel
width: flow.columnWidth
labelOpacity: y > 0 ? 1 : root.expandedRatio
opacity: y <= 0 ? 1 : root.expandedRatio
transform: Translate {
y: otherRowsHeight * (1 - root.expandedRatio) - PlasmaCore.Units.smallSpacing * 2
}
Connections {
target: delegateItem
onCloseRequested: root.closeRequested();
}
Connections {
target: root
onClosed: delegateItem.panelClosed();
}
}
}
move: Transition {
NumberAnimation {
duration: units.shortDuration
easing.type: Easing.Linear
properties: "x,y"
}
}
}
BrightnessItem {
id: brightnessSlider
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: units.smallSpacing
Layout.bottomMargin: units.smallSpacing
Layout.leftMargin: units.largeSpacing
Layout.rightMargin: units.largeSpacing
Layout.fillWidth: true
opacity: root.expandedRatio
transform: Translate {
y: otherRowsHeight * (1 - root.expandedRatio) - PlasmaCore.Units.smallSpacing * 2
}
}
}
}
}