mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 12:46:46 +00:00
feat(GODT-2792): Implement display of question set for bug report.
This commit is contained in:
committed by
Romain Le Jeune
parent
f0e2688a8e
commit
80add80be2
@ -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>
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
127
internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml
Normal file
127
internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
72
internal/frontend/bridge-gui/bridge-gui/qml/CategoryItem.qml
Normal file
72
internal/frontend/bridge-gui/bridge-gui/qml/CategoryItem.qml
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
|
||||
@ -35,9 +35,6 @@ ApplicationWindow {
|
||||
root.requestActivate();
|
||||
}
|
||||
}
|
||||
function showBugReportAndPrefill(message) {
|
||||
contentWrapper.showBugReportAndPrefill(message);
|
||||
}
|
||||
function showHelp() {
|
||||
contentWrapper.showHelp();
|
||||
}
|
||||
|
||||
153
internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml
Normal file
153
internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user