Implement lockscreen mockups

This commit is contained in:
Devin Lin 2020-08-31 01:38:46 +00:00
parent da3d3c022f
commit 46022538ac
13 changed files with 1326 additions and 132 deletions

View file

@ -1,26 +1,65 @@
/*
Copyright (C) 2019 Nicolas Fella <nicolas.fella@gmx.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.8
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.5
import QtGraphicalEffects 1.12
import org.kde.plasma.core 2.0
ColumnLayout {
readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software
property int alignment
Layout.alignment: alignment
spacing: units.gridUnit
Label {
text: Qt.formatTime(timeSource.data["Local"]["DateTime"])
text: Qt.formatTime(timeSource.data["Local"]["DateTime"], "h:mm ap")
color: ColorScope.textColor
style: softwareRendering ? Text.Outline : Text.Normal
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter
font.pointSize: 40
Layout.alignment: Qt.AlignHCenter
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" // no outline, doesn't matter
Layout.alignment: alignment
font.weight: Font.Light // this font weight may switch to regular on distros that don't have a light variant
font.pointSize: 36
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 1
radius: 4
samples: 6
color: "#757575"
}
}
Label {
text: Qt.formatDate(timeSource.data["Local"]["DateTime"], Qt.DefaultLocaleLongDate)
text: Qt.formatDate(timeSource.data["Local"]["DateTime"], "ddd, MMM d")
color: ColorScope.textColor
style: softwareRendering ? Text.Outline : Text.Normal
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter
font.pointSize: 16
Layout.alignment: Qt.AlignHCenter
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" // no outline, doesn't matter
Layout.alignment: alignment
font.pointSize: 10
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 1
radius: 4
samples: 6
color: "#757575"
}
}
DataSource {
id: timeSource

View file

@ -0,0 +1,56 @@
/*
* Copyright 2019 Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
import QtQuick 2.10
import org.kde.kirigami 2.11 as Kirigami
MouseArea {
id: delegate
property Item contentItem
property bool draggable: false
signal dismissRequested
anchors.fill: contentItem
implicitWidth: contentItem ? contentItem.implicitWidth : 0
implicitHeight: contentItem ? contentItem.implicitHeight : 0
opacity: 1 - Math.min(1, 1.5 * Math.abs(x) / width)
drag {
axis: Drag.XAxis
target: draggable && Kirigami.Settings.tabletMode ? this : null
}
onReleased: {
if (Math.abs(x) > width / 2) {
delegate.dismissRequested();
} else {
slideAnim.restart();
}
}
NumberAnimation {
id: slideAnim
target: delegate
property: "x"
to: 0
duration: units.longDuration
}
}

View file

@ -0,0 +1,227 @@
/*
Copyright (C) 2020 Devin Lin <espidev@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.12
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.12
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.workspace.keyboardlayout 1.0
Rectangle {
color: Qt.rgba(250, 250, 250, 0.85) // slightly translucent background, for key contrast
property string pinLabel: qsTr("Enter PIN")
// for displaying temporary number in pin dot display
property string lastKeyPressValue: "0"
property int indexWithNumber: -2
// keypad functions
function backspace() {
lastKeyPressValue = "0";
indexWithNumber = -2;
root.password = root.password.substr(0, root.password.length - 1);
}
function enter() {
authenticator.tryUnlock(root.password);
}
function keyPress(data) {
if (keypad.pinLabel !== qsTr("Enter PIN")) {
keypad.pinLabel = qsTr("Enter PIN");
}
lastKeyPressValue = data;
indexWithNumber = root.password.length;
root.password += data
// trigger turning letter into dot later
letterTimer.restart();
}
Connections {
target: authenticator
function onFailed() {
root.password = "";
pinLabel = qsTr("Wrong PIN")
}
}
// listen for keyboard events
Keys.onPressed: {
if (event.modifiers === Qt.NoModifier) {
if (event.key === Qt.Key_Backspace) {
backspace();
} else if (event.key === Qt.Key_Return) {
enter();
} else if (event.text != "") {
keyPress(event.text);
}
}
}
// trigger turning letter into dot after 500 milliseconds
Timer {
id: letterTimer
interval: 500
running: false
repeat: false
onTriggered: {
lastKeyPressValue = 0;
indexWithNumber = -2;
}
}
ColumnLayout {
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: parent.bottom
topMargin: units.gridUnit
bottomMargin: units.gridUnit
}
spacing: units.gridUnit
// pin dot display
Item {
Layout.alignment: Qt.AlignHCenter
Layout.minimumHeight: units.gridUnit * 0.5
Layout.maximumWidth: parent.width
Label {
visible: root.password.length === 0
anchors.centerIn: parent
text: pinLabel
font.pointSize: 12
color: "#616161"
}
RowLayout {
id: dotDisplay
anchors.centerIn: parent
height: units.gridUnit // maintain height when letter is shown
spacing: 6
Repeater {
model: root.password.length
delegate: Rectangle { // dot
visible: index !== indexWithNumber // hide dot if number is shown
Layout.preferredWidth: units.gridUnit * 0.25
Layout.preferredHeight: Layout.preferredWidth
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
radius: width
color: "#424242"
}
}
Label { // number/letter
visible: root.password.length-1 === indexWithNumber // hide label if no label needed
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
color: "#424242"
text: lastKeyPressValue
font.pointSize: 10
}
}
}
// separator
Rectangle {
Layout.fillWidth: true
height: 1
color: "#eeeeee"
}
// number keys
GridLayout {
property string thePw
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.leftMargin: units.gridUnit * 0.5
Layout.rightMargin: units.gridUnit * 0.5
Layout.maximumWidth: units.gridUnit * 22
Layout.maximumHeight: units.gridUnit * 12.5
columns: 4
// numpad keys
Repeater {
model: ["1", "2", "3", "R", "4", "5", "6", "0", "7", "8", "9", "E"]
delegate: Item {
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
id: keyRect
anchors.centerIn: parent
width: parent.width
height: parent.height
radius: 5
color: "white"
visible: modelData.length > 0
MouseArea {
anchors.fill: parent
onPressed: parent.color = "#e0e0e0"
onReleased: parent.color = "white"
onClicked: {
if (modelData === "R") {
backspace();
} else if (modelData === "E") {
enter();
} else {
keyPress(modelData);
}
}
}
}
DropShadow {
anchors.fill: keyRect
source: keyRect
cached: true
horizontalOffset: 0
verticalOffset: 1
radius: 4
samples: 6
color: "#e0e0e0"
}
PlasmaComponents.Label {
visible: modelData !== "R" && modelData !== "E"
text: modelData
anchors.centerIn: parent
font.pointSize: 18
color: "#424242"
}
PlasmaCore.IconItem {
visible: modelData === "R"
anchors.centerIn: parent
// colorGroup: PlasmaCore.ColorScope.backgroundColor
source: "edit-clear"
}
PlasmaCore.IconItem {
visible: modelData === "E"
anchors.centerIn: parent
// colorGroup: PlasmaCore.ColorScope.backgroundColor
source: "go-next"
}
}
}
}
}
}

View file

@ -22,68 +22,183 @@ import QtGraphicalEffects 1.12
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.workspace.keyboardlayout 1.0
import org.kde.notificationmanager 1.1 as Notifications
import "../components"
PlasmaCore.ColorScope {
id: root
property string password
property bool isWidescreen: root.height < root.width * 0.75
property bool notificationsShown: phoneNotificationsList.count !== 0
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
anchors.fill: parent
BrightnessContrast {
id: darken
function isPinDrawerOpen() {
return passwordFlickable.contentY === passwordFlickable.columnHeight;
}
// blur background once keypad is open
FastBlur {
id: blur
cached: true
anchors.fill: parent
source: wallpaper
brightness: -(passwordFlickable.contentY / passwordFlickable.columnHeight * 0.6)
}
DropShadow {
id: clockShadow
anchors.fill: clock
source: clock
horizontalOffset: 1
verticalOffset: 1
radius: 6
samples: 14
spread: 0.3
color: PlasmaCore.ColorScope.backgroundColor
visible: true
// hide when keypad is shown
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
property bool doBlur: notificationsShown || isPinDrawerOpen() // only blur once animation finished for performance
Behavior on doBlur {
NumberAnimation {
target: blur
property: "radius"
duration: 1000
to: blur.doBlur ? 0 : 50
easing.type: Easing.InOutQuad
}
PropertyAction {
target: blur
property: "visible"
value: blur.doBlur
}
}
}
Clock {
id: clock
property Item shadow: clockShadow
anchors.leftMargin: units.gridUnit
anchors.rightMargin: units.gridUnit
anchors.topMargin: units.gridUnit * 3
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Notifications.WatchedNotificationsModel {
id: notifModel
}
// header bar
SimpleHeaderBar {
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: units.gridUnit
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
}
MediaControls {
// phone clock component
ColumnLayout {
id: phoneClockComponent
visible: !isWidescreen
anchors {
top: parent.top
topMargin: root.height / 2 - (height / 2 + units.gridUnit * 2)
left: parent.left
right: parent.right
}
spacing: 0
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
states: State {
name: "notification"; when: notificationsShown
PropertyChanges { target: phoneClockComponent; anchors.topMargin: units.gridUnit * 5 }
}
transitions: Transition {
NumberAnimation {
properties: "anchors.topMargin"
easing.type: Easing.InOutQuad
}
}
Clock {
id: phoneClock
alignment: Qt.AlignHCenter
Layout.bottomMargin: units.gridUnit * 2 // keep spacing even if media controls are gone
}
MediaControls {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.maximumWidth: units.gridUnit * 25
Layout.minimumWidth: units.gridUnit * 15
Layout.leftMargin: units.gridUnit
Layout.rightMargin: units.gridUnit
z: 5
}
}
// tablet clock component
Item {
id: tabletClockComponent
visible: isWidescreen
width: parent.width / 2
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
leftMargin: units.gridUnit * 3
}
ColumnLayout {
id: tabletLayout
anchors.centerIn: parent
spacing: units.gridUnit
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
Clock {
id: tabletClock
alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.minimumWidth: units.gridUnit * 20
}
MediaControls {
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.maximumWidth: units.gridUnit * 25
Layout.minimumWidth: units.gridUnit * 20
z: 5
}
}
}
// phone notifications list
NotificationsList {
id: phoneNotificationsList
visible: !isWidescreen
z: passwordFlickable.contentY === 0 ? 5 : 0 // prevent mousearea from interfering with pin drawer
anchors {
top: phoneClockComponent.bottom
topMargin: units.gridUnit
bottom: scrollUpIcon.top
bottomMargin: units.gridUnit
left: parent.left
leftMargin: units.gridUnit
right: parent.right
rightMargin: units.gridUnit
verticalCenter: parent.verticalCenter
}
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
z: 5
}
// tablet notifications list
ColumnLayout {
visible: isWidescreen
z: passwordFlickable.contentY === 0 ? 5 : 0 // prevent mousearea from interfering with pin drawer
anchors {
top: parent.top
bottom: parent.bottom
left: tabletClockComponent.right
right: parent.right
rightMargin: units.gridUnit
}
NotificationsList {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.fillWidth: true
Layout.minimumHeight: this.notificationListHeight
Layout.minimumWidth: units.gridUnit * 15
Layout.maximumWidth: units.gridUnit * 25
}
}
// scroll up icon
PlasmaCore.IconItem {
id: scrollUpIcon
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: units.gridUnit + passwordFlickable.contentY * 0.5
anchors.horizontalCenter: parent.horizontalCenter
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
@ -116,8 +231,10 @@ PlasmaCore.ColorScope {
// wipe password if it is more than half way down the screen
onContentYChanged: {
if (contentY < columnHeight / 2)
if (contentY < columnHeight / 2) {
root.password = "";
keypad.pinLabel = qsTr("Enter PIN");
}
}
ColumnLayout {
@ -125,99 +242,22 @@ PlasmaCore.ColorScope {
anchors.bottom: parent.bottom
width: parent.width
spacing: units.gridUnit * 2
spacing: units.gridUnit
opacity: Math.sin((Math.PI / 2) * (passwordFlickable.contentY / passwordFlickable.columnHeight) + 1.5 * Math.PI) + 1
PlasmaComponents.Label {
// scroll down icon
PlasmaCore.IconItem {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Enter PIN")
font.pointSize: 12
}
Row {
id: dotDisplay
Layout.alignment: Qt.AlignHCenter
spacing: 6
Layout.minimumHeight: units.gridUnit
Layout.maximumWidth: parent.width
Repeater {
model: root.password.length
delegate: Rectangle {
width: units.gridUnit
height: width
radius: width
color: Qt.rgba(255, 255, 255, 0.3)
}
}
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
source: "arrow-down"
}
GridLayout {
id: numBlock
property string thePw
Keypad {
id: keypad
focus: passwordFlickable.contentY === passwordFlickable.columnHeight
Layout.fillWidth: true
Layout.minimumHeight: units.gridUnit * 16
Layout.minimumHeight: units.gridUnit * 17
Layout.maximumWidth: root.width
Layout.bottomMargin: units.gridUnit * 2
Layout.leftMargin: units.gridUnit * 2
Layout.rightMargin: units.gridUnit * 2
rowSpacing: units.gridUnit
columns: 3
Repeater {
model: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "R", "0", "E"]
delegate: Item {
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
anchors.centerIn: parent
width: units.gridUnit * 3
height: width
radius: 12
color: Qt.rgba(PlasmaCore.ColorScope.backgroundColor.r, PlasmaCore.ColorScope.backgroundColor.g, PlasmaCore.ColorScope.backgroundColor.b, ma.pressed ? 0.8 : 0.3)
visible: modelData.length > 0
MouseArea {
id: ma
anchors.fill: parent
onClicked: {
if (modelData === "R") {
root.password = root.password.substr(0, root.password.length - 1);
} else if (modelData === "E") {
authenticator.tryUnlock(root.password);
} else {
root.password += modelData
}
}
}
}
PlasmaComponents.Label {
visible: modelData !== "R" && modelData !== "E"
text: modelData
anchors.centerIn: parent
font.pointSize: 16
}
PlasmaCore.IconItem {
visible: modelData === "R"
anchors.centerIn: parent
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
source: "edit-clear"
}
PlasmaCore.IconItem {
visible: modelData === "E"
anchors.centerIn: parent
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
source: "go-next"
}
}
}
}
}
}

View file

@ -0,0 +1,58 @@
/*
Copyright (C) 2020 Devin Lin <espidev@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.12
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.12
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.notificationmanager 1.1 as Notifications
import "../components"
Item {
property alias notificationListHeight: notificationListView.contentHeight
property int count: notificationListView.count
ListView {
id: notificationListView
model: notifModel
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: Math.min(contentHeight, parent.height) // don't take up the entire screen for notification list view
interactive: contentHeight > parent.height // only allow scrolling on notifications list if it is long enough
clip: true
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
spacing: units.gridUnit
delegate: Column {
width: notificationListView.width
spacing: units.smallSpacing
// insert application heading here once application grouping is implemented
SimpleNotification {
notification: model
}
}
}
}

View file

@ -0,0 +1,108 @@
/*
* Copyright 2019 Marco Martin <mart@kde.org>
* 2020 Devin Lin <espidev@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.12
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
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 "indicators" as Indicators
// a simple version of the task panel
// in the future, it should share components with the existing task panel
PlasmaCore.ColorScope {
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
layer.enabled: true
layer.effect: 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
}
PlasmaCore.DataSource {
id: timeSource
engine: "time"
connectedSources: ["Local"]
interval: 60 * 1000
}
Rectangle {
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
source: Qt.resolvedUrl("indicators/SignalStrength.qml")
}
PlasmaComponents.Label {
id: clock
anchors.fill: parent
text: Qt.formatTime(timeSource.data.Local.DateTime, "hh:mm")
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 {}
Indicators.Wifi {}
Indicators.Volume {}
Indicators.Battery {}
}
}

View file

@ -0,0 +1,169 @@
/*
Copyright (C) 2020 Devin Lin <espidev@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.12
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.12
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.notificationmanager 1.1 as Notifications
import org.kde.kquickcontrolsaddons 2.0 as KQCAddons
import "../components"
// meant to be temporary, until the notifications components in plasma-workspace are available to used
// https://invent.kde.org/plasma/plasma-workspace/-/blob/master/applets/notifications/package/contents/ui/NotificationItem.qml
Item {
property var notification
anchors.left: parent.left
anchors.right: parent.right
height: notifLayout.height + units.gridUnit
opacity: 1 - Math.min(1, 1.5 * Math.abs(rect.x) / width) // opacity during dismiss swipe
// notification
Rectangle {
id: rect
radius: 5
color: "white"
height: parent.height
width: parent.width
border.color: "#bdbdbd"
border.width: 1
RowLayout {
id: notifLayout
height: textLayout.height
anchors {
left: parent.left
leftMargin: units.gridUnit * 0.5
right: parent.right
rightMargin: units.gridUnit * 0.5
verticalCenter: parent.verticalCenter
}
spacing: units.smallSpacing / 2
// notif body
ColumnLayout {
id: textLayout
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
spacing: units.gridUnit / 2
Label {
text: notification.summary
color: "#212121"
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
maximumLineCount: 3
wrapMode: Text.WordWrap
elide: Text.ElideRight
font.pointSize: 11
}
Label {
text: notification.body
color: "#616161"
Layout.fillWidth: true
wrapMode: Text.WordWrap
elide: Text.ElideRight
font.pointSize: 10
}
}
// notification icon
Item {
id: iconContainer
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.preferredWidth: units.iconSizes.large
Layout.preferredHeight: units.iconSizes.large
Layout.topMargin: units.smallSpacing
Layout.bottomMargin: units.smallSpacing
visible: iconItem.active || imageItem.active
PlasmaCore.IconItem {
id: iconItem
// don't show two identical icons
readonly property bool active: valid && source != notification.applicationIconSource
anchors.fill: parent
usesPlasmaTheme: false
smooth: true
source: {
let icon = notification.icon;
if (typeof icon !== "string") return "";
if (icon === "dialog-information") return "";
return icon;
}
visible: active
}
KQCAddons.QImageItem {
id: imageItem
readonly property bool active: !null && nativeWidth > 0
anchors.fill: parent
smooth: true
fillMode: KQCAddons.QImageItem.PreserveAspectFit
visible: active
image: typeof notification.icon === "object" ? notification.icon : undefined
}
}
}
// swipe gesture for dismissing notification (left/right)
MouseArea {
id: dismissSwipe
anchors.fill: parent
drag.axis: Drag.XAxis
drag.target: rect
onReleased: {
if (Math.abs(rect.x) > width / 2) { // dismiss notification when finished swipe
notifModel.close(notification.id);
} else {
slideAnim.restart();
}
}
NumberAnimation {
id: slideAnim
target: rect
property: "x"
to: 0
duration: units.longDuration
}
}
}
DropShadow {
anchors.fill: rect
source: rect
horizontalOffset: 1
verticalOffset: 1
radius: 4
samples: 6
color: "#616161"
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2019 Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
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
RowLayout {
visible: pmSource.data["Battery"]["Has Cumulative"]
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
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)
Layout.alignment: Qt.AlignVCenter
color: PlasmaCore.ColorScope.textColor
font.pixelSize: parent.height / 2
}
}

View file

@ -0,0 +1,62 @@
/*
Copyright 2019 MArco MArtni <mart@kde.org>
Copyright 2013-2017 Jan Grulich <jgrulich@redhat.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
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
PlasmaCore.IconItem {
id: connectionIcon
property bool deviceConnected : false
source: deviceConnected ? "preferences-system-bluetooth-activated" : "preferences-system-bluetooth";
colorGroup: PlasmaCore.ColorScope.colorGroup
visible: BluezQt.Manager.bluetoothOperational
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

@ -0,0 +1,44 @@
/*
* Copyright 2019 Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.6
import QtQuick.Layouts 1.4
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
RowLayout {
property alias icon: icon.source
property alias text: label.text
PlasmaCore.IconItem {
id: icon
colorGroup: PlasmaCore.ColorScope.colorGroup
Layout.fillHeight: true
Layout.preferredWidth: height
}
PlasmaComponents.Label {
id: label
visible: text.length > 0
color: PlasmaCore.ColorScope.textColor
font.pixelSize: parent.height / 2
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright 2015 Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
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
Item {
width: strengthIcon.height + strengthLabel.width
Layout.minimumWidth: strengthIcon.height + strengthLabel.width
OfonoManager {
id: ofonoManager
onAvailableChanged: {
console.log("Ofono is " + available)
}
onModemAdded: {
console.log("modem added " + modem)
}
onModemRemoved: console.log("modem removed")
}
OfonoNetworkRegistration {
id: netreg
Component.onCompleted: {
netreg.scan()
updateStrengthIcon()
}
onNetworkOperatorsChanged : {
console.log("operators :"+netreg.currentOperator["Name"].toString())
}
modemPath: ofonoManager.modems.length ? ofonoManager.modems[0] : ""
function updateStrengthIcon() {
if (netreg.strength >= 100) {
strengthIcon.source = "network-mobile-100";
} else if (netreg.strength >= 80) {
strengthIcon.source = "network-mobile-80";
} else if (netreg.strength >= 60) {
strengthIcon.source = "network-mobile-60";
} else if (netreg.strength >= 40) {
strengthIcon.source = "network-mobile-40";
} else if (netreg.strength >= 20) {
strengthIcon.source = "network-mobile-20";
} else {
strengthIcon.source = "network-mobile-0";
}
}
onStrengthChanged: {
console.log("Strength changed to " + netreg.strength)
updateStrengthIcon()
}
}
PlasmaCore.IconItem {
id: strengthIcon
colorGroup: PlasmaCore.ColorScope.colorGroup
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
width: height
height: parent.height
}
PlasmaComponents.Label {
id: strengthLabel
anchors {
left: strengthIcon.right
verticalCenter: parent.verticalCenter
}
text: netreg.strength + "% " + netreg.name
color: PlasmaCore.ColorScope.textColor
font.pixelSize: parent.height / 2
}
}

View file

@ -0,0 +1,176 @@
/*
Copyright 2019 Aditya Mehra <Aix.m@outlook.com>
Copyright 2014-2015 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
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
PlasmaCore.IconItem {
id: paIcon
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)
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: main.displayName
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,60 @@
/*
Copyright 2019 MArco MArtni <mart@kde.org>
Copyright 2013-2017 Jan Grulich <jgrulich@redhat.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
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
PlasmaCore.IconItem {
id: connectionIcon
source: connectionIconProvider.connectionIcon
colorGroup: PlasmaCore.ColorScope.colorGroup
Layout.fillHeight: true
Layout.preferredWidth: height
PlasmaComponents.BusyIndicator {
id: connectingIndicator
anchors.fill: parent
running: connectionIconProvider.connecting
visible: running
}
PlasmaNM.NetworkStatus {
id: networkStatus
}
PlasmaNM.NetworkModel {
id: connectionModel
}
PlasmaNM.Handler {
id: handler
}
PlasmaNM.ConnectionIcon {
id: connectionIconProvider
}
}