Warning, /system/mycroft-gui/import/qml/AudioPlayer.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * Copyright 2019 by Aditya Mehra <aix.m@outlook.com>
0003  * Copyright 2019 by Marco Martin <mart@kde.org>
0004  *
0005  * Licensed under the Apache License, Version 2.0 (the "License");
0006  * you may not use this file except in compliance with the License.
0007  * You may obtain a copy of the License at
0008  *
0009  *    http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  *
0017  */
0018 
0019 import QtQuick 2.15
0020 import QtQuick.Controls 2.15 as Controls
0021 import QtQuick.Layouts 1.15
0022 import org.kde.kirigami 2.19 as Kirigami
0023 import Mycroft 1.0 as Mycroft
0024 import QtMultimedia
0025 
0026 Item {
0027     id: root
0028 
0029     property alias source: player.source
0030     property string status: "stop"
0031     property int switchWidth: Kirigami.Units.gridUnit * 22
0032     property alias thumbnail: albumimg.source
0033     property alias title: songtitle.text
0034     property bool progressBar: true
0035     property bool thumbnailVisible: true
0036     property bool titleVisible: true
0037     property var nextAction
0038     property var previousAction
0039     property alias currentState: player.status
0040     readonly property bool horizontal: width > switchWidth
0041 
0042     onEnabledChanged: syncStatusTimer.restart()
0043     onSourceChanged: syncStatusTimer.restart()
0044     Component.onCompleted: syncStatusTimer.restart()
0045 
0046     // Sometimes can't be restarted reliably immediately, put it in a timer
0047     onActiveFocusChanged: {
0048         if(activeFocus){
0049             playButton.forceActiveFocus();
0050         }
0051     }
0052 
0053     function msToTime(duration) {
0054         var seconds = parseInt((duration/1000)%60);
0055         var minutes = parseInt((duration/(1000*60))%60);
0056 
0057         minutes = (minutes < 10) ? "0" + minutes : minutes;
0058         seconds = (seconds < 10) ? "0" + seconds : seconds;
0059 
0060         return minutes + ":" + seconds;
0061     }
0062     
0063     Timer {
0064         id: syncStatusTimer
0065         interval: 0
0066         onTriggered: {
0067             if (enabled && status == "play") {
0068                 player.play();
0069             } else if (status == "stop") {
0070                 player.stop();
0071             } else {
0072                 player.pause();
0073             }
0074         }
0075     }
0076     MediaPlayer {
0077         id: player
0078         autoPlay: false
0079         readonly property string currentStatus: root.enabled ? root.status : "pause"
0080 
0081         onCurrentStatusChanged: {
0082             switch(currentStatus){
0083             case "stop":
0084                 player.stop();
0085                 break;
0086             case "pause":
0087                 player.pause()
0088                 break;
0089             case "play":
0090                 player.play()
0091                 break;
0092             }
0093         }
0094     }
0095 
0096 
0097     GridLayout {
0098         anchors {
0099             top: root.horizontal ? undefined : parent.top
0100             left: parent.left
0101             right: parent.right
0102             bottom: parent.bottom
0103         }
0104         columns: root.horizontal ? 2 : 1
0105         height: implicitHeight
0106 
0107         Image {
0108             id: albumimg
0109             fillMode: Image.PreserveAspectCrop
0110             visible: root.thumbnailVisible ? 1 : 0
0111             enabled: root.thumbnailVisible ? 1 : 0
0112             Layout.preferredWidth: root.horizontal ? Kirigami.Units.gridUnit * 10 : Kirigami.Units.gridUnit * 5
0113             Layout.preferredHeight: root.horizontal ? Kirigami.Units.gridUnit * 10 : Kirigami.Units.gridUnit * 5
0114             Layout.alignment: Qt.AlignHCenter
0115         }
0116 
0117         ColumnLayout {
0118             Layout.fillWidth: true
0119             Layout.fillHeight: true
0120             spacing: Kirigami.Units.largeSpacing
0121 
0122             Kirigami.Heading {
0123                 id: songtitle
0124                 text: title
0125                 level: root.horizontal ? 1 : 3
0126                 Layout.fillWidth: true
0127                 elide: Text.ElideRight
0128                 font.capitalization: Font.Capitalize
0129                 visible: root.titleVisible ? 1 : 0
0130                 enabled: root.titleVisible ? 1 : 0
0131             }
0132 
0133             RowLayout {
0134                 Layout.fillWidth: true
0135                 Layout.fillHeight: true
0136                 Layout.alignment: root.horizontal ? Qt.AlignLeft : Qt.AlignHCenter
0137                 spacing: Kirigami.Units.largeSpacing
0138 
0139                 Controls.RoundButton {
0140                     id: previousButton
0141                     Layout.minimumWidth: Kirigami.Units.iconSizes.smallMedium
0142                     Layout.minimumHeight: width
0143                     Layout.fillWidth: true
0144                     Layout.fillHeight: true
0145                     Layout.maximumWidth: Kirigami.Units.gridUnit * 3
0146                     Layout.maximumHeight: width
0147                     focus: false
0148                     icon.name: "media-seek-backward"
0149                     KeyNavigation.right: playButton
0150                     KeyNavigation.down: seekableslider
0151                     onClicked: {
0152                         triggerGuiEvent(previousAction, {})
0153                     }
0154                     
0155                     background: Rectangle {
0156                         Kirigami.Theme.colorSet: Kirigami.Theme.Button
0157                         radius: width
0158                         color: previousButton.activeFocus ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
0159                     }
0160                     
0161                     Keys.onReturnPressed: {
0162                         clicked()
0163                     }
0164                 }
0165 
0166                 Controls.RoundButton {
0167                     id: playButton
0168                     Layout.minimumWidth: Kirigami.Units.iconSizes.medium
0169                     Layout.minimumHeight: width
0170                     Layout.fillWidth: true
0171                     Layout.fillHeight: true
0172                     Layout.maximumWidth: Kirigami.Units.gridUnit * 4
0173                     Layout.maximumHeight: width
0174                     focus: false
0175                     icon.name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start"
0176                     KeyNavigation.left: previousButton
0177                     KeyNavigation.right: nextButton
0178                     KeyNavigation.down: seekableslider
0179                     onClicked: {
0180                         player.playbackState === MediaPlayer.PlayingState ? player.pause() : player.play()
0181                     }
0182                     
0183                     background: Rectangle {
0184                         Kirigami.Theme.colorSet: Kirigami.Theme.Button
0185                         radius: width
0186                         color: playButton.activeFocus ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
0187                     }
0188                     
0189                     Keys.onReturnPressed: {
0190                         clicked()
0191                     }
0192                 }
0193 
0194                 Controls.RoundButton {
0195                     id: nextButton
0196                     Layout.minimumWidth: Kirigami.Units.iconSizes.smallMedium
0197                     Layout.minimumHeight: width
0198                     Layout.fillWidth: true
0199                     Layout.fillHeight: true
0200                     Layout.maximumWidth: Kirigami.Units.gridUnit * 3
0201                     Layout.maximumHeight: width
0202                     focus: false
0203                     icon.name: "media-seek-forward"
0204                     KeyNavigation.left: playButton
0205                     KeyNavigation.down: seekableslider
0206                     onClicked: {
0207                         triggerGuiEvent(nextAction, {})
0208                     }
0209                     
0210                     background: Rectangle {
0211                         Kirigami.Theme.colorSet: Kirigami.Theme.Button
0212                         radius: width
0213                         color: nextButton.activeFocus ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
0214                     }
0215                     
0216                     Keys.onReturnPressed: {
0217                         clicked()
0218                     }
0219                 }
0220             }
0221 
0222             RowLayout {
0223                 spacing: Kirigami.Units.smallSpacing
0224                 Layout.fillWidth: true
0225                 visible: root.progressBar ? 1 : 0
0226                 enabled: root.progressBar ? 1 : 0
0227 
0228                 Controls.Slider {
0229                     id: seekableslider
0230                     to: player.duration
0231                     Layout.fillWidth: true
0232                     property bool sync: false
0233 
0234                     onValueChanged: {
0235                         if (!sync)
0236                             player.seek(value)
0237                     }
0238 
0239                     Connections {
0240                         target: player
0241                         onPositionChanged: {
0242                             seekableslider.sync = true
0243                             seekableslider.value = player.position
0244                             seekableslider.sync = false
0245                         }
0246                     }
0247                     
0248                     Keys.onLeftPressed: {
0249                         var l = 0
0250                         l = seekableslider.position - 0.05
0251                         seekableslider.value = seekableslider.valueAt(l);                        
0252                     }
0253                     
0254                     Keys.onRightPressed: {
0255                         var l = 0
0256                         l = seekableslider.position + 0.05
0257                         seekableslider.value = seekableslider.valueAt(l);
0258                     }
0259                 }
0260 
0261                 Controls.Label {
0262                     id: positionLabel
0263                     text: msToTime(player.position) + " / " + msToTime(player.duration)
0264                 }
0265             }
0266         }
0267     }
0268 }
0269