Warning, /system/mycroft-gui/application/main.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 * Copyright 2018 by Marco Martin <mart@kde.org>
0003 * Copyright 2018 David Edmundson <davidedmundson@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.Window 2.15
0021 import QtQuick.Layouts 1.15
0022 import QtQuick.Controls 2.15
0023 import QtQuick.Controls.Material 2.15
0024 import org.kde.kirigami 2.19 as Kirigami
0025 import Mycroft 1.0 as Mycroft
0026 import org.kde.private.mycroftgui 1.0 as MycroftGui
0027 import Qt5Compat.GraphicalEffects
0028
0029 Kirigami.ApplicationWindow {
0030 id: root
0031 visible: true
0032
0033 minimumHeight : deviceHeight || undefined
0034 maximumHeight : deviceHeight || undefined
0035 minimumWidth : deviceWidth || undefined
0036 maximumWidth : deviceWidth || undefined
0037 x: deviceWidth ? Screen.desktopAvailableHeight - width : undefined
0038 y: deviceHeight ? Screen.desktopAvailableHeight - height : undefined
0039
0040 color: "black"
0041 //HACK!! needs proper api in kirigami
0042 Component.onCompleted: {
0043 globalDrawer.handle.handleAnchor = handleAnchor;
0044
0045 // Maximize and auto connect if set
0046 if (deviceMaximized) {
0047 showMaximized()
0048 }
0049
0050 if (singleSkillHome.length > 0 && Mycroft.MycroftController.status === Mycroft.MycroftController.Open) {
0051 Mycroft.MycroftController.sendRequest(singleSkillHome, {});
0052 }
0053
0054 if(!isAndroid && Kirigami.Settings.isMobile){
0055 applicationSettings.usesRemoteSTT = true
0056 Mycroft.GlobalSettings.usesRemoteTTS = true
0057 }
0058 }
0059
0060 Connections {
0061 target: Mycroft.MycroftController
0062 function onStatusChanged(status) {
0063 if (singleSkillHome.length > 0 && Mycroft.MycroftController.status === Mycroft.MycroftController.Open) {
0064 Mycroft.MycroftController.sendRequest(singleSkillHome, {});
0065 }
0066 }
0067
0068 function onSpeechRequestedChanged(expectingResponse) {
0069 if(expectingResponse) {
0070 micButton.clicked()
0071 }
0072 }
0073
0074 function onSkillTimeoutReceived(skillidleid) {
0075 if(mainView.currentItem.contentItem.skillId() == skillidleid) {
0076 root.close()
0077 }
0078 }
0079 }
0080
0081 Connections {
0082 target: keyFilter
0083 function onGlobalBackReceived() {
0084 mainView.currentItem.backRequested()
0085 }
0086 }
0087
0088 // Uses Android's voice popup for speech recognition
0089 MycroftGui.SpeechIntent {
0090 id: speechIntent
0091 title: "Say something to Mycroft" // TODO i18n
0092 onSpeechRecognized: (text)=> {
0093 Mycroft.MycroftController.sendText(text)
0094 }
0095 //onRecognitionFailed: console.log("SPEECH FAILED")
0096 //onRecognitionCanceled: console.log("SPEECH CANCELED")
0097 //onNothingRecognized: console.log("SPEECH NOTHING")
0098 }
0099
0100 //HACK
0101 Connections {
0102 target: root.pageStack.layers
0103 onDepthChanged: {
0104 if (root.pageStack.layers.depth == 1) {
0105 globalDrawer.handle.handleAnchor = handleAnchor;
0106 } else {
0107 globalDrawer.handle.handleAnchor = null;
0108 }
0109 }
0110 }
0111
0112 globalDrawer: Kirigami.GlobalDrawer {
0113 bannerImageSource: "banner.png"
0114 handleVisible: !hideTextInput
0115 Kirigami.Theme.inherit: false
0116 Kirigami.Theme.colorSet: applicationSettings.darkMode ? Kirigami.Theme.Complementary : Kirigami.Theme.View
0117
0118 actions: [
0119 Kirigami.Action {
0120 text: "Hints"
0121 iconName: "help-hint"
0122 visible: !Kirigami.Settings.isMobile
0123 checked: pageStack.layers.currentItem.objectName == "hints"
0124 onTriggered: {
0125 if (checked) {
0126 pageStack.layers.pop(pageStack.layers.initialItem);
0127 } else if (pageStack.layers.depth > 1) {
0128 pageStack.layers.replace(Qt.resolvedUrl("HintsPage.qml"));
0129 } else {
0130 pageStack.layers.push(Qt.resolvedUrl("HintsPage.qml"));
0131 }
0132 }
0133 },
0134 Kirigami.Action {
0135 text: "Settings"
0136 iconName: "configure"
0137 checked: pageStack.layers.currentItem.objectName == "Settings"
0138 onTriggered: {
0139 if (checked) {
0140 pageStack.layers.pop(pageStack.layers.initialItem);
0141 } else if (pageStack.layers.depth > 1) {
0142 pageStack.layers.replace(Qt.resolvedUrl("SettingsPage.qml"));
0143 } else {
0144 pageStack.layers.push(Qt.resolvedUrl("SettingsPage.qml"));
0145 }
0146 }
0147 },
0148 Kirigami.Action {
0149 text: "About"
0150 iconName: "help-about"
0151 checked: pageStack.layers.currentItem.objectName == "About"
0152 onTriggered: {
0153 if (checked) {
0154 pageStack.layers.pop(pageStack.layers.initialItem);
0155 } else if (pageStack.layers.depth > 1) {
0156 pageStack.layers.replace(Qt.resolvedUrl("AboutPage.qml"));
0157 } else {
0158 pageStack.layers.push(Qt.resolvedUrl("AboutPage.qml"));
0159 }
0160 }
0161 }
0162 ]
0163
0164 Switch {
0165 id: nightSwitch
0166 visible: !Kirigami.Settings.isMobile
0167 text: "Dark Mode"
0168 checked: applicationSettings.darkMode
0169 onCheckedChanged: applicationSettings.darkMode = checked
0170 }
0171 }
0172
0173 Timer {
0174 interval: 20000
0175 running: Mycroft.GlobalSettings.autoConnect && Mycroft.MycroftController.status != Mycroft.MycroftController.Open
0176 triggeredOnStart: true
0177 onTriggered: {
0178 print("Trying to connect to Mycroft");
0179 Mycroft.MycroftController.start();
0180 }
0181 }
0182
0183 pageStack.globalToolBar.style: pageStack.layers.depth == 1 ? Kirigami.ApplicationHeaderStyle.None : Kirigami.ApplicationHeaderStyle.Auto
0184
0185 pageStack.initialPage: Kirigami.Page {
0186 leftPadding: 0
0187 rightPadding: 0
0188 topPadding: 0
0189 bottomPadding: 0
0190 onBackRequested: {
0191 if (mainView.active) {
0192 event.accepted = true;
0193 mainView.goBack();
0194 }
0195 }
0196 Rectangle {
0197 color: nightSwitch.checked ? "black" : Kirigami.Theme.backgroundColor
0198 rotation: globalScreenRotation || 0
0199 anchors.fill: parent
0200 Image {
0201 visible: singleSkill.length === 0
0202 source: "background.png"
0203 fillMode: Image.PreserveAspectFit
0204 anchors.fill: parent
0205 opacity: !mainView.currentItem
0206 Behavior on opacity {
0207 OpacityAnimator {
0208 duration: Kirigami.Units.longDuration
0209 easing.type: Easing.InQuad
0210 }
0211 }
0212 }
0213
0214 Popup {
0215 id: audioRecorder
0216 width: root.width - (Kirigami.Units.largeSpacing * 2)
0217 height: root.height / 2
0218 closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
0219 Kirigami.Theme.colorSet: nightSwitch.checked ? Kirigami.Theme.Complementary : Kirigami.Theme.View
0220 parent: root
0221 x: (root.width - width) / 2
0222 y: (root.height - height) / 2
0223
0224 background: Rectangle {
0225 color: Kirigami.Theme.backgroundColor
0226 radius: Kirigami.Units.smallSpacing * 0.25
0227 border.width: 1
0228 Kirigami.Theme.colorSet: nightSwitch.checked ? Kirigami.Theme.Complementary : Kirigami.Theme.View
0229 border.color: Qt.rgba(Kirigami.Theme.disabledTextColor.r, Kirigami.Theme.disabledTextColor.g, Kirigami.Theme.disabledTextColor.b, 0.7)
0230 }
0231
0232 RemoteStt {
0233 id: remoteSttInstance
0234 }
0235
0236 onOpenedChanged: {
0237 if(audioRecorder.opened){
0238 remoteSttInstance.record = true;
0239 } else {
0240 remoteSttInstance.record = false;
0241 }
0242 }
0243 }
0244
0245 Mycroft.SkillView {
0246 id: mainView
0247 activeSkills.whiteList: singleSkill.length > 0 ? singleSkill : null
0248 Kirigami.Theme.colorSet: nightSwitch.checked ? Kirigami.Theme.Complementary : Kirigami.Theme.View
0249 anchors.fill: parent
0250 }
0251
0252 Button {
0253 anchors.centerIn: parent
0254 text: "start"
0255 visible: Mycroft.MycroftController.status == Mycroft.MycroftController.Closed
0256 onClicked: (mouse)=> {
0257 Mycroft.MycroftController.start();
0258 }
0259 }
0260
0261 Mycroft.StatusIndicator {
0262 id: si
0263 //visible: false
0264 anchors {
0265 top: parent.top
0266 right: parent.right
0267 margins: Kirigami.Units.largeSpacing
0268 }
0269 z: 999
0270 }
0271
0272 Kirigami.Heading {
0273 id: inputQuery
0274 Kirigami.Theme.colorSet: mainView.Kirigami.Theme.colorSet
0275 anchors.right: si.left
0276 anchors.rightMargin: Kirigami.Units.largeSpacing
0277 anchors.verticalCenter: si.verticalCenter
0278 level: 3
0279 opacity: 0
0280 onTextChanged: {
0281 opacity = 1;
0282 utteranceTimer.restart();
0283 }
0284 Timer {
0285 id: utteranceTimer
0286 interval: 8000
0287 onTriggered: {
0288 inputQuery.text = "";
0289 inputQuery.opacity = 0
0290 }
0291 }
0292 Behavior on opacity {
0293 OpacityAnimator {
0294 duration: Kirigami.units.longDuration
0295 easing.type: Easing.InOutQuad
0296 }
0297 }
0298
0299 Connections {
0300 target: Mycroft.MycroftController
0301 function onIntentRecevied(type, data) {
0302 if(type == "recognizer_loop:utterance") {
0303 inputQuery.text = data.utterances[0]
0304 }
0305 }
0306 }
0307 }
0308 }
0309
0310 //Note: a custom control as ToolBar on Android has a funny color
0311 footer: Control {
0312 Kirigami.Theme.colorSet: nightSwitch.checked ? Kirigami.Theme.Complementary : Kirigami.Theme.Window
0313 visible: !hideTextInput
0314 height: hideTextInput ? 0 : implicitHeight
0315 implicitHeight: contentItem.implicitHeight + topPadding + bottomPadding
0316 contentItem: RowLayout {
0317 Item {
0318 id: handleAnchor
0319 Layout.fillHeight: true
0320 Layout.preferredWidth: height
0321 }
0322
0323 ToolButton {
0324 id: backButton
0325 Kirigami.Theme.colorSet: nightSwitch.checked ? Kirigami.Theme.Complementary : Kirigami.Theme.Window
0326 Layout.preferredWidth: handleAnchor.width
0327 Layout.fillHeight: true
0328 Layout.rightMargin: Kirigami.Units.smallSpacing
0329 enabled: !isAndroid && Kirigami.Settings.isMobile ? 1 : 0
0330 icon.name: "go-previous"
0331
0332 onClicked:(mouse)=> {
0333 mainView.currentItem.backRequested()
0334 }
0335 visible: !isAndroid && Kirigami.Settings.isMobile ? 1 : 0
0336 }
0337
0338
0339 TextField {
0340 id: qinput
0341 Layout.fillWidth: true
0342
0343 placeholderText: "Ask Mycroft..."
0344 onAccepted: {
0345 Mycroft.MycroftController.sendText(qinput.text)
0346 }
0347 focus: false
0348 Connections {
0349 target: speechIntent
0350 function onSpeechRecognized(text){
0351 qinput.text = text
0352 }
0353 }
0354 onFocusChanged: {
0355 if (focus) {
0356 selectAll();
0357 }
0358 }
0359 }
0360
0361 ToolButton {
0362 id: micButton
0363 Kirigami.Theme.colorSet: nightSwitch.checked ? Kirigami.Theme.Complementary : Kirigami.Theme.Window
0364 Layout.preferredWidth: handleAnchor.width
0365 Layout.fillHeight: true
0366 Layout.rightMargin: Kirigami.Units.smallSpacing
0367 icon.name: "audio-input-microphone"
0368
0369 onClicked: (mouse)=> {
0370 if(applicationSettings.usesRemoteSTT){
0371 audioRecorder.open()
0372 } else {
0373 speechIntent.start()
0374 }
0375 }
0376 visible: speechIntent.supported || applicationSettings.usesRemoteSTT
0377 }
0378 }
0379 background: Rectangle {
0380 color: Kirigami.Theme.backgroundColor
0381 LinearGradient {
0382 anchors {
0383 left: parent.left
0384 right: parent.right
0385 bottom: parent.top
0386 }
0387 implicitHeight: Kirigami.Units.gridUnit/2
0388
0389 start: Qt.point(0, height)
0390 end: Qt.point(0, 0)
0391 gradient: Gradient {
0392 GradientStop {
0393 position: 0.0
0394 color: Qt.rgba(0, 0, 0, 0.2)
0395 }
0396 GradientStop {
0397 position: 0.3
0398 color: Qt.rgba(0, 0, 0, 0.1)
0399 }
0400 GradientStop {
0401 position: 1.0
0402 color: "transparent"
0403 }
0404 }
0405 }
0406 }
0407 }
0408 }
0409 }