diff --git a/internal/frontend/bridge-gui/bridge-gui/Resources.qrc b/internal/frontend/bridge-gui/bridge-gui/Resources.qrc index e7521f98..a3d0ec7b 100644 --- a/internal/frontend/bridge-gui/bridge-gui/Resources.qrc +++ b/internal/frontend/bridge-gui/bridge-gui/Resources.qrc @@ -6,7 +6,11 @@ qml/Banner.qml qml/Bridge.qml qml/bridgeqml.qmlproject + qml/BugCategoryView.qml + qml/BugQuestionView.qml + qml/BugReportFlow.qml qml/BugReportView.qml + qml/CategoryItem.qml qml/Configuration.qml qml/ConfigurationItem.qml qml/ContentWrapper.qml @@ -95,6 +99,7 @@ qml/Proton/TextArea.qml qml/Proton/TextField.qml qml/Proton/Toggle.qml + qml/QuestionItem.qml qml/SettingsItem.qml qml/SettingsView.qml qml/SetupGuide.qml @@ -104,4 +109,4 @@ qml/Status.qml qml/WelcomeGuide.qml - + \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BugCategoryView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BugCategoryView.qml new file mode 100644 index 00000000..343aaea1 --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/qml/BugCategoryView.qml @@ -0,0 +1,51 @@ +// Copyright (c) 2023 Proton AG +// This file is part of Proton Mail Bridge. +// Proton Mail Bridge 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 3 of the License, or +// (at your option) any later version. +// Proton Mail Bridge 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 Proton Mail Bridge. If not, see . +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Proton + +SettingsView { + id: root + + signal categorySelected(int categoryId) + + fillHeight: true + + property var categories: ["category 1", "category 2"] + + Label { + Layout.fillWidth: true + colorScheme: root.colorScheme + text: qsTr("What's the issue?") + type: Label.Heading + } + + Repeater { + model: root.categories + + CategoryItem { + Layout.fillWidth: true + actionIcon: "/qml/icons/ic-chevron-right.svg" + colorScheme: root.colorScheme + text: modelData + + onClicked: root.categorySelected(index) + } + } + + // fill height so the footer label will always be attached to the bottom + Item { + Layout.fillHeight: true + } +} \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml new file mode 100644 index 00000000..3a18f03b --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml @@ -0,0 +1,127 @@ +// Copyright (c) 2023 Proton AG +// This file is part of Proton Mail Bridge. +// Proton Mail Bridge 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 3 of the License, or +// (at your option) any later version. +// Proton Mail Bridge 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 Proton Mail Bridge. If not, see . +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Proton + +SettingsView { + id: root + + signal resume + signal questionAnswered + + function setDefaultValue() { + } + + function next() { + + if (stackLayout.currentIndex >=(stackLayout.count - 1)) { + root.questionAnswered(); + } + else + { + ++stackLayout.currentIndex + root.setDefaultValue(); + } + } + + function previous() { + if (stackLayout.currentIndex === 0) { + root.resume() + } + else { + --stackLayout.currentIndex + root.setDefaultValue(); + } + } + + fillHeight: true + + onBack: { + root.previous(); + } + + onVisibleChanged: { + root.setDefaultValue(); + } + + Label { + Layout.fillWidth: true + colorScheme: root.colorScheme + text: qsTr("Give us more details") + type: Label.Heading + } + + Label { + Layout.fillWidth: true + colorScheme: root.colorScheme + text: qsTr("Step " + (stackLayout.currentIndex + 1) + " of " + stackLayout.count ) + type: Label.Caption + } + + StackLayout { + id: stackLayout + QuestionItem { + Layout.fillWidth: true + colorScheme: root.colorScheme + + text: "question 1" + type: QuestionItem.InputType.TextInput + mandatory: true + tips: "" + errorString: "please answer the question" + } + + QuestionItem { + Layout.fillWidth: true + colorScheme: root.colorScheme + + text: "question 2" + type: QuestionItem.InputType.Radio + mandatory: true + answerList: ["answer A", "answer B", "answer C","answer D"] + tips: "" + errorString: "please answer the question" + } + + QuestionItem { + Layout.fillWidth: true + colorScheme: root.colorScheme + + text: "question 3" + type: QuestionItem.InputType.Checkbox + mandatory: true + answerList: ["answer 1", "answer 2", "answer 3","answer 4"] + tips: "" + errorString: "please answer the question" + } + } + // fill height so the footer label will always be attached to the bottom + Item { + Layout.fillHeight: true + } + Button { + id: continueButton + colorScheme: root.colorScheme + enabled: !loading + text: qsTr("Continue") + + onClicked: { + if (stackLayout.children[stackLayout.currentIndex].validate()) { + next(); + } + + } + } +} \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BugReportFlow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BugReportFlow.qml new file mode 100644 index 00000000..21f0b911 --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/qml/BugReportFlow.qml @@ -0,0 +1,98 @@ +// Copyright (c) 2023 Proton AG +// This file is part of Proton Mail Bridge. +// Proton Mail Bridge 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 3 of the License, or +// (at your option) any later version. +// Proton Mail Bridge 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 Proton Mail Bridge. If not, see . +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Proton +import Notifications + +Item { + id: root + + property ColorScheme colorScheme + property string selectedAddress + property var titles: ["Category", "Description", "Confirmation"] + property int categoryId: -1 + + signal back + signal bugReportWasSent + + Rectangle { + anchors.fill: parent + + Layout.fillHeight: true // right content background + Layout.fillWidth: true + color: colorScheme.background_norm + + StackLayout { + id: bugReportFlow + + function showBugCategory() { + bugReportFlow.currentIndex = 0; + } + function showBugQuestion() { + bugReportFlow.currentIndex = 1; + } + function showBugReport() { + bugReportFlow.currentIndex = 2; + } + + anchors.fill: parent + + BugCategoryView { + // 0 + id: bugCategory + colorScheme: root.colorScheme + path: root.titles + currPath: 0 + + onBack: { + root.back() + } + onCategorySelected: function(categoryId){ + root.categoryId = categoryId + bugReportFlow.showBugQuestion(); + } + } + BugQuestionView { + // 1 + id: bugQuestion + colorScheme: root.colorScheme + path: root.titles + currPath: 1 + + onResume: { + bugReportFlow.showBugCategory(); + } + onQuestionAnswered: { + bugReportFlow.showBugReport(); + } + } + BugReportView { + // 2 + id: bugReport + colorScheme: root.colorScheme + selectedAddress: root.selectedAddress + path: root.titles + currPath: 2 + + onBack: { + bugReportFlow.showBugQuestion(); + } + onBugReportWasSent: { + root.bugReportWasSent(); + } + } + } + } +} \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BugReportView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BugReportView.qml index 1f7abc73..dbeaeabf 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/BugReportView.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/BugReportView.qml @@ -48,7 +48,7 @@ SettingsView { Label { colorScheme: root.colorScheme - text: qsTr("Report a problem") + text: qsTr("Send report") type: Label.Heading } TextArea { @@ -172,4 +172,4 @@ SettingsView { target: Backend } } -} +} \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/CategoryItem.qml b/internal/frontend/bridge-gui/bridge-gui/qml/CategoryItem.qml new file mode 100644 index 00000000..059c77ea --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/qml/CategoryItem.qml @@ -0,0 +1,72 @@ +// Copyright (c) 2023 Proton AG +// This file is part of Proton Mail Bridge. +// Proton Mail Bridge 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 3 of the License, or +// (at your option) any later version. +// Proton Mail Bridge 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 Proton Mail Bridge. If not, see . +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Proton + +Item { + id: root + + property var _bottomMargin: 20 + property var _lineHeight: 1 + property string actionIcon: "" + property var colorScheme + property bool showSeparator: true + property string text: "Text" + + signal clicked + + implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin + + RowLayout { + anchors.fill: parent + spacing: 16 + + Label { + id: mainLabel + colorScheme: root.colorScheme + text: root.text + type: Label.Body + Layout.fillHeight: true + Layout.fillWidth: true + Layout.preferredWidth: parent.width + Layout.alignment: Qt.AlignVCenter + Layout.bottomMargin: root._bottomMargin + wrapMode: Text.WordWrap + } + Button { + id: button + Layout.alignment: Qt.AlignVCenter + Layout.bottomMargin: root._bottomMargin + colorScheme: root.colorScheme + icon.source: root.actionIcon + text: "" + secondary: true + visible: root.actionIcon !== "" + + onClicked: { + if (!root.loading) + root.clicked(); + } + } + } + Rectangle { + anchors.bottom: root.bottom + anchors.left: root.left + anchors.right: root.right + color: colorScheme.border_weak + height: root._lineHeight + visible: root.showSeparator + } +} \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml b/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml index eca31c53..b5224262 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml @@ -40,10 +40,6 @@ Item { } console.error("User with ID ", userID, " was not found in the account list"); } - function showBugReportAndPrefill(description) { - rightContent.showBugReport(); - bugReport.setDescription(description); - } function showHelp() { rightContent.showHelpView(); } @@ -437,7 +433,7 @@ Item { rightContent.showAccount(); } } - BugReportView { + BugReportFlow { // 8 id: bugReport colorScheme: root.colorScheme @@ -472,4 +468,4 @@ Item { } } } -} +} \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml index 969567ba..b0277748 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml @@ -76,7 +76,7 @@ SettingsView { SettingsItem { id: reportBug Layout.fillWidth: true - actionText: qsTr("Report a problem") + actionText: qsTr("Report problem") colorScheme: root.colorScheme description: qsTr("Something not working as expected? Let us know.") text: qsTr("Report a problem") diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml index a76c1a6a..a16ebc52 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml @@ -35,9 +35,6 @@ ApplicationWindow { root.requestActivate(); } } - function showBugReportAndPrefill(message) { - contentWrapper.showBugReportAndPrefill(message); - } function showHelp() { contentWrapper.showHelp(); } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml b/internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml new file mode 100644 index 00000000..712284f9 --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml @@ -0,0 +1,153 @@ +// Copyright (c) 2023 Proton AG +// This file is part of Proton Mail Bridge. +// Proton Mail Bridge 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 3 of the License, or +// (at your option) any later version. +// Proton Mail Bridge 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 Proton Mail Bridge. If not, see . +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Proton + +Item { + id: root + enum InputType { + TextInput = 1, + Radio, + Checkbox + } + + property var colorScheme + property string text: "" + property string tips: "" + property string errorString: "" + property bool error: false + property var type: QuestionItem.InputType.TextInput + property bool mandatory: true + property var answerList: ListModel{} + property string answer:{ + if (type === QuestionItem.InputType.TextInput) { + return textInput.text + } else if (type === QuestionItem.InputType.Radio) { + return selectionRadio.text + } else if (type === QuestionItem.InputType.Checkbox) { + return selectionCheckBox.text + } + return "" + } + + function validate() { + if (type === QuestionItem.InputType.TextInput) { + textInput.validate() + root.error = textInput.error + } else if (type === QuestionItem.InputType.Radio) { + selectionRadio.validate() + } else if (type === QuestionItem.InputType.Checkbox) { + selectionCheckBox.validate() + } + return !root.error + } + + implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin + + ColumnLayout { + anchors.fill: parent + spacing: 16 + + Label { + id: mainLabel + colorScheme: root.colorScheme + text: qsTr(root.text) + type: Label.Body + } + ColumnLayout { + spacing: 16 + TextArea { + id: textInput + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: root.type === QuestionItem.InputType.TextInput ? heightForLinesVisible(2) : 0 + colorScheme: root.colorScheme + + label: qsTr("Your answer") + placeholderText: qsTr(root.tips) + + validator: function (str) { + if (root.mandatory && str.length === 0) { + return root.errorStr; + } + return; + } + + visible: root.type === QuestionItem.InputType.TextInput + } + + ButtonGroup { + id: selectionRadio + property string text: { + return checkedButton ? checkedButton.text : ""; + } + + function validate() { + root.error = false + } + } + Repeater { + model: root.answerList + + RadioButton { + ButtonGroup.group: selectionRadio + colorScheme: root.colorScheme + text: modelData + visible: root.type === QuestionItem.InputType.Radio + } + } + ButtonGroup { + id: selectionCheckBox + exclusive: false + property string text: { + var str = ""; + for (var i = 0; i < buttons.length; ++i) { + if (buttons[i].checked) { + str += buttons[i].text + " "; + } + } + return str; + } + + function validate() { + root.error = false + } + } + Repeater { + model: root.answerList + + CheckBox { + ButtonGroup.group: selectionCheckBox + colorScheme: root.colorScheme + text: modelData + visible: root.type === QuestionItem.InputType.Checkbox + } + } + } + } + Label { + id: errorText + Layout.fillWidth: true + visible: root.error + color: root.colorScheme.signal_danger + colorScheme: root.colorScheme + text: root.errorString + type: Label.LabelType.Caption_semibold + } + // fill height so the footer label will always be attached to the bottom + Item { + Layout.fillHeight: true + } +} \ No newline at end of file diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SettingsView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SettingsView.qml index e4619052..06718b3a 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/SettingsView.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/SettingsView.qml @@ -29,6 +29,8 @@ Item { // fillHeight indicates whether the SettingsView should fill all available explicit height set property bool fillHeight: false default property alias items: content.children + property var path: ListModel{} + property var currPath: 0 signal back @@ -61,6 +63,37 @@ Item { Layout.rightMargin: root._rightMargin Layout.topMargin: root._topMargin spacing: root._spacing + ListView { + id: trackPath + Layout.fillWidth: true + Layout.topMargin: root._topMargin + Layout.bottomMargin: root._spacing + + interactive: false + orientation: ListView.Horizontal + model: path + + delegate: Item{ + width: children[0].width + children[0].spacing + RowLayout { + Label { + colorScheme: root.colorScheme + text: qsTr(modelData) + type: Label.Caption + color: index === currPath ? colorScheme.interaction_norm : colorScheme.text_hint + } + Label { + colorScheme: root.colorScheme + text: "/" + color: colorScheme.text_hint + type: Label.Caption + visible: index < (root.path.length - 1) + } + } + } + + visible: model.length > 0 + } } Item { id: filler