diff --git a/internal/frontend/qml/AccountView.qml b/internal/frontend/qml/AccountView.qml index 2833bc13..7a92188f 100644 --- a/internal/frontend/qml/AccountView.qml +++ b/internal/frontend/qml/AccountView.qml @@ -40,195 +40,208 @@ Item { property int _lineWidth: 1 ScrollView { + id: scrollView clip: true anchors.fill: parent - ColumnLayout { - width: root.width - spacing: 0 + Item { + // can't use parent here because parent is not ScrollView (Flickable inside contentItem inside ScrollView) + width: scrollView.availableWidth + height: scrollView.availableHeight - Rectangle { - id: topRectangle - color: root.colorScheme.background_norm + implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin + // do not set implicitWidth because implicit width of ColumnLayout will be equal to maximum implicit width of + // internal items. And if one of internal items would be a Text or Label - implicit width of those is always + // equal to non-wrapped text (i.e. one line only). That will lead to enabling horizontal scroll when not needed + implicitWidth: width - implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin - implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin + ColumnLayout { + spacing: 0 - Layout.fillWidth: true + anchors.fill: parent - ColumnLayout { - spacing: root._spacing + Rectangle { + id: topRectangle + color: root.colorScheme.background_norm - anchors.fill: parent - anchors.leftMargin: root._leftMargin - anchors.rightMargin: root._rightMargin - anchors.topMargin: root._topMargin - anchors.bottomMargin: root._bottomMargin + implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin + implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin + Layout.fillWidth: true - RowLayout { // account delegate with action buttons - Layout.fillWidth: true + ColumnLayout { + spacing: root._spacing - AccountDelegate { + anchors.fill: parent + anchors.leftMargin: root._leftMargin + anchors.rightMargin: root._rightMargin + anchors.topMargin: root._topMargin + anchors.bottomMargin: root._bottomMargin + + RowLayout { // account delegate with action buttons Layout.fillWidth: true + + AccountDelegate { + Layout.fillWidth: true + colorScheme: root.colorScheme + user: root.user + type: AccountDelegate.LargeView + enabled: root.user ? root.user.loggedIn : false + } + + Button { + Layout.alignment: Qt.AlignTop + colorScheme: root.colorScheme + text: qsTr("Sign out") + secondary: true + visible: root.user ? root.user.loggedIn : false + onClicked: { + if (!root.user) return + root.user.logout() + } + } + + Button { + Layout.alignment: Qt.AlignTop + colorScheme: root.colorScheme + text: qsTr("Sign in") + secondary: true + visible: root.user ? !root.user.loggedIn : false + onClicked: { + if (!root.user) return + root.parent.rightContent.showSignIn() + } + } + + Button { + Layout.alignment: Qt.AlignTop + colorScheme: root.colorScheme + icon.source: "icons/ic-trash.svg" + secondary: true + onClicked: { + if (!root.user) return + root.user.remove() + } + } + } + + Rectangle { + Layout.fillWidth: true + height: root._lineWidth + color: root.colorScheme.border_weak + } + + SettingsItem { colorScheme: root.colorScheme - user: root.user - type: AccountDelegate.LargeView + text: qsTr("Email clients") + actionText: qsTr("Configure") + description: qsTr("Proton Mail Bridge works with email clients that support IMAP/SMPT to send and receive messages. Using the mailbox details below, you can (re)configure your client at any point.") + type: SettingsItem.Button enabled: root.user ? root.user.loggedIn : false - } - - Button { - Layout.alignment: Qt.AlignTop - colorScheme: root.colorScheme - text: qsTr("Sign out") - secondary: true - visible: root.user ? root.user.loggedIn : false + visible: root.user ? !root.user.splitMode || root.user.addresses.length==1 : false + showSeparator: splitMode.visible onClicked: { if (!root.user) return - root.user.logout() + root.showSetupGuide(root.user, user.addresses[0]) } - } - Button { - Layout.alignment: Qt.AlignTop - colorScheme: root.colorScheme - text: qsTr("Sign in") - secondary: true - visible: root.user ? !root.user.loggedIn : false - onClicked: { - if (!root.user) return - root.parent.rightContent.showSignIn() - } - } - - Button { - Layout.alignment: Qt.AlignTop - colorScheme: root.colorScheme - icon.source: "icons/ic-trash.svg" - secondary: true - onClicked: { - if (!root.user) return - root.user.remove() - } - } - } - - Rectangle { - Layout.fillWidth: true - height: root._lineWidth - color: root.colorScheme.border_weak - } - - SettingsItem { - colorScheme: root.colorScheme - text: qsTr("Email clients") - actionText: qsTr("Configure") - description: qsTr("Proton Mail Bridge works with email clients that support IMAP/SMPT to send and receive messages. Using the mailbox details below, you can (re)configure your client at any point.") - type: SettingsItem.Button - enabled: root.user ? root.user.loggedIn : false - visible: root.user ? !root.user.splitMode || root.user.addresses.length==1 : false - showSeparator: splitMode.visible - onClicked: { - if (!root.user) return - root.showSetupGuide(root.user, user.addresses[0]) - } - - Layout.fillWidth: true - } - - SettingsItem { - id: splitMode - colorScheme: root.colorScheme - text: qsTr("Split addresses") - description: qsTr("Split addresses allows you to configure multiple email addresses individually. Changing its mode will require you to delete your accounts(s) from your email client and begin the setup process from scratch.") - type: SettingsItem.Toggle - checked: root.user ? root.user.splitMode : false - visible: root.user ? root.user.addresses.length > 1 : false - enabled: root.user ? root.user.loggedIn : false - showSeparator: addressSelector.visible - onClicked: { - if (!splitMode.checked){ - root.notifications.askEnableSplitMode(user) - } else { - root.user.toggleSplitMode(!splitMode.checked) - } - } - - Layout.fillWidth: true - } - - RowLayout { - Layout.fillWidth: true - enabled: root.user ? root.user.loggedIn : false - visible: root.user ? root.user.splitMode : false - - ComboBox { - id: addressSelector - colorScheme: root.colorScheme Layout.fillWidth: true - model: root.user ? root.user.addresses : null } - Button { + SettingsItem { + id: splitMode colorScheme: root.colorScheme - text: qsTr("Configure") - secondary: true + text: qsTr("Split addresses") + description: qsTr("Split addresses allows you to configure multiple email addresses individually. Changing its mode will require you to delete your accounts(s) from your email client and begin the setup process from scratch.") + type: SettingsItem.Toggle + checked: root.user ? root.user.splitMode : false + visible: root.user ? root.user.addresses.length > 1 : false + enabled: root.user ? root.user.loggedIn : false + showSeparator: addressSelector.visible onClicked: { - if (!root.user) return - root.showSetupGuide(root.user, addressSelector.displayText) + if (!splitMode.checked){ + root.notifications.askEnableSplitMode(user) + } else { + root.user.toggleSplitMode(!splitMode.checked) + } + } + + Layout.fillWidth: true + } + + RowLayout { + Layout.fillWidth: true + enabled: root.user ? root.user.loggedIn : false + visible: root.user ? root.user.splitMode : false + + ComboBox { + id: addressSelector + colorScheme: root.colorScheme + Layout.fillWidth: true + model: root.user ? root.user.addresses : null + } + + Button { + colorScheme: root.colorScheme + text: qsTr("Configure") + secondary: true + onClicked: { + if (!root.user) return + root.showSetupGuide(root.user, addressSelector.displayText) + } } } } } - } - Rectangle { - color: root.colorScheme.background_weak + Rectangle { + color: root.colorScheme.background_weak - implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin - implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin + implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin + implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin - Layout.fillWidth: true + Layout.fillWidth: true - ColumnLayout { - id: configuration + ColumnLayout { + id: configuration - anchors.fill: parent - anchors.leftMargin: root._leftMargin - anchors.rightMargin: root._rightMargin - anchors.topMargin: root._detailsTopMargin - anchors.bottomMargin: root._spacing + anchors.fill: parent + anchors.leftMargin: root._leftMargin + anchors.rightMargin: root._rightMargin + anchors.topMargin: root._detailsTopMargin + anchors.bottomMargin: root._spacing - spacing: root._spacing - visible: root.user ? root.user.loggedIn : false + spacing: root._spacing + visible: root.user ? root.user.loggedIn : false - property string currentAddress: addressSelector.displayText + property string currentAddress: addressSelector.displayText - Label { - colorScheme: root.colorScheme - text: qsTr("Mailbox details") - type: Label.Body_semibold - } + Label { + colorScheme: root.colorScheme + text: qsTr("Mailbox details") + type: Label.Body_semibold + } - Configuration { - colorScheme: root.colorScheme - title: qsTr("IMAP") - hostname: root.backend.hostname - port: root.backend.portIMAP.toString() - username: configuration.currentAddress - password: root.user ? root.user.password : "" - security: "STARTTLS" - } + Configuration { + colorScheme: root.colorScheme + title: qsTr("IMAP") + hostname: root.backend.hostname + port: root.backend.portIMAP.toString() + username: configuration.currentAddress + password: root.user ? root.user.password : "" + security: "STARTTLS" + } - Configuration { - colorScheme: root.colorScheme - title: qsTr("SMTP") - hostname : root.backend.hostname - port : root.backend.portSMTP.toString() - username : configuration.currentAddress - password : root.user ? root.user.password : "" - security : root.backend.useSSLforSMTP ? "SSL" : "STARTTLS" + Configuration { + colorScheme: root.colorScheme + title: qsTr("SMTP") + hostname : root.backend.hostname + port : root.backend.portSMTP.toString() + username : configuration.currentAddress + password : root.user ? root.user.password : "" + security : root.backend.useSSLforSMTP ? "SSL" : "STARTTLS" + } } } } diff --git a/internal/frontend/qml/BugReportView.qml b/internal/frontend/qml/BugReportView.qml index 08739ba1..7e6cc4f4 100644 --- a/internal/frontend/qml/BugReportView.qml +++ b/internal/frontend/qml/BugReportView.qml @@ -24,6 +24,8 @@ import Proton 4.0 SettingsView { id: root + fillHeight: true + property var selectedAddress Label { @@ -41,7 +43,8 @@ SettingsView { label: qsTr("Description") colorScheme: root.colorScheme Layout.fillWidth: true - Layout.minimumHeight: 100 + Layout.fillHeight: true + Layout.minimumHeight: heightForLinesVisible(4) hint: description.text.length + "/" + _maxLength placeholderText: qsTr("Tell us what went wrong or isn't working (min. %1 characters).").arg(_minLength) @@ -66,6 +69,11 @@ SettingsView { KeyNavigation.priority: KeyNavigation.BeforeItem KeyNavigation.tab: address + + // set implicitHeight to explicit height because se don't + // want TextArea implicitHeight (which is height of all text) + // to be considered in SettingsView internal scroll view + implicitHeight: height } diff --git a/internal/frontend/qml/DebugWrapper.qml b/internal/frontend/qml/DebugWrapper.qml index 5b3088d4..0df15260 100644 --- a/internal/frontend/qml/DebugWrapper.qml +++ b/internal/frontend/qml/DebugWrapper.qml @@ -41,4 +41,15 @@ Rectangle { color: "black" colorScheme: ProtonStyle.currentStyle } + + Rectangle { + width: target.implicitWidth + height: target.implicitHeight + + color: "transparent" + border.color: "green" + border.width: 1 + //z: parent.z - 1 + z: 10000000 + } } diff --git a/internal/frontend/qml/GeneralSettings.qml b/internal/frontend/qml/GeneralSettings.qml index 64d4b030..9549b7ea 100644 --- a/internal/frontend/qml/GeneralSettings.qml +++ b/internal/frontend/qml/GeneralSettings.qml @@ -28,6 +28,8 @@ SettingsView { property bool _isAdvancedShown: false property var notifications + fillHeight: false + Label { colorScheme: root.colorScheme text: qsTr("Settings") diff --git a/internal/frontend/qml/HelpView.qml b/internal/frontend/qml/HelpView.qml index 9fade7a7..a3ec8ec4 100644 --- a/internal/frontend/qml/HelpView.qml +++ b/internal/frontend/qml/HelpView.qml @@ -24,6 +24,8 @@ import Proton 4.0 SettingsView { id: root + fillHeight: true + Label { colorScheme: root.colorScheme text: qsTr("Help") @@ -88,6 +90,12 @@ SettingsView { Layout.fillWidth: true } + // fill height so the footer label will be allways attached to the bottom + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + Label { Layout.alignment: Qt.AlignHCenter colorScheme: root.colorScheme diff --git a/internal/frontend/qml/LocalCacheSettings.qml b/internal/frontend/qml/LocalCacheSettings.qml index 69583b04..efd95242 100644 --- a/internal/frontend/qml/LocalCacheSettings.qml +++ b/internal/frontend/qml/LocalCacheSettings.qml @@ -26,6 +26,8 @@ import Proton 4.0 SettingsView { id: root + fillHeight: false + property var notifications property bool _diskCacheEnabled: true property string _diskCachePath: "/home" diff --git a/internal/frontend/qml/PortSettings.qml b/internal/frontend/qml/PortSettings.qml index cf25bff9..9785a501 100644 --- a/internal/frontend/qml/PortSettings.qml +++ b/internal/frontend/qml/PortSettings.qml @@ -25,6 +25,8 @@ import Proton 4.0 SettingsView { id: root + fillHeight: false + property bool _valuesChanged: ( imapField.text*1 !== root.backend.portIMAP || smtpField.text*1 !== root.backend.portSMTP diff --git a/internal/frontend/qml/Proton/TextArea.qml b/internal/frontend/qml/Proton/TextArea.qml index d834c562..6a992db4 100644 --- a/internal/frontend/qml/Proton/TextArea.qml +++ b/internal/frontend/qml/Proton/TextArea.qml @@ -124,11 +124,27 @@ FocusScope { function selectWord() { return control.selectWord() } function undo() { return control.undo() } + // Calculates the height of the component to make exactly lineNum visible in edit area + function heightForLinesVisible(lineNum) { + var totalHeight = 0 + totalHeight += headerLayout.height + totalHeight += footerLayout.height + totalHeight += control.topPadding + control.bottomPadding + totalHeight += lineNum * fontMetrics.height + return totalHeight + } + + FontMetrics { + id: fontMetrics + font: control.font + } + ColumnLayout { anchors.fill: parent spacing: 0 RowLayout { + id: headerLayout Layout.fillWidth: true spacing: 0 @@ -282,6 +298,7 @@ FocusScope { } RowLayout { + id: footerLayout Layout.fillWidth: true spacing: 0 diff --git a/internal/frontend/qml/SMTPSettings.qml b/internal/frontend/qml/SMTPSettings.qml index 24c11d79..66502109 100644 --- a/internal/frontend/qml/SMTPSettings.qml +++ b/internal/frontend/qml/SMTPSettings.qml @@ -25,6 +25,8 @@ import Proton 4.0 SettingsView { id: root + fillHeight: false + Label { colorScheme: root.colorScheme text: qsTr("SMTP connection mode") diff --git a/internal/frontend/qml/SettingsView.qml b/internal/frontend/qml/SettingsView.qml index 81c09521..cbcd940c 100644 --- a/internal/frontend/qml/SettingsView.qml +++ b/internal/frontend/qml/SettingsView.qml @@ -37,28 +37,47 @@ Item { property int _bottomMargin: 32 property int _spacing: 20 + // fillHeight indicates whether the SettingsView should fill all available explicit height set + property bool fillHeight: false ScrollView { + id: scrollView clip: true - width:root.width - height:root.height + anchors.fill: parent - contentWidth: content.width + content.anchors.leftMargin + content.anchors.rightMargin - contentHeight: content.height + content.anchors.topMargin + content.anchors.bottomMargin + Item { + // can't use parent here because parent is not ScrollView (Flickable inside contentItem inside ScrollView) + width: scrollView.availableWidth + height: scrollView.availableHeight - ColumnLayout { - id: content - spacing: root._spacing - width: root.width - (root._leftMargin + root._rightMargin) + implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin + // do not set implicitWidth because implicit width of ColumnLayout will be equal to maximum implicit width of + // internal items. And if one of internal items would be a Text or Label - implicit width of those is always + // equal to non-wrapped text (i.e. one line only). That will lead to enabling horizontal scroll when not needed + implicitWidth: width - anchors{ - top: parent.top - left: parent.left - topMargin: root._topMargin - bottomMargin: root._bottomMargin - leftMargin: root._leftMargin - rightMargin: root._rightMargin + ColumnLayout { + anchors.fill: parent + spacing: 0 + + ColumnLayout { + id: content + spacing: root._spacing + + Layout.fillWidth: true + + Layout.topMargin: root._topMargin + Layout.bottomMargin: root._bottomMargin + Layout.leftMargin: root._leftMargin + Layout.rightMargin: root._rightMargin + } + + Item { + id: filler + Layout.fillHeight: true + visible: !root.fillHeight + } } } }