linphone-desktop/Linphone/view/Page/Form/Contact/ContactEdition.qml

466 lines
17 KiB
QML

import QtCore
import QtQuick
import QtQuick.Controls.Basic as Control
import QtQuick.Dialogs
import QtQuick.Effects
import QtQuick.Layouts
import Linphone
import UtilsCpp
import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
MainRightPanel {
id: mainItem
property FriendGui contact
Connections {
target: contact.core
function onIsSavedChanged() {
if (contact.core.isSaved) {
mainItem.closeEdition(contact.core.defaultFullAddress)
}
}
}
//: "Modifier contact"
property string title: qsTr("contact_editor_title")
//: "Enregistrer
property string saveButtonText: qsTr("save")
property string oldPictureUri
property int addressCount: 0
signal closeEdition(var redirectAddress)
Dialog {
id: confirmDialog
onAccepted: {
mainItem.contact.core.undo()
mainItem.closeEdition('')
}
width: Utils.getSizeWithScreenRatio(278)
//: "Les changements seront annulés. Souhaitez-vous continuer ?"
text: qsTr("contact_editor_dialog_cancel_change_message")
}
headerContentItem: RowLayout {
Text {
text: mainItem.title
font {
pixelSize: Utils.getSizeWithScreenRatio(20)
weight: Typography.h4.weight
}
}
Item{Layout.fillWidth: true}
Button {
style: ButtonStyle.noBackground
Layout.preferredWidth: Utils.getSizeWithScreenRatio(30)
Layout.preferredHeight: Utils.getSizeWithScreenRatio(30)
icon.source: AppIcons.closeX
icon.width: Utils.getSizeWithScreenRatio(24)
icon.height: Utils.getSizeWithScreenRatio(24)
//: Close %n
Accessible.name: qsTr("close_accessible_name").arg(mainItem.title)
onClicked: {
if (contact.core.isSaved) mainItem.closeEdition('')
else showConfirmationLambdaPopup("", qsTr("contact_editor_dialog_cancel_change_message"), "", function(confirmed) {
if (confirmed) {
mainItem.contact.core.undo()
mainItem.closeEdition('')
}
})
}
}
}
content: ContactLayout {
id: contactLayoutItem
anchors.fill: parent
contact: mainItem.contact
button.text: mainItem.saveButtonText
button.Keys.onPressed: (event) => {
if(event.key == Qt.Key_Up){
phoneNumberInput.forceActiveFocus(Qt.BacktabFocusReason)
event.accepted = true
}
}
// Let some time to GUI to set fields on losing focus.
Timer{
id: saveDelay
interval: 200
onTriggered: {
//: "Veuillez saisir un prénom ou un nom d'entreprise"
if (mainItem.contact.core.givenName.length === 0 && mainItem.contact.core.organization.length === 0) {
givenName.errorMessage = qsTr("contact_editor_mandatory_first_name_or_company_not_filled")
return
} else if (addressesList.count === 0 && phoneNumberList.count === 0) {
//: "Veuillez saisir une adresse ou un numéro de téléphone"
addressesErrorText.setText(qsTr("contact_editor_mandatory_address_or_number_not_filled"))
return
}
mainItem.contact.core.save()
}
}
button.onClicked: {
button.forceActiveFocus()
saveDelay.restart()
}
bannerContent: [
IconLabelButton {
id: addPictureButton
Layout.preferredWidth: width
visible: !mainItem.contact || mainItem.contact.core.pictureUri.length === 0
icon.source: AppIcons.camera
//: "Ajouter une image"
text: qsTr("contact_editor_add_image_label")
textSize: Typography.h4.pixelSize
textWeight: Typography.h4.weight
textColor: DefaultStyle.main2_700
hoveredTextColor: DefaultStyle.main2_800
pressedTextColor: DefaultStyle.main2_900
KeyNavigation.down: editButton.visible ? editButton : givenNameEdit
onClicked: fileDialog.open()
},
RowLayout {
visible: mainItem.contact && mainItem.contact.core.pictureUri.length != 0
Layout.alignment: Qt.AlignHCenter
spacing: Utils.getSizeWithScreenRatio(32)
IconLabelButton {
id: editButton
Layout.preferredWidth: width
icon.source: AppIcons.pencil
//: "Modifier"
text: qsTr("contact_details_edit")
textColor: DefaultStyle.main2_700
hoveredTextColor: DefaultStyle.main2_800
pressedTextColor: DefaultStyle.main2_900
textSize: Typography.h4.pixelSize
textWeight: Typography.h4.weight
KeyNavigation.right: removeButton
onClicked: fileDialog.open()
//: "Edit contact image"
Accessible.name: qsTr("edit_contact_image_accessible_name")
}
FileDialog {
id: fileDialog
currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
onAccepted: {
mainItem.oldPictureUri = mainItem.contact.core.pictureUri
var avatarPath = UtilsCpp.createAvatar( selectedFile )
if(avatarPath){
mainItem.contact.core.pictureUri = avatarPath
}
}
}
IconLabelButton {
id: removeButton
Layout.preferredWidth: width
icon.source: AppIcons.trashCan
//: "Supprimer"
text: qsTr("contact_details_delete")
textColor: DefaultStyle.main2_700
hoveredTextColor: DefaultStyle.main2_800
pressedTextColor: DefaultStyle.main2_900
textSize: Typography.h4.pixelSize
textWeight: Typography.h4.weight
KeyNavigation.left: editButton
onClicked: mainItem.contact.core.pictureUri = ""
//: "Delete contact image"
Accessible.name: qsTr("delete_contact_image_accessible_name")
}
},
Item{Layout.fillWidth: true}
]
content: Flickable {
id: editionLayout
contentWidth: Math.min(parent.width, Utils.getSizeWithScreenRatio(421))
width: parent.width
contentY: 0
MouseArea {
anchors.fill: parent
onClicked: {
editionLayout.forceActiveFocus()
}
}
signal ensureVisibleRequested(Item item)
function ensureVisible(r) {
if (contentY >= r.y)
contentY = r.y;
else if (contentY+height <= r.y+r.height)
contentY = r.y + r.height - height;
}
// Hack to ensure the empty textfield is really visible, because
// its y changes too late after the editingFinished is emitted
function connectOnce(sig, slot) {
var f = function() {
slot.apply(this, arguments)
sig.disconnect(f)
}
sig.connect(f)
}
ScrollBar.vertical: ScrollBar {
anchors.right: parent.right
visible: editionLayout.contentHeight > editionLayout.height
}
ScrollBar.horizontal: ScrollBar {
}
ColumnLayout {
spacing: Utils.getSizeWithScreenRatio(20)
anchors.left: parent.left
anchors.right: parent.right
FormItemLayout {
id: givenName
Layout.fillWidth: true
enableErrorText: true
//: "Prénom"
label: qsTr("contact_editor_first_name")
contentItem: TextField {
id: givenNameEdit
Layout.preferredHeight: Utils.getSizeWithScreenRatio(49)
initialText: contact.core.givenName
onTextEdited: {
contact.core.givenName = givenNameEdit.text
}
backgroundColor: DefaultStyle.grey_0
backgroundBorderColor: givenName.errorTextVisible ? DefaultStyle.danger_500_main : DefaultStyle.grey_200
KeyNavigation.up: editButton.visible ? editButton : addPictureButton
KeyNavigation.down: nameTextField
Accessible.name: qsTr("contact_editor_first_name")
}
}
FormItemLayout {
//: "Nom"
label: qsTr("contact_editor_last_name")
Layout.fillWidth: true
contentItem: TextField {
id: nameTextField
initialText: contact.core.familyName
onTextEdited: contact.core.familyName = text
backgroundColor: DefaultStyle.grey_0
KeyNavigation.up: givenNameEdit
KeyNavigation.down: companyTextField
Accessible.name: qsTr("contact_editor_last_name")
}
}
FormItemLayout {
//: "Entreprise"
label: qsTr("contact_editor_company")
Layout.fillWidth: true
contentItem: TextField {
id: companyTextField
initialText: contact.core.organization
onTextEdited: contact.core.organization = text
backgroundColor: DefaultStyle.grey_0
KeyNavigation.up: nameTextField
KeyNavigation.down: jobTextField
Accessible.name: qsTr("contact_editor_company")
}
}
FormItemLayout {
//: "Fonction"
label: qsTr("contact_editor_job_title")
Layout.fillWidth: true
contentItem: TextField {
id: jobTextField
initialText: contact.core.job
onTextEdited: contact.core.job = text
backgroundColor: DefaultStyle.grey_0
KeyNavigation.up: companyTextField
Keys.onPressed: (event) => {
if(event.key == Qt.Key_Down){
(addressesList.count > 0 ? addressesList.itemAt(0) : newAddressTextField).forceActiveFocus(Qt.TabFocusReason)
event.accepted = true
}
}
Accessible.name: qsTr("contact_editor_job_title")
}
}
Repeater {
id: addressesList
onCountChanged: mainItem.addressCount = count
model: VariantList {
model: mainItem.contact && mainItem.contact.core.addresses || []
}
delegate: FormItemLayout {
label: modelData.label
contentItem: RowLayout {
id: addressLayout
spacing: Utils.getSizeWithScreenRatio(10)
function updateFocus(event){
if(event.key == Qt.Key_Up){
(index - 1 >=0 ? addressesList.itemAt(index - 1) : jobTextField).forceActiveFocus(Qt.BacktabFocusReason)
event.accepted = true
}else if(event.key == Qt.Key_Down){
(index + 1 < addressesList.count ? addressesList.itemAt(index+1) : newAddressTextField).forceActiveFocus(Qt.TabFocusReason)
event.accepted = true
}else if(event.key == Qt.Key_Right && addressTextField.activeFocus){
removeAddressButton.forceActiveFocus(Qt.TabFocusReason)
}else if(event.key == Qt.Key_Left && removeAddressButton.activeFocus){
addressTextField.forceActiveFocus(Qt.BacktabFocusReason)
}
}
TextField {
id: addressTextField
Layout.preferredWidth: Utils.getSizeWithScreenRatio(421)
Layout.preferredHeight: height
onEditingFinished: {
var label = qsTr("sip_address")
if (text.length != 0) mainItem.contact.core.setAddressAt(index, label, text)
}
property string _initialText: modelData.address
initialText: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(_initialText) : _initialText
backgroundColor: DefaultStyle.grey_0
focus: true
KeyNavigation.right: removeAddressButton
Keys.onPressed: (event) => addressLayout.updateFocus(event)
//: "SIP address number %1"
Accessible.name: qsTr("sip_address_number_accessible_name").arg(index+1)
}
Button {
id: removeAddressButton
Layout.preferredWidth: Utils.getSizeWithScreenRatio(30)
Layout.preferredHeight: Utils.getSizeWithScreenRatio(30)
Layout.alignment: Qt.AlignVCenter
icon.source: AppIcons.closeX
icon.width: Utils.getSizeWithScreenRatio(24)
icon.height: Utils.getSizeWithScreenRatio(24)
style: ButtonStyle.noBackground
KeyNavigation.left: addressTextField
Keys.onPressed: (event) => addressLayout.updateFocus(event)
onClicked: mainItem.contact.core.removeAddress(index)
//: "Remove SIP address %1"
Accessible.name: qsTr("remove_sip_address_accessible_name").arg(addressTextField.text)
}
}
}
}
FormItemLayout {
id: newAddressSipTextField
label: qsTr("sip_address")
Layout.fillWidth: true
onYChanged: {
editionLayout.ensureVisibleRequested(newAddressSipTextField)
}
contentItem: TextField {
id: newAddressTextField
backgroundColor: DefaultStyle.grey_0
Keys.onPressed: (event) => {
if(event.key == Qt.Key_Up){
(addressesList.count > 0 ? addressesList.itemAt(addressesList.count - 1) : jobTextField).forceActiveFocus(Qt.BacktabFocusReason)
event.accepted = true
}else if(event.key == Qt.Key_Down){
(phoneNumberList.count > 0 ? phoneNumberList.itemAt(0) : phoneNumberInputTextField).forceActiveFocus(Qt.TabFocusReason)
event.accepted = true
}
}
onEditingFinished: {
if (text.length > 0) mainItem.contact.core.appendAddress(text)
newAddressTextField.clear()
editionLayout.connectOnce(editionLayout.ensureVisibleRequested, editionLayout.ensureVisible)
}
//: "New SIP address"
Accessible.name: qsTr("new_sip_address_accessible_name")
}
}
Repeater {
id: phoneNumberList
model: VariantList {
model: mainItem.contact && mainItem.contact.core.phoneNumbers || []
}
delegate: FormItemLayout {
label: modelData.label
contentItem: RowLayout {
id: phoneNumberLayout
spacing: Utils.getSizeWithScreenRatio(10)
function updateFocus(event){
if(event.key == Qt.Key_Up){
(index - 1 >=0 ? phoneNumberList.itemAt(index - 1): newAddressTextField).forceActiveFocus(Qt.BacktabFocusReason)
event.accepted = true
}else if(event.key == Qt.Key_Down){
(index + 1 < phoneNumberList.count ? phoneNumberList.itemAt(index+1) : phoneNumberInputTextField).forceActiveFocus(Qt.TabFocusReason)
event.accepted = true
}
}
TextField {
id: phoneTextField
Layout.preferredWidth: Utils.getSizeWithScreenRatio(421)
Layout.preferredHeight: height
initialText: modelData.address
backgroundColor: DefaultStyle.grey_0
focus: true
KeyNavigation.right: removePhoneButton
Keys.onPressed: (event) => phoneNumberLayout.updateFocus(event)
onEditingFinished: {
//: "Téléphone"
if (text.length != 0) mainItem.contact.core.setPhoneNumberAt(index, qsTr("phone"), text)
}
//: "Phone number number %1"
Accessible.name: qsTr("phone_number_number_accessible_name").arg(index+1)
}
Button {
id: removePhoneButton
Layout.preferredWidth: Utils.getSizeWithScreenRatio(30)
Layout.preferredHeight: Utils.getSizeWithScreenRatio(30)
Layout.alignment: Qt.AlignVCenter
style: ButtonStyle.noBackground
icon.source: AppIcons.closeX
icon.width: Utils.getSizeWithScreenRatio(24)
icon.height: Utils.getSizeWithScreenRatio(24)
KeyNavigation.left: phoneTextField
Keys.onPressed: (event) => phoneNumberLayout.updateFocus(event)
onClicked: mainItem.contact.core.removePhoneNumber(index)
//: Remove phone number %1
Accessible.name: qsTr("remove_phone_number_accessible_name").arg(phoneTextField.text)
}
}
}
}
FormItemLayout {
id: phoneNumberInput
Layout.fillWidth: true
label: qsTr("phone")
onYChanged: {
editionLayout.ensureVisibleRequested(phoneNumberInput)
}
contentItem: TextField {
id: phoneNumberInputTextField
backgroundColor: DefaultStyle.grey_0
Keys.onPressed: (event) => {
if(event.key == Qt.Key_Up){
(phoneNumberList.count > 0 ? phoneNumberList.itemAt(phoneNumberList.count - 1) : newAddressTextField).forceActiveFocus(Qt.BacktabFocusReason)
event.accepted = true
}else if(event.key == Qt.Key_Down){
(contactLayoutItem.button.enabled ? contactLayoutItem.button : givenNameEdit).forceActiveFocus(Qt.TabFocusReason)
event.accepted = true
}
}
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.appendPhoneNumber(phoneNumberInput.label, text)
phoneNumberInputTextField.clear()
editionLayout.connectOnce(editionLayout.ensureVisibleRequested, editionLayout.ensureVisible)
}
//: "New phone number"
Accessible.name: qsTr("new_phone_number_accessible_name")
}
}
TemporaryText {
id: addressesErrorText
Layout.fillWidth: true
wrapMode: Text.WordWrap
elide: Text.ElideRight
onTextChanged: if(addressesErrorText.text.length > 0) editionLayout.ensureVisible(this)
}
Item{Layout.fillHeight: true}
}
}
}
}