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

View file

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

View file

@ -15,10 +15,11 @@ FullContainer {
shouldBeVisible: applet && historyModel.count > 0
visible: shouldBeVisible
NotificationManager.Notifications {
id: historyModel
showExpired: 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-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.workspace.components 2.0 as PW
import "providers"
RowLayout {
visible: pmSource.data["Battery"]["Has Cumulative"]
required property BatteryProvider provider
visible: provider.isVisible
PW.BatteryIcon {
id: battery
Layout.preferredWidth: height
Layout.fillHeight: true
hasBattery: true
percent: pmSource.data["Battery"]["Percent"]
pluggedIn: pmSource.data["AC Adapter"] ? pmSource.data["AC Adapter"]["Plugged in"] : false
percent: provider.percent
pluggedIn: provider.pluggedIn
height: batteryLabel.height
width: batteryLabel.height
PlasmaCore.DataSource {
id: pmSource
engine: "powermanagement"
connectedSources: ["Battery", "AC Adapter"]
}
}
PlasmaComponents.Label {
id: batteryLabel
text: i18n("%1%", battery.percent)
text: i18n("%1%", provider.percent)
Layout.alignment: Qt.AlignVCenter
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: 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.bluezqt 1.0 as BluezQt
import "providers"
PlasmaCore.IconItem {
id: connectionIcon
required property BluetoothProvider provider
property bool deviceConnected : false
source: deviceConnected ? "preferences-system-bluetooth-activated" : "preferences-system-bluetooth";
source: provider.icon;
colorGroup: PlasmaCore.ColorScope.colorGroup
visible: BluezQt.Manager.bluetoothOperational
visible: provider.isVisible
Layout.fillHeight: true
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-License-Identifier: GPL-2.0-or-later
@ -7,34 +8,19 @@
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
import "providers"
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
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 {
id: strengthIcon
colorGroup: PlasmaCore.ColorScope.colorGroup
@ -43,12 +29,7 @@ Item {
width: height
height: parent.height
source: 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"
source: provider.icon
}
PlasmaComponents.Label {
@ -56,7 +37,7 @@ Item {
anchors.left: strengthIcon.right
anchors.verticalCenter: parent.verticalCenter
text: simManager.pinRequired !== OfonoSimManager.NoPin ? i18n("Sim locked") : netreg.name
text: provider.label
color: PlasmaCore.ColorScope.textColor
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: 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.private.volume 0.1
PlasmaCore.IconItem {
import "providers"
PlasmaCore.IconItem {
id: paIcon
required property VolumeProvider provider
Layout.fillHeight: true
Layout.preferredWidth: height
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"
source: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)
? iconName(paSinkModel.preferredSink.volume, paSinkModel.preferredSink.muted)
: iconName(0, true)
source: provider.icon
colorGroup: PlasmaCore.ColorScope.colorGroup
visible: paSinkModel.preferredSink && paSinkModel.preferredSink.muted
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()
}
}
visible: provider.isVisible
}

View file

@ -1,4 +1,5 @@
/*
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>
@ -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.networkmanagement 0.2 as PlasmaNM
import "providers"
PlasmaCore.IconItem {
id: connectionIcon
required property WifiProvider provider
source: connectionIconProvider.connectionIcon
source: provider.icon
colorGroup: PlasmaCore.ColorScope.colorGroup
Layout.fillHeight: true
@ -24,23 +28,7 @@ PlasmaCore.IconItem {
id: connectingIndicator
anchors.fill: parent
running: connectionIconProvider.connecting
running: provider.indicatorRunning
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-License-Identifier: GPL-2.0-or-later
@ -9,6 +10,8 @@ import QtQuick.Layouts 1.3
import QtQml.Models 2.12
import QtGraphicalEffects 1.12
import org.kde.kirigami 2.12 as Kirigami
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
@ -23,7 +26,7 @@ import "LayoutManager.js" as LayoutManager
import "quicksettings"
import "indicators" as Indicators
import "indicators/providers" as IndicatorProviders
Item {
id: root
@ -37,7 +40,7 @@ Item {
property bool reorderingApps: false
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 hasTasks: tasksModel.count > 0
@ -48,7 +51,7 @@ Item {
}
function addApplet(applet, x, y) {
var compactContainer = compactContainerComponent.createObject(appletIconsRow)
var compactContainer = compactContainerComponent.createObject(topPanel.applets)
print("Applet added: " + applet + " " + applet.title)
applet.parent = compactContainer;
@ -115,138 +118,59 @@ Item {
property Item applet
visible: applet && (applet.status != PlasmaCore.Types.HiddenStatus && applet.status != PlasmaCore.Types.PassiveStatus)
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
}
}
Component {
id: fullContainerComponent
FullContainer {
}
FullContainer {}
}
Component {
id: fullNotificationsContainerComponent
FullNotificationsContainer {
}
FullNotificationsContainer {}
}
PlasmaCore.DataSource {
id: timeSource
engine: "time"
connectedSources: ["Local"]
interval: 60 * 1000
// indicator providers
IndicatorProviders.BatteryProvider {
id: batteryProvider
}
DropShadow {
anchors.fill: icons
visible: !showingApp
cached: true
horizontalOffset: 0
verticalOffset: 1
radius: 4.0
samples: 17
color: Qt.rgba(0,0,0,0.8)
source: icons
IndicatorProviders.BluetoothProvider {
id: bluetoothProvider
}
// screen top panel
PlasmaCore.ColorScope {
id: icons
z: 1
colorGroup: showingApp ? PlasmaCore.Theme.HeaderColorGroup : PlasmaCore.Theme.ComplementaryColorGroup
//parent: slidingPanel.visible && !slidingPanel.wideScreen ? panelContents : root
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: root.height
Rectangle {
anchors.fill: parent
gradient: Gradient {
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 {}
}
property alias signalStrengthProvider: signalStrengthProviderLoader.item
Loader {
id: signalStrengthProviderLoader
source: Qt.resolvedUrl("indicators/providers/SignalStrengthProvider.qml")
}
IndicatorProviders.VolumeProvider {
id: volumeProvider
}
IndicatorProviders.WifiProvider {
id: wifiProvider
}
// screen top panel background (background for the rest of the screen in SlidingPanel.qml)
// top panel component
IndicatorsRow {
id: topPanel
anchors.fill: parent
z: 1
colorGroup: showingApp ? PlasmaCore.Theme.HeaderColorGroup : PlasmaCore.Theme.ComplementaryColorGroup
backgroundColor: !showingApp ? "transparent" : root.backgroundColor
showGradientBackground: !showingApp
showDropShadow: !showingApp
}
// top panel background (background for the rest of the screen in SlidingPanel.qml)
Rectangle {
anchors.fill: parent
color: "black"
color: PlasmaCore.Theme.backgroundColor
opacity: 0.6 * Math.min(1, slidingPanel.offset/panelContents.height)
}
// initial swipe down
MouseArea {
z: 99
property int oldMouseY: 0
@ -256,13 +180,12 @@ Item {
slidingPanel.cancelAnimations();
slidingPanel.drawerX = Math.min(Math.max(0, mouse.x - slidingPanel.drawerWidth/2), slidingPanel.width - slidingPanel.contentItem.width)
slidingPanel.userInteracting = true;
slidingPanel.flickable.contentY = slidingPanel.closedContentY;
oldMouseY = mouse.y;
slidingPanel.offset = 0//units.gridUnit * 2;
slidingPanel.showFullScreen();
}
onPositionChanged: {
slidingPanel.offset = Math.min(slidingPanel.contentItem.height, slidingPanel.offset + (mouse.y - oldMouseY));
slidingPanel.updateOffset(mouse.y - oldMouseY);
oldMouseY = mouse.y;
}
onReleased: {
@ -275,61 +198,65 @@ Item {
}
}
SlidingPanel {
// sliding component
SlidingContainer {
id: slidingPanel
width: plasmoid.availableScreenRect.width
height: plasmoid.availableScreenRect.height
openThreshold: units.gridUnit * 2
headerHeight: root.height
topPanelHeight: topPanel.height
topEmptyAreaHeight: quickSettings.topEmptyAreaHeight
collapsedHeight: quickSettings.collapsedHeight
fullyOpenHeight: quickSettings.implicitHeight
appletsShown: fullRepresentationView.count > 0
offset: quickSettings.height
onClosed: quickSettings.closed()
contentItem: Item {
implicitWidth: panelContents.implicitWidth
contentItem: MouseArea {
// mousearea captures touch presses so that the flickable picks them up for swiping
implicitWidth: slidingPanel.width
implicitHeight: Math.min(slidingPanel.height, quickSettings.implicitHeight)
GridLayout {
id: panelContents
anchors.fill: parent
implicitWidth: quickSettings.implicitWidth
implicitHeight: Math.min(slidingPanel.height, quickSettings.implicitHeight)
columns: slidingPanel.wideScreen ? 2 : 1
rows: slidingPanel.wideScreen ? 1 : 2
QuickSettings {
QuickSettingsPanel {
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.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, units.gridUnit * 25) : panelContents.width
z: 4
parentSlidingPanel: slidingPanel
onCloseRequested: {
slidingPanel.hide()
}
background: DrawerBackground {}
onCloseRequested: slidingPanel.hide()
}
// notifications
ListView {
id: fullRepresentationView
z: 1
interactive: width < contentWidth
//parent: slidingPanel.wideScreen ? slidingPanel.flickable.contentItem : panelContents
implicitHeight: units.gridUnit * 20
Layout.topMargin: slidingPanel.wideScreen ? 0 : Math.round(Kirigami.Units.gridUnit * 1.5) // add height of bottom bar
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
y: slidingPanel.wideScreen ? 0 : quickSettings.height - (quickSettings.height + height) * (1-opacity)
opacity: slidingPanel.wideScreen ? 1 : fullRepresentationModel.count > 0 && (slidingPanel.offset + slidingPanel.headerHeight)/(quickSettings.height -slidingPanel.topEmptyAreaHeight)
Layout.preferredHeight: Math.min(plasmoid.screenGeometry.height - slidingPanel.headerHeight - quickSettings.height - bottomBar.height + slidingPanel.topEmptyAreaHeight, implicitHeight)
//leftMargin: slidingPanel.drawerX
y: slidingPanel.wideScreen ? 0 : quickSettings.trueHeight
opacity: {
if (slidingPanel.wideScreen) {
return 1;
} else {
return fullRepresentationModel.count > 0 && slidingPanel.offset / slidingPanel.collapsedHeight;
}
}
preferredHighlightBegin: slidingPanel.drawerX
implicitHeight: units.gridUnit * 20
cacheBuffer: width * 100
highlightFollowsCurrentItem: true
highlightRangeMode: ListView.StrictlyEnforceRange
@ -346,10 +273,6 @@ Item {
z: -1
onClicked: slidingPanel.close()
}
//implicitHeight: fullRepresentationLayout.implicitHeight
//clip: true
}
}
}
@ -360,11 +283,11 @@ Item {
right: parent.right
bottom: parent.bottom
}
backgroundColor: Kirigami.ColorUtils.adjustColor(PlasmaCore.Theme.backgroundColor, {"alpha": 0.8*255})
parent: slidingPanel.fixedArea
opacity: fullRepresentationView.opacity
visible: !slidingPanel.wideScreen && fullRepresentationModel.count > 1
//height: 40
z: 100
contentItem: RowLayout {
PlasmaComponents.TabBar {

View file

@ -9,40 +9,89 @@
import QtQuick 2.0
import QtQuick.Controls 2.15
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.components 3.0 as PC3
RowLayout {
Item {
id: brightnessRoot
property alias value: brightnessSlider.value
property alias maximumValue: brightnessSlider.to
signal moved
spacing: units.smallSpacing
PlasmaCore.IconItem {
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.preferredWidth: units.iconSizes.medium
Layout.preferredHeight: width
source: "low-brightness"
}
Slider {
id: brightnessSlider
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
onMoved: brightnessRoot.moved()
from: 1
implicitHeight: brightnessRow.implicitHeight
property int screenBrightness
property bool disableBrightnessUpdate: true
readonly property int maximumScreenBrightness: pmSource.data["PowerDevil"] ? pmSource.data["PowerDevil"]["Maximum Screen Brightness"] || 0 : 0
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.IconItem {
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.preferredWidth: units.iconSizes.medium
Layout.preferredHeight: width
source: "high-brightness"
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.leftMargin: PlasmaCore.Units.smallSpacing
Layout.preferredWidth: Math.round(PlasmaCore.Units.gridUnit * 1.75)
Layout.preferredHeight: width
source: "low-brightness"
}
Slider {
id: brightnessSlider
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
value: screenBrightness
from: 1
to: maximumScreenBrightness
}
Kirigami.Icon {
color: PlasmaCore.Theme.textColor
isMask: true
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: PlasmaCore.Units.smallSpacing
Layout.preferredWidth: Math.round(PlasmaCore.Units.gridUnit * 1.75)
Layout.preferredHeight: width
source: "high-brightness"
}
}
}

View file

@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
@ -14,6 +15,9 @@ import org.kde.plasma.private.nanoshell 2.0 as NanoShell
ColumnLayout {
id: delegateRoot
spacing: units.smallSpacing
required property var settingsModel
signal closeRequested
signal panelClosed
@ -24,67 +28,68 @@ ColumnLayout {
required property string settingsCommand
required property var toggleFunction
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 {
Layout.preferredWidth: units.iconSizes.large + units.smallSpacing
Layout.preferredWidth: PlasmaCore.Units.iconSizes.large + PlasmaCore.Units.smallSpacing
Layout.minimumHeight: width
Layout.alignment: Qt.AlignHCenter
radius: units.smallSpacing
radius: PlasmaCore.Units.smallSpacing
border.color: delegateRoot.enabled ?
Qt.darker(Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.highlightColor, {}), 1.25) :
Kirigami.ColorUtils.adjustColor(PlasmaCore.ColorScope.textColor, {"alpha": 0.2*255})
color: {
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 {
if (iconMouseArea.pressed) {
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});
}
return iconMouseArea.pressed ? disabledPressedButtonColor : disabledButtonColor
}
}
PlasmaCore.IconItem {
Kirigami.Icon {
id: icon
colorGroup: PlasmaCore.ColorScope.colorGroup
anchors {
fill: parent
margins: units.smallSpacing
}
color: PlasmaCore.Theme.textColor
anchors.centerIn: parent
implicitWidth: Math.round(parent.width * 0.6)
implicitHeight: width
source: delegateRoot.icon
MouseArea {
id: iconMouseArea
anchors.fill: parent
onClicked: {
if (delegateRoot.toggle) {
delegateRoot.toggle();
} else if (delegateRoot.toggleFunction) {
root[delegateRoot.toggleFunction]();
} else if (delegateRoot.settingsCommand) {
NanoShell.StartupFeedback.open(
delegateRoot.icon,
delegateRoot.text,
icon.Kirigami.ScenePosition.x + icon.width/2,
icon.Kirigami.ScenePosition.y + icon.height/2,
Math.min(icon.width, icon.height))
plasmoid.nativeInterface.executeCommand(delegateRoot.settingsCommand);
root.closeRequested();
}
}
MouseArea {
id: iconMouseArea
anchors.fill: parent
onClicked: {
if (delegateRoot.toggle) {
delegateRoot.toggle();
} else if (delegateRoot.toggleFunction) {
settingsModel[delegateRoot.toggleFunction]();
} else if (delegateRoot.settingsCommand) {
NanoShell.StartupFeedback.open(
delegateRoot.icon,
delegateRoot.text,
icon.Kirigami.ScenePosition.x + icon.width/2,
icon.Kirigami.ScenePosition.y + icon.height/2,
Math.min(icon.width, icon.height))
plasmoid.nativeInterface.executeCommand(delegateRoot.settingsCommand);
root.closeRequested();
}
onPressAndHold: {
if (delegateRoot.settingsCommand) {
NanoShell.StartupFeedback.open(
delegateRoot.icon,
delegateRoot.text,
icon.Kirigami.ScenePosition.x + icon.width/2,
icon.Kirigami.ScenePosition.y + icon.height/2,
Math.min(icon.width, icon.height))
closeRequested();
plasmoid.nativeInterface.executeCommand(delegateRoot.settingsCommand);
} else if (delegateRoot.toggleFunction) {
root[delegateRoot.toggleFunction]();
}
}
onPressAndHold: {
if (delegateRoot.settingsCommand) {
NanoShell.StartupFeedback.open(
delegateRoot.icon,
delegateRoot.text,
icon.Kirigami.ScenePosition.x + icon.width/2,
icon.Kirigami.ScenePosition.y + icon.height/2,
Math.min(icon.width, icon.height))
closeRequested();
plasmoid.nativeInterface.executeCommand(delegateRoot.settingsCommand);
} else if (delegateRoot.toggleFunction) {
root[delegateRoot.toggleFunction]();
}
}
}
@ -131,7 +136,7 @@ ColumnLayout {
plasmoid.nativeInterface.executeCommand(delegateRoot.settingsCommand);
closeRequested();
} 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
}
}
}
}
}