Fix register checking ui #LINQT-2332

Add accessibility focus ui on register country combobox and fix register page spacings and interaction #LINQT-2333
This commit is contained in:
Gaelle Braud 2026-01-13 13:25:09 +01:00
parent 7b7d382cc6
commit 2e7c250d8d
11 changed files with 699 additions and 686 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -357,10 +357,11 @@ void AccountManager::linkNewAccountUsingCode(const QString &code,
const std::string &errorMessage, const std::shared_ptr<const linphone::Dictionary> &parameterErrors) { const std::string &errorMessage, const std::shared_ptr<const linphone::Dictionary> &parameterErrors) {
if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkEmailUsingCode) { if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkEmailUsingCode) {
lInfo() << "[AccountManager] error linking email to account" << errorMessage; lInfo() << "[AccountManager] error linking email to account" << errorMessage;
emit linkingNewAccountWithCodeFailed(Utils::coreStringToAppString(errorMessage));
} else if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkPhoneNumberUsingCode) { } else if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkPhoneNumberUsingCode) {
lInfo() << "[AccountManager] error linking phone number to account" << errorMessage; lInfo() << "[AccountManager] error linking phone number to account" << errorMessage;
emit linkingNewAccountWithCodeFailed(Utils::coreStringToAppString(errorMessage));
} }
emit linkingNewAccountWithCodeFailed(Utils::coreStringToAppString(errorMessage));
}); });
if (registerType == RegisterType::Email) if (registerType == RegisterType::Email)
mAccountManagerServicesModel->linkEmailToAccountUsingCode(sipIdentityAddress, mAccountManagerServicesModel->linkEmailToAccountUsingCode(sipIdentityAddress,

View file

@ -3,12 +3,18 @@ import QtQuick.Controls.Basic as Control
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Effects import QtQuick.Effects
import Linphone import Linphone
import CustomControls 1.0
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
Control.ComboBox { Control.ComboBox {
id: mainItem id: mainItem
property string defaultCallingCode: "" property string defaultCallingCode: ""
property bool enableBackgroundColors: false property bool enableBackgroundColors: false
onKeyboardFocusChanged: console.log("keyboard focus combobox", keyboardFocus)
property bool keyboardFocus: FocusHelper.keyboardFocus
property color keyboardFocusedBorderColor: DefaultStyle.main2_900
property real borderWidth: Utils.getSizeWithScreenRatio(1)
property real keyboardFocusedBorderWidth: Utils.getSizeWithScreenRatio(3)
property string text: combobox.model.getAt(combobox.currentIndex) ? combobox.model.getAt(combobox.currentIndex).countryCallingCode : "" property string text: combobox.model.getAt(combobox.currentIndex) ? combobox.model.getAt(combobox.currentIndex).countryCallingCode : ""
currentIndex: phoneNumberModel.count > 0 ? Math.max(0, phoneNumberModel.findIndexByCountryCallingCode(defaultCallingCode)) : -1 currentIndex: phoneNumberModel.count > 0 ? Math.max(0, phoneNumberModel.findIndexByCountryCallingCode(defaultCallingCode)) : -1
Accessible.name: mainItem.Accessible.name Accessible.name: mainItem.Accessible.name
@ -19,13 +25,16 @@ Control.ComboBox {
anchors.fill: parent anchors.fill: parent
radius: Utils.getSizeWithScreenRatio(63) radius: Utils.getSizeWithScreenRatio(63)
color: mainItem.enableBackgroundColor ? DefaultStyle.grey_100 : "transparent" color: mainItem.enableBackgroundColor ? DefaultStyle.grey_100 : "transparent"
border.color: mainItem.enableBackgroundColors border.color: mainItem.keyboardFocus
? (mainItem.errorMessage.length > 0 ? mainItem.keyboardFocusedBorderColor
? DefaultStyle.danger_500_main : mainItem.enableBackgroundColors
: textField.activeFocus ? (mainItem.errorMessage.length > 0
? DefaultStyle.main1_500_main ? DefaultStyle.danger_500_main
: DefaultStyle.grey_200) : mainItem.activeFocus || textField.activeFocus
: "transparent" ? DefaultStyle.main1_500_main
: DefaultStyle.grey_200)
: "transparent"
border.width: mainItem.keyboardFocus ? mainItem.keyboardFocusedBorderWidth : mainItem.borderWidth
} }
contentItem: RowLayout { contentItem: RowLayout {
readonly property var currentItem: combobox.model.getAt(combobox.currentIndex) readonly property var currentItem: combobox.model.getAt(combobox.currentIndex)
@ -95,8 +104,6 @@ Control.ComboBox {
maximumFlickVelocity: 1500 maximumFlickVelocity: 1500
spacing: Utils.getSizeWithScreenRatio(10) spacing: Utils.getSizeWithScreenRatio(10)
highlight: Rectangle { highlight: Rectangle {
anchors.left: parent.left
anchors.right: parent.right
width: listView.width width: listView.width
height: listView.height height: listView.height
color: DefaultStyle.main2_300 color: DefaultStyle.main2_300

View file

@ -12,6 +12,7 @@ FocusScope{
property string labelIndication property string labelIndication
property string tooltip: "" property string tooltip: ""
property bool mandatory: false property bool mandatory: false
property int errorTextTopMargin: 0//
property alias errorTextItem: errorText property alias errorTextItem: errorText
property alias errorMessage: errorText.text property alias errorMessage: errorText.text
@ -85,7 +86,7 @@ FocusScope{
Item { Item {
Layout.preferredHeight: childrenRect.height Layout.preferredHeight: childrenRect.height
Layout.fillWidth: true Layout.fillWidth: true
StackLayout { FocusScope {
id: contentItem id: contentItem
height: childrenRect.height height: childrenRect.height
anchors.left: parent.left anchors.left: parent.left
@ -94,6 +95,7 @@ FocusScope{
TemporaryText { TemporaryText {
id: errorText id: errorText
anchors.top: contentItem.bottom anchors.top: contentItem.bottom
anchors.topMargin: mainItem.errorTextTopMargin
color: DefaultStyle.danger_500_main color: DefaultStyle.danger_500_main
} }
} }

View file

@ -6,6 +6,7 @@ import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
Control.TextField { Control.TextField {
id: mainItem id: mainItem
property real inputSize: Utils.getSizeWithScreenRatio(100) property real inputSize: Utils.getSizeWithScreenRatio(100)
property bool isError: false
color: activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_500_main color: activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_500_main
validator: IntValidator{bottom: 0; top: 9} validator: IntValidator{bottom: 0; top: 9}
@ -34,7 +35,11 @@ Control.TextField {
Rectangle { Rectangle {
id: background id: background
border.width: Utils.getSizeWithScreenRatio(1) border.width: Utils.getSizeWithScreenRatio(1)
border.color: mainItem.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_500_main border.color: mainItem.isError
? DefaultStyle.danger_500_main
: mainItem.activeFocus
? DefaultStyle.main1_500_main
: DefaultStyle.main2_500_main
radius: mainItem.inputSize * 0.15 radius: mainItem.inputSize * 0.15
width: mainItem.inputSize * 0.9 width: mainItem.inputSize * 0.9
height: mainItem.inputSize height: mainItem.inputSize

View file

@ -18,7 +18,10 @@ ColumnLayout {
readonly property string phoneNumber: textField.text readonly property string phoneNumber: textField.text
readonly property string countryCode: combobox.text readonly property string countryCode: combobox.text
property string defaultCallingCode property string defaultCallingCode
property bool keyboardFocus: FocusHelper.keyboardFocus property bool keyboardFocus: combobox.keyboardFocus || textField.keyboardFocus
property color keyboardFocusedBorderColor: DefaultStyle.main2_900
property real borderWidth: Utils.getSizeWithScreenRatio(1)
property real keyboardFocusedBorderWidth: Utils.getSizeWithScreenRatio(3)
spacing: Utils.getSizeWithScreenRatio(5) spacing: Utils.getSizeWithScreenRatio(5)
@ -26,7 +29,7 @@ ColumnLayout {
visible: label.length > 0 visible: label.length > 0
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: mainItem.label + (mainItem.mandatory ? "*" : "") text: mainItem.label + (mainItem.mandatory ? "*" : "")
color: (combobox.hasActiveFocus || textField.hasActiveFocus) ? DefaultStyle.main1_500_main : DefaultStyle.main2_600 color: (combobox.activeFocus || textField.activeFocus) ? DefaultStyle.main1_500_main : DefaultStyle.main2_600
font { font {
pixelSize: Typography.p2.pixelSize pixelSize: Typography.p2.pixelSize
weight: Typography.p2.weight weight: Typography.p2.weight
@ -36,25 +39,25 @@ ColumnLayout {
Control.Control { Control.Control {
Layout.preferredWidth: mainItem.width Layout.preferredWidth: mainItem.width
Layout.preferredHeight: Utils.getSizeWithScreenRatio(49) Layout.preferredHeight: Utils.getSizeWithScreenRatio(49)
leftPadding: Utils.getSizeWithScreenRatio(16)
background: Rectangle { background: Rectangle {
id: contentBackground id: contentBackground
anchors.fill: parent anchors.fill: parent
radius: Utils.getSizeWithScreenRatio(63) radius: Utils.getSizeWithScreenRatio(63)
color: DefaultStyle.grey_100 color: DefaultStyle.grey_100
border.color: mainItem.errorMessage.length > 0 border.color: mainItem.errorMessage.length > 0
? DefaultStyle.danger_500_main ? DefaultStyle.danger_500_main
: (textField.hasActiveFocus || combobox.hasActiveFocus) : (textField.activeFocus || combobox.activeFocus)
? DefaultStyle.main1_500_main ? DefaultStyle.main1_500_main
: DefaultStyle.grey_200 : DefaultStyle.grey_200
border.width: mainItem.borderWidth
} }
contentItem: RowLayout { contentItem: RowLayout {
CountryIndicatorCombobox { CountryIndicatorCombobox {
id: combobox id: combobox
implicitWidth: Utils.getSizeWithScreenRatio(110) implicitWidth: Utils.getSizeWithScreenRatio(110)
leftPadding: Utils.getSizeWithScreenRatio(16)
Layout.fillHeight: true Layout.fillHeight: true
defaultCallingCode: mainItem.defaultCallingCode defaultCallingCode: mainItem.defaultCallingCode
property bool keyboardFocus: FocusHelper.keyboardFocus
//: %1 prefix //: %1 prefix
Accessible.name: qsTr("prefix_phone_number_accessible_name").arg(mainItem.Accessible.name) Accessible.name: qsTr("prefix_phone_number_accessible_name").arg(mainItem.Accessible.name)
} }
@ -69,10 +72,15 @@ ColumnLayout {
id: textField id: textField
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: mainItem.placeholderText placeholderText: mainItem.placeholderText
background: Item{} background: Rectangle {
visible: textField.keyboardFocus
radius: Utils.getSizeWithScreenRatio(63)
color: "transparent"
border.color: mainItem.keyboardFocusedBorderColor
border.width: mainItem.keyboardFocusedBorderWidth
}
initialText: initialPhoneNumber initialText: initialPhoneNumber
validator: RegularExpressionValidator{ regularExpression: /[0-9]+/} validator: RegularExpressionValidator{ regularExpression: /[0-9]+/}
property bool keyboardFocus: FocusHelper.keyboardFocus
//: %1 number //: %1 number
Accessible.name: qsTr("number_phone_number_accessible_name").arg(mainItem.Accessible.name) Accessible.name: qsTr("number_phone_number_accessible_name").arg(mainItem.Accessible.name)
} }

View file

@ -14,6 +14,7 @@ LoginLayout {
property string address property string address
property string sipIdentityAddress property string sipIdentityAddress
property string code property string code
property alias errorMessage: codeItemLayout.errorMessage
property bool ctrlIsPressed property bool ctrlIsPressed
onCtrlIsPressedChanged: console.log("ctrl is pressed", ctrlIsPressed) onCtrlIsPressedChanged: console.log("ctrl is pressed", ctrlIsPressed)
titleContent: [ titleContent: [
@ -78,66 +79,71 @@ LoginLayout {
text = qsTr("assistant_account_creation_confirmation_explanation").arg(completeString).arg(address) text = qsTr("assistant_account_creation_confirmation_explanation").arg(completeString).arg(address)
} }
} }
RowLayout { FormItemLayout {
spacing: Utils.getSizeWithScreenRatio(45) id: codeItemLayout
Repeater { errorTextTopMargin: Utils.getSizeWithScreenRatio(5)
model: 4 contentItem: RowLayout {
id: repeater spacing: Utils.getSizeWithScreenRatio(45)
signal pasteRequested(string text) Repeater {
DigitInput { model: 4
id: digitInput id: repeater
required property int index signal pasteRequested(string text)
Layout.preferredWidth: width DigitInput {
Layout.preferredHeight: height id: digitInput
Connections { required property int index
target: repeater Layout.preferredWidth: width
function onPasteRequested(text) { Layout.preferredHeight: height
console.log("paste requested", text[digitInput.index]) isError: codeItemLayout.errorMessage !== ""
var test= text; Connections {
if (UtilsCpp.isInteger(text)) target: repeater
{ function onPasteRequested(text) {
digitInput.text = text[digitInput.index] console.log("paste requested", text[digitInput.index])
var test= text;
if (UtilsCpp.isInteger(text))
{
digitInput.text = text[digitInput.index]
}
} }
} }
} onTextChanged: {
onTextChanged: { console.log("text edited", text)
console.log("text edited", text) if (text.length > 0 ) {
if (text.length > 0 ) { mainItem.code = mainItem.code.slice(0, index) + text + mainItem.code.slice(index)
mainItem.code = mainItem.code.slice(0, index) + text + mainItem.code.slice(index) if (index < 3)
if (index < 3) nextItemInFocusChain(true).forceActiveFocus()
nextItemInFocusChain(true).forceActiveFocus() else {
else { mainItem.sendCode(mainItem.code)
mainItem.sendCode(mainItem.code) mainItem.code = ""
mainItem.code = "" }
}
} else {
if (index > 0)
nextItemInFocusChain(false).forceActiveFocus()
}
}
Keys.onPressed: (event) => {
if (event.key == Qt.Key_Backspace) {
if (text.length === 0) {
nextItemInFocusChain(false).forceActiveFocus()
event.accepted = true
} else { } else {
event.accepted = false if (index > 0)
nextItemInFocusChain(false).forceActiveFocus()
} }
} else if (event.key == Qt.Key_Control) {
mainItem.ctrlIsPressed = true
event.accepted = false
} else if (mainItem.ctrlIsPressed && event.key == Qt.Key_V) {
var clipboard = UtilsCpp.getClipboardText()
console.log("paste", clipboard)
repeater.pasteRequested(clipboard)
} else {
event.accepted = false
} }
} Keys.onPressed: (event) => {
Keys.onReleased: (event) => { if (event.key == Qt.Key_Backspace) {
if (event.key == Qt.Key_Control) { if (text.length === 0) {
mainItem.ctrlIsPressed = false nextItemInFocusChain(false).forceActiveFocus()
event.accepted = true event.accepted = true
} else {
event.accepted = false
}
} else if (event.key == Qt.Key_Control) {
mainItem.ctrlIsPressed = true
event.accepted = false
} else if (mainItem.ctrlIsPressed && event.key == Qt.Key_V) {
var clipboard = UtilsCpp.getClipboardText()
console.log("paste", clipboard)
repeater.pasteRequested(clipboard)
} else {
event.accepted = false
}
}
Keys.onReleased: (event) => {
if (event.key == Qt.Key_Control) {
mainItem.ctrlIsPressed = false
event.accepted = true
}
} }
} }
} }

View file

@ -128,15 +128,11 @@ LoginLayout {
ColumnLayout { ColumnLayout {
id: contentLayout id: contentLayout
anchors.left: parent.left
anchors.right: parent.right
spacing: Utils.getSizeWithScreenRatio(8) spacing: Utils.getSizeWithScreenRatio(8)
ColumnLayout { ColumnLayout {
id: formLayout id: formLayout
spacing: Utils.getSizeWithScreenRatio(24) spacing: Utils.getSizeWithScreenRatio(24)
RowLayout { RowLayout {
Layout.preferredHeight: usernameItem.height
spacing: Utils.getSizeWithScreenRatio(16)
FormItemLayout { FormItemLayout {
id: usernameItem id: usernameItem
label: qsTr("username") label: qsTr("username")
@ -152,6 +148,7 @@ LoginLayout {
} }
RowLayout { RowLayout {
spacing: Utils.getSizeWithScreenRatio(10) spacing: Utils.getSizeWithScreenRatio(10)
Layout.leftMargin: Utils.getSizeWithScreenRatio(16)
ComboBox { ComboBox {
Layout.preferredWidth: Utils.getSizeWithScreenRatio(210) Layout.preferredWidth: Utils.getSizeWithScreenRatio(210)
Layout.preferredHeight: Utils.getSizeWithScreenRatio(49) Layout.preferredHeight: Utils.getSizeWithScreenRatio(49)
@ -171,7 +168,8 @@ LoginLayout {
currentIndex: bar.currentIndex currentIndex: bar.currentIndex
PhoneNumberInput { PhoneNumberInput {
id: phoneNumberInput id: phoneNumberInput
Layout.preferredWidth: Utils.getSizeWithScreenRatio(346) Layout.fillWidth: false
Layout.preferredWidth: Utils.getSizeWithScreenRatio(390)
property string completePhoneNumber: countryCode + phoneNumber property string completePhoneNumber: countryCode + phoneNumber
//: "Numéro de téléphone" //: "Numéro de téléphone"
label: qsTr("phone_number") label: qsTr("phone_number")
@ -221,6 +219,7 @@ LoginLayout {
} }
FormItemLayout { FormItemLayout {
Layout.preferredWidth: Utils.getSizeWithScreenRatio(346) Layout.preferredWidth: Utils.getSizeWithScreenRatio(346)
Layout.leftMargin: Utils.getSizeWithScreenRatio(16)
//: "Confirmation mot de passe" //: "Confirmation mot de passe"
label: qsTr("assistant_account_register_password_confirmation") label: qsTr("assistant_account_register_password_confirmation")
mandatory: true mandatory: true
@ -235,13 +234,14 @@ LoginLayout {
} }
} }
} }
TemporaryText {
id: otherErrorText
Layout.fillWidth: true
Layout.topMargin: Utils.getSizeWithScreenRatio(5)
}
} }
} }
TemporaryText {
id: otherErrorText
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
// Layout.topMargin: Utils.getSizeWithScreenRatio(5)
}
// ColumnLayout { // ColumnLayout {
// spacing: Utils.getSizeWithScreenRatio(18) // spacing: Utils.getSizeWithScreenRatio(18)
// RowLayout { // RowLayout {
@ -276,6 +276,7 @@ LoginLayout {
Accessible.name: acceptCguAndPrivacyPolicyItem.associatedText Accessible.name: acceptCguAndPrivacyPolicyItem.associatedText
} }
Text { Text {
id: privacyLinkText
text: acceptCguAndPrivacyPolicyItem.associatedText text: acceptCguAndPrivacyPolicyItem.associatedText
onLinkActivated: (link) => Qt.openUrlExternally(link) onLinkActivated: (link) => Qt.openUrlExternally(link)
font { font {
@ -284,9 +285,17 @@ LoginLayout {
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.NoButton acceptedButtons: Qt.LeftButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: termsCheckBox.toggle() onClicked: (mouse) => {
mouse.accepted = false
if (parent.hoveredLink) {
privacyLinkText.linkActivated(privacyLinkText.linkAt(mouse.x, mouse.y))
}
else {
termsCheckBox.toggle()
}
}
} }
} }
} }

View file

@ -230,6 +230,7 @@ AbstractWindow {
Component { Component {
id: checkingPage id: checkingPage
RegisterCheckingPage { RegisterCheckingPage {
id: registerCheckingPage
onReturnToRegister: mainWindowStackView.pop() onReturnToRegister: mainWindowStackView.pop()
onSendCode: (code) => { onSendCode: (code) => {
RegisterPageCpp.linkNewAccountUsingCode(code, registerWithEmail, sipIdentityAddress) RegisterPageCpp.linkNewAccountUsingCode(code, registerWithEmail, sipIdentityAddress)
@ -238,15 +239,16 @@ AbstractWindow {
target: RegisterPageCpp target: RegisterPageCpp
function onLinkingNewAccountWithCodeSucceed() { function onLinkingNewAccountWithCodeSucceed() {
goToLogin() goToLogin()
//: "Compte créé" //: "Compte créé"
mainWindow.showInformationPopup(qsTr("assistant_register_success_title"), mainWindow.showInformationPopup(qsTr("assistant_register_success_title"),
//: "Le compte a été créé. Vous pouvez maintenant vous connecter" //: "Le compte a été créé. Vous pouvez maintenant vous connecter"
qsTr("assistant_register_success_message"), true) qsTr("assistant_register_success_message"), true)
} }
function onLinkingNewAccountWithCodeFailed(errorMessage) { function onLinkingNewAccountWithCodeFailed(errorMessage) {
//: "Erreur dans le code de validation" registerCheckingPage.errorMessage = ""
if (errorMessage.length === 0) errorMessage = qsTr("assistant_register_error_code") //: "Erreur dans le code de validation"
mainWindow.showInformationPopup(qsTr("information_popup_error_title"), errorMessage, false) if (errorMessage.length === 0) errorMessage = qsTr("assistant_register_error_code")
registerCheckingPage.errorMessage = errorMessage
} }
} }
} }