diff --git a/src/contactview/qml/bookmarkcard.qml b/src/contactview/qml/bookmarkcard.qml index c14b33f8..adbf54ce 100644 --- a/src/contactview/qml/bookmarkcard.qml +++ b/src/contactview/qml/bookmarkcard.qml @@ -1,83 +1,85 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program 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. * * * * This program 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 this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import RingQmlWidgets 1.0 import Ring 1.0 import ContactView 1.0 Item { height: rows.implicitHeight + 10 //10 == 2*margins Rectangle { anchors.margins: 5 anchors.leftMargin: 10 anchors.rightMargin: 10 border.width: 1 border.color: inactivePalette.text color: "transparent" anchors.fill: parent radius: 5 RowLayout { id: rows anchors.topMargin: 5 anchors.bottomMargin: 5 anchors.fill: parent Item { - width: 48 - height: 48 - anchors.verticalCenter: parent.verticalCenter + Layout.preferredWidth: 48 + Layout.fillHeight: true ContactPhoto { - anchors.fill: parent + width: 36 + height: 36 + + anchors.centerIn: parent anchors.margins: 5 contactMethod: object } } ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true Text { Layout.fillWidth: true id: displayNameLabel text: display color: activePalette.text font.bold: true } Text { Layout.fillWidth: true color: inactivePalette.text text: number } Item { Layout.fillHeight: true } } } MouseArea { anchors.fill: parent onClicked: { treeView.selectItem(rootIndex) bookmarkList.contactMethodSelected(object) } } } } diff --git a/src/contactview/qml/contactcard.qml b/src/contactview/qml/contactcard.qml index 868e74cb..21a62ac4 100644 --- a/src/contactview/qml/contactcard.qml +++ b/src/contactview/qml/contactcard.qml @@ -1,114 +1,116 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program 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. * * * * This program 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 this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import QtQuick.Controls 2.0 import QtQml.Models 2.2 import RingQmlWidgets 1.0 import Ring 1.0 import ContactView 1.0 Item { width: parent.width height: 56 + rowCount*(displayNameLabel.implicitHeight+4) + 10 property var selectionCallback: undefined property var rightControls: undefined Component.onCompleted: { if (!rightControls) return var widget = rightControls.createObject(parent, { "anchors.right" : parent.right, "widget.anchors" : parent.verticalCenter, "visible" : true }) widget.anchors.right = parent.right widget.anchors.verticalCenter = parent.verticalCenter } // Support both ContactRequests and Person property var personObj: objectType != Ring.Person ? person : object Rectangle { anchors.margins: 5 anchors.leftMargin: 10 anchors.rightMargin: 10 border.width: 1 border.color: inactivePalette.text color: "transparent" anchors.fill: parent radius: 5 RowLayout { anchors.topMargin: 5 anchors.bottomMargin: 5 anchors.fill: parent Item { - width: 48 - height: 48 - anchors.verticalCenter: parent.verticalCenter + Layout.preferredWidth: 48 + Layout.fillHeight: true ContactPhoto { - anchors.fill: parent + width: 36 + height: 36 + + anchors.centerIn: parent anchors.margins: 5 person: personObj } } ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true Text { Layout.fillWidth: true id: displayNameLabel text: display color: activePalette.text font.bold: true } Text { Layout.fillWidth: true visible: !individual.hasPhoneNumbers color: inactivePalette.text text: i18n("There is no way to reach this contact") } Item { Layout.fillHeight: true } } } MouseArea { anchors.fill: parent onClicked: { if (selectionCallback) selectionCallback(index, object, rootIndex) else if (treeView != undefined) { //FIXME move elsewhere treeView.selectItem(rootIndex) if (objectType == 0) contactList.contactMethodSelected( object.lastUsedContactMethod ) if (objectType == 1) contactList.contactMethodSelected(object) } } } } } diff --git a/src/timeline/qml/contactinfo.qml b/src/timeline/qml/contactinfo.qml index 24781f49..1d9d2063 100644 --- a/src/timeline/qml/contactinfo.qml +++ b/src/timeline/qml/contactinfo.qml @@ -1,717 +1,713 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program 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. * * * * This program 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 this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.0 +import QtQuick.Layouts 1.2 import Ring 1.0 import PhotoSelectorPlugin 1.0 import RingQmlWidgets 1.0 import org.kde.kirigami 2.2 as Kirigami import ContactView 1.0 Kirigami.ScrollablePage { id: contactViewPage property string defaultName: "" property var individual: null property string forcedState: "" property bool editable: true property bool editing: editable signal changed() signal selectChat() signal selectHistory() property bool showStat: true property bool showImage: false property bool showSave: true property bool isChanged: false property var labelColor: inactivePalette.text property var cachedPhoto: undefined state: forcedState // verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff // horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff function save() { if (!individual) return var person = individual.person if (!person) person = contactBuilder.from(individual, vCardForm.name) if (!vCardForm.currentPerson) vCardForm.currentPerson = person vCardForm.syncDetails(person) if (contactViewPage.cachedPhoto != undefined) person.photo = contactViewPage.cachedPhoto person.save() //currentPerson = person isChanged = false } onChanged: { isChanged = true } SystemPalette { id: activePalette colorGroup: SystemPalette.Active } SystemPalette { id: inactivePalette colorGroup: SystemPalette.Inactive } actions { main: Kirigami.Action { iconName: editing ? "document-save" : "document-edit" visible: contactViewPage.state == "mobile" onTriggered: { if (editing && isChanged) { console.log("Saving!") contactViewPage.save() } editing = (!editing) && editable } } } onIndividualChanged: { vCardForm.currentPerson = individual ? individual.person : null vCardForm.individual = individual isChanged = false } GroupBox { id: advanced title: i18n("Advanced") clip: true height: 300 Behavior on height { NumberAnimation { duration: 200 } } ColumnLayout { id: tabbedContactInfo anchors.topMargin: contactViewPage.showImage ? 95 : 0 spacing: 0 clip: true anchors.fill: parent TabBar { Layout.fillWidth: true id: tabBar onCurrentIndexChanged: { sv.currentIndex = currentIndex } TabButton { text: i18n("Phone numbers") } // TabButton { // text: i18n("Addresses") // } } SwipeView { id: sv Layout.fillWidth: true Layout.fillHeight: true onCurrentIndexChanged: { tabBar.currentIndex = currentIndex } background: Rectangle { color: activePalette.base } Page { Layout.fillWidth: true Layout.fillHeight: true id: tabbedContactInfoPage1 VCardForm { id: vCardForm height: preferredHeight editing: contactViewPage.editing - onEditingChanged: { - console.log("Editing changed", editing) - } - onChanged: { isChanged = true } } background: Rectangle { color: activePalette.base } } Page { id: phoneNumbersPage Layout.fillWidth: true Layout.fillHeight: true PhoneNumbers { id: phoneNumbers width: parent.width model: contactViewPage.individual buttonColor: contactViewPage.labelColor showAdd: contactViewPage.editing } background: Rectangle { color: activePalette.base } } // Page { // id: addressesPage // Layout.fillWidth: true // Layout.fillHeight: true // Addresses { // id: addresses // anchors.fill: parent // } // // background: Rectangle { color: activePalette.base } // } Page { Layout.fillWidth: true Layout.fillHeight: true background: Rectangle { color: activePalette.base } id: tabbedContactInfoPage4 Statistics { id: statistics Layout.fillWidth: true visible: showStat individual: contactViewPage.individual labelColor: contactViewPage.labelColor } } } } } ContactBuilder { id: contactBuilder } Rectangle { id: saveButton z: 10 radius: 999 color: activePalette.highlight visible: showSave && isChanged anchors.margins: 10 width: 56 height: 56 Image { source: "image://icon/edit-save" height: 32 width: 32 anchors.centerIn: parent } MouseArea { anchors.fill: parent hoverEnabled: true onClicked: { contactViewPage.save() } } } ColumnLayout { id: phoneLayout visible: false anchors.left: parent.left anchors.top: parent.top width: parent.width spacing: 10 /** * When showing the profile or adding a contact, display the image at the top. * * When showing the main GUI, this image is part of the header and should * not be shown. */ Item { id: contactPicture visible: showImage height: showImage ? 90 : 0 implicitHeight: showImage ? 90 : 0 Layout.fillWidth: true ContactPhoto { id: photoRect tracked: false visible: showImage anchors.centerIn: parent height: 90 width: 90 defaultColor: contactViewPage.labelColor individual: contactViewPage.individual function onNewPhoto(p) { contactViewPage.cachedPhoto = p contactViewPage.changed() } MouseArea { anchors.fill: parent z: 100 onClicked: { if (!contactViewPage.editing) return false var component = Qt.createComponent("PhotoEditor.qml") if (component.status == Component.Ready) { var window = component.createObject(contactViewPage) window.person = individual ? individual.person : null window.newPhoto.connect(photoRect.onNewPhoto) } else console.log("ERROR", component.status, component.errorString()) } } } } Kirigami.Heading { id: statisticHeader text: i18n("Statistics") color: contactViewPage.labelColor level: 2 } Item { id: statisticHolder - anchors.left: parent.left +// Layout.leftAnchor: parent.left height: statistics.implicitHeight Layout.fillWidth: true } // Keep in columns to avoid spacing ColumnLayout { Layout.fillWidth: true Kirigami.BasicListItem { id: viewHistory label: i18n("View history") icon: "view-history" separatorVisible: true onClicked: { contactViewPage.selectHistory() } } Kirigami.BasicListItem { id: openChat label: i18n("Open chat") icon: "dialog-messages" onClicked: { contactViewPage.selectChat() } } } Kirigami.Heading { text: i18n("Contact details") color: contactViewPage.labelColor level: 2 } Item { id: contactHolder height: vCardForm.preferredHeight Layout.preferredHeight: height Layout.maximumHeight: height Layout.minimumHeight: height Layout.fillWidth: true } Kirigami.Heading { text: i18n("Phone numbers") color: contactViewPage.labelColor level: 2 } Item { id: phoneNumberHolder height: phoneNumbers.preferredHeight Layout.preferredHeight: height Layout.maximumHeight: height Layout.minimumHeight: height Layout.fillWidth: true } // Kirigami.Heading { // text: i18n("Addresses") // color: contactViewPage.labelColor // level: 2 // } // Item { // id: addressesHolder // height: addresses.contentHeight // width: parent.width // } } onStateChanged: { tabBar.currentIndex = 0 sv.currentIndex = 1 } /** * To make this page scale down, reparent everything depending on the * resolution. */ states: [ // In tablet mode, use 3 columns for the details State { name: "tablet" when: (forcedState == "" ) && (contactViewPage.width >= 600 && contactViewPage.height <= ( statistics.implicitHeight + 320) // 320 = advanced.height + 2*spacing ) ParentChange { target: advanced parent: contactViewPage } ParentChange { target: vCardForm parent: contactViewPage } ParentChange { target: statistics parent: contactViewPage } ParentChange { target: phoneNumbers parent: phoneNumbersPage } // ParentChange { // target: addresses // parent: addressesPage // } AnchorChanges { target: advanced anchors.right: advanced.parent.right anchors.bottom: advanced.parent.bottom anchors.top: contactPicture.bottom anchors.left: undefined } AnchorChanges { target: statistics anchors.top: contactPicture.visible ? contactPicture.bottom : contactViewPage.top anchors.left: statistics.parent.left } AnchorChanges { target: vCardForm anchors.left: vCardForm.parent.left anchors.top: statistics.bottom } AnchorChanges { target: phoneNumbers anchors.left: undefined anchors.top: undefined } // AnchorChanges { // target: addresses // anchors.left: undefined // } PropertyChanges { target: advanced visible: true width: contactViewPage.width / 2 height: contactViewPage.height } PropertyChanges { target: statistics width: contactViewPage.width / 2 height: statistics.implicitHeight } PropertyChanges { target: vCardForm width: contactViewPage.width / 2 } PropertyChanges { target: phoneNumbers anchors.fill: phoneNumbersPage width: undefined height: phoneNumbersPage.height interactive: true } PropertyChanges { target: contactViewPage editing: editable } AnchorChanges { target: saveButton anchors.bottom: saveButton.parent.bottom anchors.top: undefined anchors.left: saveButton.parent.left anchors.right: undefined anchors.horizontalCenter: undefined } PropertyChanges { target: saveButton width: 64 height: 64 } }, // In desktop mode, put everything on top of each other and get rid // of the second tabbar State { name: "" extend: "tablet" AnchorChanges { target: saveButton anchors.top: saveButton.parent.top anchors.right: saveButton.parent.right anchors.bottom: undefined anchors.left: undefined anchors.horizontalCenter: undefined } PropertyChanges { target: saveButton width: 64 height: 64 } AnchorChanges { target: advanced anchors.right: advanced.parent.right anchors.bottom: advanced.parent.bottom anchors.top: undefined anchors.left: advanced.parent.left } PropertyChanges { target: statistics width: contactViewPage.width } PropertyChanges { target: vCardForm width: vCardForm.implicitWidth height: vCardForm.implicitHeight anchors.topMargin: 10 anchors.horizontalCenter: undefined } PropertyChanges { target: advanced height: contactViewPage.height ? 300 : 299 //BUG prevent a race condition in QML visible: true anchors.topMargin: 10 } }, // The first phone mode was not very usable, lets try again State { name: "mobile" when: ((forcedState == "" && (contactViewPage.width < 600 || contactViewPage.height < ( statistics.implicitHeight + vCardForm.implicitHeight + 320) // 320 = advanced.height + 2*spacing ))) || forcedState == "mobile" // Mute the QML warning about having elements with anchors in `Column` AnchorChanges { target: saveButton anchors.right: undefined anchors.bottom: undefined anchors.top: undefined anchors.left: undefined anchors.horizontalCenter: undefined } AnchorChanges { target: advanced anchors.right: undefined anchors.bottom: undefined anchors.top: undefined anchors.left: undefined } ParentChange { target: vCardForm parent: contactHolder } AnchorChanges { target: vCardForm anchors.left: contactHolder.left anchors.top: contactHolder.top } PropertyChanges { target: vCardForm anchors.horizontalCenter: undefined } ParentChange { target: phoneNumbers parent: phoneNumberHolder } AnchorChanges { target: phoneNumbers anchors.left: phoneNumberHolder.left anchors.top: phoneNumberHolder.top } // ParentChange { // target: addresses // parent: addressesHolder // } // AnchorChanges { // target: addresses // anchors.left: contactViewPage.left // } ParentChange { target: statistics parent: statisticHolder } AnchorChanges { target: statistics anchors.left: statisticHolder.left anchors.top: statisticHolder.top } PropertyChanges { target: phoneNumbers anchors.fill: undefined width: contactViewPage.width interactive: false height: preferredHeight x: 0 y: 0 } // PropertyChanges { // target: addresses // anchors.fill: undefined // } PropertyChanges { target: phoneLayout visible: true } // Hide the tabs and groupbox in favor of standard rows PropertyChanges { target: advanced visible: false } PropertyChanges { target: tabBar visible: false } PropertyChanges { target: sv visible: false } PropertyChanges { target: contactViewPage bottomPadding: undefined topPadding: undefined leftPadding: undefined rightPadding: undefined editing: false } }, State { name: "profile" extend: "mobile" PropertyChanges { target: openChat visible: false } PropertyChanges { target: vCardForm anchors.horizontalCenter: contactHolder.horizontalCenter } PropertyChanges { target: statisticHolder visible: false } PropertyChanges { target: viewHistory visible: false } PropertyChanges { target: statisticHeader visible: false } PropertyChanges { target: contactViewPage bottomPadding: 0 topPadding: 0 leftPadding: 0 rightPadding: 0 editing: editable } AnchorChanges { target: phoneLayout anchors.top: contactPicture.bottom } } ] transitions: Transition { AnchorAnimation { duration: 300 } } } diff --git a/src/timeline/qml/contactmethoddelegate.qml b/src/timeline/qml/contactmethoddelegate.qml index a0586b78..3d3b598c 100644 --- a/src/timeline/qml/contactmethoddelegate.qml +++ b/src/timeline/qml/contactmethoddelegate.qml @@ -1,362 +1,360 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program 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. * * * * This program 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 this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Layouts 1.0 import Ring 1.0 import RingQmlWidgets 1.0 import ContactView 1.0 // import org.kde.kirigami 2.0 as Kirigami MouseArea { id: componentItem width: parent != undefined ? parent.width : undefined height: computeHeight() acceptedButtons: Qt.LeftButton | Qt.RightButton hoverEnabled: true property bool hasMessage: hasActiveCall || unreadTextMessageCount > 0 || isRecording || hasActiveVideo function computeHeight() { if (hasMessage) return 7*fontMetrics.height + 14 return 5*fontMetrics.height + 13 } function thirdRowMessage() { if (hasActiveVideo) return "Video in progress" else if (hasActiveCall) return "Call in progress" else if (unreadTextMessageCount > 0) return unreadTextMessageCount + " new messages" return "" } onClicked: { if (mouse.button == Qt.LeftButton) { recentView.currentIndex = rootIndex.row individualSelected(object) } else if (mouse.button == Qt.RightButton) contextMenuRequested(object.lastUsedContactMethod, rootIndex.row) } Rectangle { width: 1 color: inactivePalette.text height: parent.height x: 10 } Rectangle { radius: 99 color: activePalette.base border.width: 1 border.color: inactivePalette.text width: 16 height: 16 y: 10 x: 3 // (16 - 10) / 2 Rectangle { id: demandsAttention radius: 99 color: inactivePalette.text anchors.centerIn: parent height: 8 width: 8 } } Rectangle { id: outline border.color: inactivePalette.text border.width: 1 anchors.fill: parent anchors.topMargin: 5 anchors.bottomMargin: 5 anchors.leftMargin: 30 anchors.rightMargin: 40 color: "transparent" radius: 10 Rectangle { id: highlight anchors.fill: parent color: "red" visible: false opacity: 0 } ColumnLayout { anchors.fill: parent RowLayout { Layout.fillWidth: true height: 3*fontMetrics.height Item { - anchors.margins: 4 - height: parent.height width: parent.height ContactPhoto { anchors.margins: 3 anchors.fill: parent individual: object defaultColor: isCurrentItem ? activePalette.highlightedText : activePalette.text drawEmptyOutline: false } } Text { text: object.bestName clip: true font.bold : true Layout.fillWidth: true - anchors.verticalCenter: parent.verticalCenter + Layout.alignment: Qt.AlignVCenter color: isCurrentItem ? activePalette.highlightedText : activePalette.text } } Rectangle { color: inactivePalette.text height:1 Layout.fillWidth: true } Text { Layout.fillWidth: true text: object.lastUsedUri.length == 40 ? "RingId" : object.lastUsedUri height: 2*fontMetrics.height leftPadding: 10 verticalAlignment: Text.AlignVCenter color: isCurrentItem ? activePalette.highlightedText : inactivePalette.text } Rectangle { color: inactivePalette.text height:1 Layout.fillWidth: true visible: componentItem.hasMessage } Loader { id: messageLoader active: true Layout.fillWidth: true Layout.minimumHeight: contentHeight2 * 2 Layout.maximumHeight: contentHeight2 * 2 property real contentHeight2: 10 sourceComponent: MouseArea { id: markAsRead z: 101 anchors.fill: messageLoader Component.onCompleted: { messageLoader.contentHeight2 = unreadLabel.implicitHeight } Text { id: unreadLabel Layout.fillWidth: true visible: componentItem.hasMessage text: thirdRowMessage() anchors.verticalCenter: parent.verticalCenter height: 2*fontMetrics.height leftPadding: 10 verticalAlignment: Text.AlignVCenter color: isCurrentItem ? activePalette.highlightedText : inactivePalette.text onImplicitHeightChanged: { messageLoader.contentHeight2 = implicitHeight } } onClicked: { if (object) object.markAsRead() mouse.accepted = true } Rectangle { id: button anchors.leftMargin: 7 anchors.rightMargin: 7 anchors.bottomMargin: 7 color: "transparent" visible: false radius: 5 anchors.fill: parent border.width: 1 border.color: outline.border.color Text { text: i18n("Mark as read") color: isCurrentItem ? activePalette.highlightedText : activePalette.text font.bold: true anchors.centerIn: parent } } states: [ State { name: "" PropertyChanges { target: button visible: false } }, State { name: "hover" when: messageLoader.state == "hover" PropertyChanges { target: button visible: true color: isCurrentItem ? activePalette.highlight : activePalette.base } } ] } states: [ State { name: "" }, State { name: "show" when: componentItem.hasMessage && !componentItem.containsMouse PropertyChanges { target: messageLoader active: true } }, State { name: "hover" extend: "show" when: componentItem.hasMessage && componentItem.containsMouse } ] } Item { Layout.fillHeight: true } } // Allow to set/remove bookmarks Image { id: bookmarkSwitch anchors.top: parent.top anchors.right: parent.right anchors.rightMargin: 1 anchors.topMargin: 3 height: 16 width: 16 source: object.hasBookmarks ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" z: 100 MouseArea { anchors.fill: parent onClicked: { mouse.accepted = true var cm = object.firstBookmark if (!cm) cm = object.lastUsedContactMethod if (cm) cm.bookmarked = !cm.bookmarked } } } // Add the other indicators in the bottom right RowLayout { height: 16 anchors.bottom: parent.bottom anchors.right: parent.right anchors.rightMargin: 3 anchors.bottomMargin: 3 Rectangle { id: isRecordingBox height: 16 radius: 3 color: "#b93030" opacity: 0.33 width: 20 visible: isRecording Image { height: 16 width: 16 anchors.horizontalCenter: parent.horizontalCenter source: "image://icon/media-record" } } } StateGroup { states: [ State { name: "demandsAttention" when: unreadTextMessageCount > 0 PropertyChanges { target: highlight opacity: 0.1 visible: true } PropertyChanges { target: demandsAttention color: "red" opacity: 0.1 } } ] transitions: [ Transition { to: "demandsAttention" NumberAnimation { properties: "opacity" easing.type: Easing.InQuad duration: 1500 loops: Animation.Infinite } } ] } } } diff --git a/src/timeline/qml/phonenumbers.qml b/src/timeline/qml/phonenumbers.qml index 46740df8..8c0d6476 100644 --- a/src/timeline/qml/phonenumbers.qml +++ b/src/timeline/qml/phonenumbers.qml @@ -1,307 +1,307 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program 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. * * * * This program 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 this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import Ring 1.0 import RingQmlWidgets 1.0 import org.kde.kirigami 2.2 as Kirigami import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews ListView { id: numbers property color buttonColor: inactivePalette.text property alias model: numbers.model property QtObject person: null property alias interactive: numbers.interactive property bool editing: (model && model.editRow) || !person property bool showAdd: true property real preferredHeight: numbers.contentHeight + (addButton && addButton.visible ? 0 : -addButton.height) signal personCreated(QtObject newPerson) property var addButton: null width: parent.width anchors.margins: 3 height: preferredHeight clip: true SystemPalette { id: activePalette colorGroup: SystemPalette.Active } SystemPalette { id: inactivePalette colorGroup: SystemPalette.Disabled } Component { id: editComponent RowLayout { Layout.fillWidth: true Layout.preferredHeight: 40 ComboBox { id: numbertype model: NumberCategoryModel textRole: "display" onActivated: { } } TextField { Layout.fillWidth: true id: newPhoneNumber text: editUri } CheckBox { id: customAccount checked: obj && obj.account && visible visible: AccountModel.size > 1 } ComboBox { id: numberAccount model: AccountModel enabled: customAccount.checked textRole: "display" visible: AccountModel.size > 1 currentIndex: (obj && obj.account) ? obj.account.index.row : 2 onActivated: { } } Button { id: button text: i18n("Save") onClicked: { if (newPhoneNumber.text == "") { console.log("No number added, the field is empty") return } var accIdx = customAccount.checked ? numberAccount.index : -1 var p = numbers.person ? numbers.person : numbers.model.person var cm = contactBuilder.updatePhoneNumber(obj, contactViewPage.individual, p, newPhoneNumber.text, numbertype.index, accIdx ) if (cm && cm.person) { console.log("Setting the person", cm, cm.person) person = cm.person //numbers.model = cm.person.individual } if (cm.person) { console.log("Saving", cm.person) cm.person.save() } personCreated(cm.person) numbers.currentIndex = idx numbers.currentItem.state = "" } } Button { text: i18n("Cancel") onClicked: { if (cmType == ContactMethod.TEMPORARY) numbers.model.editRow = false numbers.currentIndex = idx if (numbers.currentItem) numbers.currentItem.state = "" } } } } footer: OutlineButton { id: btn height: fontMetrics.height * 3.5 expandedHeight: fontMetrics.height * 3.5 sideMargin: 2 width: parent.width color: numbers.buttonColor label: i18n("Add a phone number or GNU Ring identity") topPadding: 2 visible: (numbers.model && !numbers.model.editRow) && numbers.showAdd onClicked: { if (numbers.model) { contactBuilder.addEmptyPhoneNumber(numbers.person) numbers.model.editRow = true numbers.currentIndex = numbers.count - 1 numbers.currentItem.state = "edit" } else console.log("No contact, not implemented") } Component.onCompleted: { numbers.addButton = btn } } delegate: Kirigami.SwipeListItem { height: readOnly.height implicitHeight: readOnly.height states: [ State { name: "" }, State { name: "edit" PropertyChanges { target: editorLoader editUri: uri active: true } PropertyChanges { target: readOnly visible: false } } ] actions: [ Kirigami.Action { iconName: "edit-delete" text: i18n("Delete") onTriggered: { // Cache the person to avoid the race condition where // the delegate is deleted before the end of the callback var p = numbers.model.person numbers.model.removePhoneNumber(object) if (p) p.save() } }, Kirigami.Action { iconName: "document-edit" text: i18n("Edit") onTriggered: { state = "edit" } }, Kirigami.Action { iconSource: "image://SymbolicColorizer/:/sharedassets/outline/call.svg" text: i18n("Call") visible: canCall onTriggered: CallModel.dialingCall(object).performAction(Call.ACCEPT) }, Kirigami.Action { iconSource: "image://SymbolicColorizer/:/sharedassets/outline/camera.svg" text: i18n("Video call") visible: canVideoCall onTriggered: CallModel.dialingCall(object).performAction(Call.ACCEPT) }, Kirigami.Action { iconSource: "image://SymbolicColorizer/:/sharedassets/outline/screen.svg" text: i18n("Share screen") visible: canVideoCall onTriggered: CallModel.dialingCall(object).performAction(Call.ACCEPT) } ] // Wrap in an extra Item to bypass Kirigami limitations regarding // the number of elements Item { height: readOnly.height implicitHeight: readOnly.height Loader { id: editorLoader property ContactMethod obj: object property int idx: index property string editUri: object ? object.uri : "" property var cmType: type sourceComponent: editComponent anchors.fill: parent anchors.rightMargin: 0 active: false } RowLayout { id: readOnly anchors.leftMargin: 10 anchors.fill: parent height: columns.implicitHeight + 30 // 30 == 3*spacing implicitHeight: columns.implicitHeight + 30 spacing: 10 KQuickItemViews.DecorationAdapter { Layout.preferredHeight: 16 Layout.preferredWidth: 16 - anchors.verticalCenter: parent.verticalCenter + Layout.alignment: Qt.AlignVCenter pixmap: decoration } ColumnLayout { id: columns Layout.fillWidth: true Row { Layout.fillWidth: true Text { text: display color: activePalette.text } Text { visible: object.registeredName == display text: "✔" color: Kirigami.Theme.positiveTextColor font.bold: true } Text { text: " ("+categoryName+")" color: inactivePalette.text } } Text { text: lastUsed == undefined || lastUsed == "" ? i18n("Never used") : i18n("Used ")+totalCallCount+i18n(" time (Last used on: ") + formattedLastUsed + ")" color: inactivePalette.text } } Item { Layout.preferredWidth: 5 } } } } ContactBuilder { id: contactBuilder } } diff --git a/src/timeline/qml/textbubble.qml b/src/timeline/qml/textbubble.qml index 52431e48..512381f4 100644 --- a/src/timeline/qml/textbubble.qml +++ b/src/timeline/qml/textbubble.qml @@ -1,126 +1,126 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program 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. * * * * This program 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 this program. If not, see . * **************************************************************************/ import QtQuick 2.7 -import QtQuick.Layouts 1.0 +import QtQuick.Layouts 1.2 import Ring 1.0 import RingQmlWidgets 1.0 import ContactView 1.0 import QtGraphicalEffects 1.0 import Style 1.0 import org.kde.kirigami 2.2 as Kirigami Item { id: chatMessage width: parent.width property color background property color foreground property var cm: contactMethod signal clicked() height: bubble.height + 10 function getFactor() { return (height > (chatMessage.width*0.5)) ? 0.9 : 0.7 } // Prevent a binding loop. the "current" height isn't required anyway onWidthChanged: { bubble.maximumWidth = chatMessage.width*getFactor() } RowLayout { anchors.fill: parent ContactPhoto { width: 50 height: 50 visible: direction == 0 drawEmptyOutline: false tracked: false contactMethod: chatMessage.cm - anchors.bottom: parent.bottom - anchors.bottomMargin: 20 + Layout.alignment: Qt.AlignBottom + Layout.bottomMargin: 20 } Item { Layout.fillWidth: true Layout.fillHeight: true Bubble { id: bubble anchors.margins: 5 anchors.right: direction == 1 ? parent.right : undefined anchors.left : direction == 1 ? undefined : parent.left font.pointSize: Kirigami.Theme.defaultFont.pointSize*1.2 font.family: "Noto Color Emoji" z: 1 alignment: direction == 1 ? Text.AlignRight : Text.AlignLeft color: background text: display != undefined ? display : "N/A" height: Math.max(50, label.implicitHeight + dateLabel.implicitHeight + 5) Text { id: label anchors.fill: parent anchors.leftMargin: 30 anchors.rightMargin: 30 anchors.topMargin: 5 anchors.bottomMargin: 5 horizontalAlignment: direction == 1 ? Text.AlignRight : Text.AlignLeft font: bubble.font text: display != undefined ? display : "N/A" color: foreground wrapMode: Text.WordWrap } Text { id: dateLabel anchors.bottom: parent.bottom anchors.left: direction == 1 ? parent.left : undefined anchors.right: direction == 0 ? parent.right : undefined anchors.bottomMargin: 4 anchors.leftMargin: direction == 1 ? 4 : undefined anchors.rightMargin: direction == 0 ? 4 : undefined text: formattedDate != undefined ? formattedDate : "N/A" color: "gray" } MouseArea { anchors.fill: parent onClicked: { chatMessage.clicked() } } } } ContactPhoto { width: 50 height: 50 visible: direction == 1 drawEmptyOutline: false tracked: false contactMethod: chatMessage.cm - anchors.bottom: parent.bottom - anchors.bottomMargin: 20 + Layout.alignment: Qt.AlignBottom + Layout.bottomMargin: 20 } } }