feat(GODT-2792): Implement display of question set for bug report.

This commit is contained in:
Romain LE JEUNE
2023-07-24 16:16:44 +02:00
committed by Romain Le Jeune
parent f0e2688a8e
commit 80add80be2
11 changed files with 545 additions and 13 deletions

View File

@ -6,7 +6,11 @@
<file>qml/Banner.qml</file>
<file>qml/Bridge.qml</file>
<file>qml/bridgeqml.qmlproject</file>
<file>qml/BugCategoryView.qml</file>
<file>qml/BugQuestionView.qml</file>
<file>qml/BugReportFlow.qml</file>
<file>qml/BugReportView.qml</file>
<file>qml/CategoryItem.qml</file>
<file>qml/Configuration.qml</file>
<file>qml/ConfigurationItem.qml</file>
<file>qml/ContentWrapper.qml</file>
@ -95,6 +99,7 @@
<file>qml/Proton/TextArea.qml</file>
<file>qml/Proton/TextField.qml</file>
<file>qml/Proton/Toggle.qml</file>
<file>qml/QuestionItem.qml</file>
<file>qml/SettingsItem.qml</file>
<file>qml/SettingsView.qml</file>
<file>qml/SetupGuide.qml</file>
@ -104,4 +109,4 @@
<file>qml/Status.qml</file>
<file>qml/WelcomeGuide.qml</file>
</qresource>
</RCC>
</RCC>

View File

@ -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 <https://www.gnu.org/licenses/>.
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
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
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();
}
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
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();
}
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
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
}
}

View File

@ -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 {
}
}
}
}
}

View File

@ -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")

View File

@ -35,9 +35,6 @@ ApplicationWindow {
root.requestActivate();
}
}
function showBugReportAndPrefill(message) {
contentWrapper.showBugReportAndPrefill(message);
}
function showHelp() {
contentWrapper.showHelp();
}

View File

@ -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 <https://www.gnu.org/licenses/>.
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
}
}

View File

@ -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