feat(GODT-2586): Two-columns layout for account details.

This commit is contained in:
Xavier Michelon
2023-04-21 10:20:32 +02:00
parent 3b297fa37b
commit ce5a559926
3 changed files with 97 additions and 108 deletions

View File

@ -27,67 +27,55 @@ Item {
property var notifications
property var user
signal showSignIn()
signal showSignIn
signal showSetupGuide(var user, string address)
property int _leftMargin: 64
property int _rightMargin: 64
property int _contentWidth: 640
property int _topMargin: 32
property int _detailsTopMargin: 25
property int _bottomMargin: 12
property int _detailsMargin: 25
property int _spacing: 20
property int _lineWidth: 1
ScrollView {
id: scrollView
clip: true
property int _lineThickness: 1
property bool _connected: root.user ? root.user.state === EUserState.Connected : false
Rectangle {
anchors.fill: parent
Component.onCompleted: contentItem.boundsBehavior = Flickable.StopAtBounds // Disable the springy effect when scroll reaches top/bottom.
color: root.colorScheme.background_weak
Item {
// can't use parent here because parent is not ScrollView (Flickable inside contentItem inside ScrollView)
width: scrollView.availableWidth
height: scrollView.availableHeight
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
ScrollView {
id: scrollView
anchors.fill: parent
Component.onCompleted: contentItem.boundsBehavior = Flickable.StopAtBounds
ColumnLayout {
id: topLevelColumnLayout
anchors.fill: parent
spacing: 0
anchors.fill: parent
Rectangle {
id: topRectangle
id: topArea
color: root.colorScheme.background_norm
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
clip: true
Layout.fillWidth: true
implicitHeight: childrenRect.height
ColumnLayout {
spacing: root._spacing
id: topLayout
width: _contentWidth
anchors.horizontalCenter: parent.horizontalCenter
spacing: _spacing
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
RowLayout {
// account delegate with action buttons
Layout.fillWidth: true
Layout.topMargin: _topMargin
AccountDelegate {
Layout.fillWidth: true
colorScheme: root.colorScheme
user: root.user
type: AccountDelegate.LargeView
enabled: root.user ? (root.user.state === EUserState.Connected) : false
enabled: _connected
}
Button {
@ -95,10 +83,11 @@ Item {
colorScheme: root.colorScheme
text: qsTr("Sign out")
secondary: true
visible: root.user ? (root.user.state === EUserState.Connected) : false
visible: _connected
onClicked: {
if (!root.user) return
root.user.logout()
if (!root.user)
return;
root.user.logout();
}
}
@ -109,8 +98,9 @@ Item {
secondary: true
visible: root.user ? (root.user.state === EUserState.SignedOut) : false
onClicked: {
if (!root.user) return
root.showSignIn()
if (!root.user)
return;
root.showSignIn();
}
}
@ -120,8 +110,9 @@ Item {
icon.source: "/qml/icons/ic-trash.svg"
secondary: true
onClicked: {
if (!root.user) return
root.notifications.askDeleteAccount(root.user)
if (!root.user)
return;
root.notifications.askDeleteAccount(root.user);
}
visible: root.user ? root.user.state !== EUserState.Locked : false
}
@ -129,7 +120,7 @@ Item {
Rectangle {
Layout.fillWidth: true
height: root._lineWidth
height: root._lineThickness
color: root.colorScheme.border_weak
}
@ -139,12 +130,12 @@ Item {
actionText: qsTr("Configure")
description: qsTr("Using the mailbox details below (re)configure your client.")
type: SettingsItem.Button
enabled: root.user ? root.user.state === EUserState.Connected : false
visible: root.user ? !root.user.splitMode || root.user.addresses.length==1 : false
visible: _connected && (!root.user.splitMode) || (root.user.addresses.length === 1)
showSeparator: splitMode.visible
onClicked: {
if (!root.user) return
root.showSetupGuide(root.user, user.addresses[0])
if (!root.user)
return;
root.showSetupGuide(root.user, user.addresses[0]);
}
Layout.fillWidth: true
@ -157,15 +148,14 @@ Item {
description: qsTr("Setup multiple email addresses individually.")
type: SettingsItem.Toggle
checked: root.user ? root.user.splitMode : false
visible: root.user ? root.user.addresses.length > 1 : false
enabled: root.user ? (root.user.state === EUserState.Connected) : false
visible: _connected && root.user.addresses.length > 1
showSeparator: addressSelector.visible
onClicked: {
if (!splitMode.checked){
root.notifications.askEnableSplitMode(user)
if (!splitMode.checked) {
root.notifications.askEnableSplitMode(user);
} else {
addressSelector.currentIndex = 0
root.user.toggleSplitMode(!splitMode.checked)
addressSelector.currentIndex = 0;
root.user.toggleSplitMode(!splitMode.checked);
}
}
@ -174,8 +164,8 @@ Item {
RowLayout {
Layout.fillWidth: true
enabled: root.user ? (root.user.state === EUserState.Connected) : false
visible: root.user ? root.user.splitMode : false
Layout.bottomMargin: _spacing
visible: _connected && root.user.splitMode
ComboBox {
id: addressSelector
@ -189,60 +179,68 @@ Item {
text: qsTr("Configure")
secondary: true
onClicked: {
if (!root.user) return
root.showSetupGuide(root.user, addressSelector.displayText)
if (!root.user)
return;
root.showSetupGuide(root.user, addressSelector.displayText);
}
}
}
Rectangle {
height: 0
} // just for some extra space before separator
}
}
Rectangle {
id: bottomArea
Layout.fillWidth: true
implicitHeight: bottomLayout.implicitHeight
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
Layout.fillWidth: true
ColumnLayout {
id: configuration
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.state === EUserState.Connected) : false
property string currentAddress: addressSelector.displayText
id: bottomLayout
width: _contentWidth
anchors.horizontalCenter: parent.horizontalCenter
spacing: _spacing
visible: _connected
Label {
Layout.topMargin: _detailsMargin
colorScheme: root.colorScheme
text: qsTr("Mailbox details")
type: Label.Body_semibold
}
Configuration {
colorScheme: root.colorScheme
title: qsTr("IMAP")
hostname: Backend.hostname
port: Backend.imapPort.toString()
username: configuration.currentAddress
password: root.user ? root.user.password : ""
security : Backend.useSSLForIMAP ? "SSL" : "STARTTLS"
}
RowLayout {
id: configuration
spacing: _spacing
Layout.fillWidth: true
Layout.fillHeight: true
Configuration {
colorScheme: root.colorScheme
title: qsTr("SMTP")
hostname : Backend.hostname
port : Backend.smtpPort.toString()
username : configuration.currentAddress
password : root.user ? root.user.password : ""
security : Backend.useSSLForSMTP ? "SSL" : "STARTTLS"
property string currentAddress: addressSelector.displayText
Configuration {
Layout.fillWidth: true
colorScheme: root.colorScheme
title: qsTr("IMAP")
hostname: Backend.hostname
port: Backend.imapPort.toString()
username: configuration.currentAddress
password: root.user ? root.user.password : ""
security: Backend.useSSLForIMAP ? "SSL" : "STARTTLS"
}
Configuration {
Layout.fillWidth: true
colorScheme: root.colorScheme
title: qsTr("SMTP")
hostname: Backend.hostname
port: Backend.smtpPort.toString()
username: configuration.currentAddress
password: root.user ? root.user.password : ""
security: Backend.useSSLForSMTP ? "SSL" : "STARTTLS"
}
}
}
}

View File

@ -61,8 +61,6 @@ Rectangle {
type: Label.Body_semibold
}
Item{}
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Hostname") ; value: root.hostname }
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Port") ; value: root.port }
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Username") ; value: root.username }

View File

@ -28,25 +28,18 @@ import "tests"
ApplicationWindow {
id: root
width: 960
height: 576
colorScheme: ProtonStyle.currentStyle
visible: true
minimumHeight: contentLayout.implicitHeight
minimumWidth: contentLayout.implicitWidth
colorScheme: ProtonStyle.currentStyle
property int _defaultWidth: 1080
property int _defaultHeight: 780
width: _defaultWidth
height: _defaultHeight
minimumWidth: _defaultWidth
property var notifications
// This is needed because on MacOS if first window shown is not transparent -
// all other windows of application will not have transparent background (black
// instead of transparency). In our case that mean that if MainWindow will be
// shown before StatusWindow - StatusWindow will not have transparent corners.
color: "transparent"
// show Setup Guide on every new user
Connections {
target: Backend.users