import QtQuick.Controls 1.1 import QtQuick.Controls 2.12 as QQC2 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.extras 2.0 as PlasmaExtras import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.1 import QtQuick 2.8 import SddmComponents 2.0 import QtMultimedia 5.7 import "components" Rectangle { // Main Container id: container LayoutMirroring.enabled: Qt.locale().textDirection == Qt.RightToLeft LayoutMirroring.childrenInherit: true // Inherited from SDDMComponents TextConstants { id: textConstants } // Set SDDM actions Connections { target: sddm onLoginSucceeded: { } onLoginFailed: { error_message.color = "#dc322f" error_message.text = textConstants.loginFailed } } // Set Font FontLoader { id: textFont; name: config.displayFont } // Background Fill Rectangle { anchors.fill: parent color: "black" } // Set Background Image Image { id: image1 anchors.fill: parent //source: config.background fillMode: Image.PreserveAspectCrop } // Set Background Video1 MediaPlayer { id: mediaplayer1 autoPlay: true; muted: true playlist: Playlist { id: playlist1 playbackMode: Playlist.Random onLoaded: { mediaplayer1.play() } } } VideoOutput { id: video1 fillMode: VideoOutput.PreserveAspectCrop anchors.fill: parent; source: mediaplayer1 MouseArea { id: mouseArea1 anchors.fill: parent; //onPressed: {playlist1.shuffle(); playlist1.next();} onPressed: {} } Keys.onPressed: {} } WallpaperFader { id: fader1 visible: true anchors.fill: parent state: "off" source: video1 } // Set Background Video2 MediaPlayer { id: mediaplayer2 autoPlay: true; muted: true playlist: Playlist { id: playlist2; playbackMode: Playlist.Random //onLoaded: { mediaplayer2.play() } } } VideoOutput { id: video2 fillMode: VideoOutput.PreserveAspectCrop anchors.fill: parent; source: mediaplayer2 opacity: 0 MouseArea { id: mouseArea2 enabled: false anchors.fill: parent; onPressed: {} } Behavior on opacity {} Keys.onPressed: {} } WallpaperFader { id: fader2 visible: true anchors.fill: parent state: "off" source: video2 } property MediaPlayer currentPlayer: mediaplayer1 // Timer event to handle fade between videos Timer { interval: 1000; running: true; repeat: true onTriggered: { if (currentPlayer.duration != -1 && currentPlayer.position > currentPlayer.duration - 10000) { // pre load the 2nd player if (video2.opacity == 0) { // toogle opacity mediaplayer2.play() } else mediaplayer1.play() } if (currentPlayer.duration != -1 && currentPlayer.position > currentPlayer.duration - 3000) { // initiate transition if (video2.opacity == 0) { // toogle opacity mouseArea1.enabled = false currentPlayer = mediaplayer2 video2.opacity = 1 triggerTimer.start() mouseArea2.enabled = true } else { mouseArea2.enabled = false currentPlayer = mediaplayer1 video2.opacity = 0 triggerTimer.start() mouseArea1.enabled = true } } } } Timer { // this timer waits for fade to stop and stops the video id: triggerTimer interval: 4000; running: false; repeat: false onTriggered: { if (video2.opacity == 1) mediaplayer1.stop() else mediaplayer2.stop() } } // Clock and Login Area Rectangle { id: rectangle anchors.fill: parent color: "transparent" MouseArea { id: loginScreenRoot anchors.fill: parent property bool uiVisible: true property bool blockUI: mainStack.depth > 1 || userListComponent.mainPasswordBox.text.length > 0 || inputPanel.keyboardActive || config.type !== "image" hoverEnabled: true drag.filterChildren: true onPressed: uiVisible = true; onPositionChanged: uiVisible = true; onUiVisibleChanged: { if (blockUI) { fadeoutTimer.running = false; } else if (uiVisible) { fadeoutTimer.restart(); } } onBlockUIChanged: { if (blockUI) { fadeoutTimer.running = false; uiVisible = true; } else { fadeoutTimer.restart(); } } Keys.onPressed: { uiVisible = true; event.accepted = false; } //takes one full minute for the ui to disappear Timer { id: fadeoutTimer running: true interval: 60000 onTriggered: { if (!loginScreenRoot.blockUI) { loginScreenRoot.uiVisible = false; } } } QQC2.StackView { id: mainStack anchors.fill: parent // If true (depends on the style and environment variables), hover events are always accepted // and propagation stopped. This means the parent MouseArea won't get them and the UI won't be shown. // Disable capturing those events while the UI is hidden to avoid that, while still passing events otherwise. // One issue is that while the UI is visible, mouse activity won't keep resetting the timer, but when it // finally expires, the next event should immediately set uiVisible = true again. hoverEnabled: loginScreenRoot.uiVisible ? undefined : false focus: true //StackView is an implicit focus scope, so we need to give this focus so the item inside will have it Timer { //SDDM has a bug in 0.13 where even though we set the focus on the right item within the window, the window doesn't have focus //it is fixed in 6d5b36b28907b16280ff78995fef764bb0c573db which will be 0.14 //we need to call "window->activate()" *After* it's been shown. We can't control that in QML so we use a shoddy timer //it's been this way for all Plasma 5.x without a huge problem running: true repeat: false interval: 200 onTriggered: mainStack.forceActiveFocus() } initialItem: Login { id: userListComponent userListModel: userModel loginScreenUiVisible: loginScreenRoot.uiVisible userListCurrentIndex: userModel.lastIndex >= 0 ? userModel.lastIndex : 0 lastUserName: userModel.lastUser showUserList: { if ( !userListModel.hasOwnProperty("count") || !userListModel.hasOwnProperty("disableAvatarsThreshold")) return (userList.y + mainStack.y) > 0 if ( userListModel.count === 0 ) return false if ( userListModel.hasOwnProperty("containsAllUsers") && !userListModel.containsAllUsers ) return false return userListModel.count <= userListModel.disableAvatarsThreshold && (userList.y + mainStack.y) > 0 } } Behavior on opacity { OpacityAnimator { duration: PlasmaCore.Units.longDuration } } readonly property real zoomFactor: 3 popEnter: Transition { ScaleAnimator { from: mainStack.zoomFactor to: 1 duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } OpacityAnimator { from: 0 to: 1 duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } } popExit: Transition { ScaleAnimator { from: 1 to: 0 duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } OpacityAnimator { from: 1 to: 0 duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } } pushEnter: Transition { ScaleAnimator { from: 0 to: 1 duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } OpacityAnimator { from: 0 to: 1 duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } } pushExit: Transition { ScaleAnimator { from: 1 to: mainStack.zoomFactor duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } OpacityAnimator { from: 1 to: 0 duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) easing.type: Easing.OutCubic } } } Loader { id: inputPanel state: "hidden" property bool keyboardActive: item ? item.active : false onKeyboardActiveChanged: { if (keyboardActive) { state = "visible" // Otherwise the password field loses focus and virtual keyboard // keystrokes get eaten userListComponent.mainPasswordBox.forceActiveFocus(); } else { state = "hidden"; } } source: Qt.platform.pluginName.includes("wayland") ? "components/VirtualKeyboard_wayland.qml" : "components/VirtualKeyboard.qml" anchors { left: parent.left right: parent.right } function showHide() { state = state == "hidden" ? "visible" : "hidden"; } states: [ State { name: "visible" PropertyChanges { target: mainStack y: Math.min(0, root.height - inputPanel.height - userListComponent.visibleBoundary) } }, State { name: "hidden" PropertyChanges { target: mainStack y: 0 } } ] transitions: [ Transition { from: "hidden" to: "visible" SequentialAnimation { ParallelAnimation { NumberAnimation { target: mainStack property: "y" duration: PlasmaCore.Units.longDuration easing.type: Easing.InOutQuad } } } }, Transition { from: "visible" to: "hidden" SequentialAnimation { ParallelAnimation { NumberAnimation { target: mainStack property: "y" duration: PlasmaCore.Units.longDuration easing.type: Easing.InOutQuad } } } } ] } Component { id: userPromptComponent Login { showUsernamePrompt: true loginScreenUiVisible: loginScreenRoot.uiVisible fontSize: parseInt(config.fontSize) + 2 // using a model rather than a QObject list to avoid QTBUG-75900 userListModel: ListModel { ListElement { name: "" iconSource: "" } Component.onCompleted: { // as we can't bind inside ListElement setProperty(0, "name", i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Type in Username and Password")); } } } } Image { id: logo visible: config.showlogo == "shown" source: config.logo anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: footer.top anchors.bottomMargin: PlasmaCore.Units.largeSpacing asynchronous: true sourceSize.height: height opacity: loginScreenRoot.uiVisible ? 0 : 1 fillMode: Image.PreserveAspectFit height: Math.round(PlasmaCore.Units.gridUnit * 3.5) Behavior on opacity { // OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1)" NumberAnimation { duration: PlasmaCore.Units.longDuration easing.type: Easing.InOutQuad } } } //Footer RowLayout { id: footer anchors { bottom: parent.bottom left: parent.left right: parent.right margins: PlasmaCore.Units.smallSpacing } Behavior on opacity { OpacityAnimator { duration: PlasmaCore.Units.longDuration } } PlasmaComponents3.ToolButton { text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to show/hide virtual keyboard", "Virtual Keyboard") font.pointSize: config.fontSize icon.name: inputPanel.keyboardActive ? "input-keyboard-virtual-on" : "input-keyboard-virtual-off" onClicked: inputPanel.showHide() visible: inputPanel.status == Loader.Ready } KeyboardButton { font.pointSize: config.fontSize } SessionButton { id: sessionButton font.pointSize: config.fontSize } Item { Layout.fillWidth: true } Battery { fontSize: config.fontSize } } } Clock { id: clock y: parent.height * config.relativePositionY - clock.height / 2 x: parent.width * config.relativePositionX - clock.width / 2 } } Component.onCompleted: { // Set Focus /* if (username_input_box.text == "") */ /* username_input_box.focus = true */ /* else */ /* password_input_box.focus = true */ video1.focus = true // load and randomize playlist var time = parseInt(new Date().toLocaleTimeString(Qt.locale(),'h')) if ( time >= 5 && time <= 17 ) { playlist1.load(Qt.resolvedUrl(config.background_vid_day), 'm3u') playlist2.load(Qt.resolvedUrl(config.background_vid_day), 'm3u') image1.source = config.background_img_day } else { playlist1.load(Qt.resolvedUrl(config.background_vid_night), 'm3u') playlist2.load(Qt.resolvedUrl(config.background_vid_night), 'm3u') image1.source = config.background_img_night } for (var k = 0; k < Math.ceil(Math.random() * 10) ; k++) { playlist1.shuffle() playlist2.shuffle() } } }