diff --git a/src/callview/qml/callview.qml b/src/callview/qml/callview.qml index 4a31e295..6cdcfec1 100644 --- a/src/callview/qml/callview.qml +++ b/src/callview/qml/callview.qml @@ -1,276 +1,272 @@ /*************************************************************************** * 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 net.lvindustries.ringqtquick 1.0 as RingQtQuick import org.kde.ringkde.jamicallview 1.0 as JamiCallView import org.kde.ringkde.jamivideoview 1.0 as JamiVideoView import org.kde.ringkde.jamidialview 1.0 as JamiDialView Item { id: videoDock signal callWithVideo () signal callWithAudio () signal callWithScreen() // C++ bindings property alias rendererName : videoWidget.rendererName property bool displayPreview : false property string mode : "PREVIEW" property bool previewRunning : false property alias peerRunning : videoWidget.started property QtObject call : null property QtObject renderer : call ? call.renderer : null property alias individual: placeholderMessage.individual property bool previewVisible: mode != "PREVIEW" && call && RingSession.previewManager.previewing Connections { target: renderer onDestroyed: { videoWidget.started = false } } // Let the animations finish before Timer { id: toolbarTimer running: false interval: 150 repeat: false onTriggered: { actionToolbar.visible = false videoSource.visible = false controlToolbar.visible = false } } function showToolbars() { actionToolbar.visible = true videoSource.visible = true // This toolbar is only useful when there is video if (videoWidget.started) controlToolbar.visible = true actionToolbar.opacity = 1 videoSource.opacity = 1 controlToolbar.opacity = 1 videoPreview.opacity = 0.8 actionToolbar.anchors.bottomMargin = 0 videoSource.anchors.rightMargin = 0 controlToolbar.anchors.topMargin = 0 } function hideToolbars() { actionToolbar.opacity = 0 videoSource.opacity = 0 controlToolbar.opacity = 0 videoPreview.opacity = 1 videoSource.anchors.rightMargin = -20 actionToolbar.anchors.bottomMargin = -20 controlToolbar.anchors.topMargin = -20 toolbarTimer.running = true } + // The main video widget JamiVideoView.VideoWidget { id: videoWidget anchors.fill: parent z: -100 started: false visible: started && !hasFailed call: videoDock.call } + // The preview JamiVideoView.VideoWidget { id: videoPreview z: -95 started: false visible: previewVisible anchors.right: parent.right anchors.bottom: parent.bottom width: 192 height: 108 } + // This toolbar allows to rotate video, take screenshots, etc JamiVideoView.VideoControlToolbar { id: controlToolbar anchors.top: parent.top visible: false Behavior on opacity { NumberAnimation {duration: 100} } Behavior on anchors.topMargin { NumberAnimation {duration: 150} } } + // The has the currently supported call actions such as hang up JamiDialView.ActionToolbar { id: actionToolbar anchors.bottom: parent.bottom visible: false Behavior on opacity { NumberAnimation {duration: 100} } Behavior on anchors.bottomMargin { NumberAnimation {duration: 150} } } + // Make it obvious when the call is being recording (locally, if the other + // side choose to record, there is no way to really know. JamiCallView.RecordingIcon { anchors.right: videoDock.right anchors.top: controlToolbar.bottom } - JamiVideoView.DeviceSetting { - id: deviceSettings - visible: mode == "PREVIEW" - width: parent.width - z: 100 - } - + // This allows to switch to different camera or enable screen sharing JamiVideoView.VideoSource { id: videoSource z: 101 visible: false anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter Behavior on opacity { NumberAnimation {duration: 100} } Behavior on anchors.rightMargin { NumberAnimation {duration: 150} } } // The background JamiCallView.CallBackground { id: placeholderMessage z: -99 anchors.fill: parent bottomMargin: actionToolbar.visible ? actionToolbar.height : 0 } // Hide both toolbars when the mouse isn't moving //TODO keep visible if the mouse if over the toolbars MouseArea { id: mainMouseArea Timer { id: activityTimer interval: 3000 running: true repeat: false onTriggered: { hideToolbars() } } function trackActivity() { - if (mode == "PREVIEW") { - deviceSettings.visible = true - } - else if (call) { + if (call && mode != "PREVIEW") showToolbars() - } activityTimer.restart() } anchors.fill: parent hoverEnabled: true propagateComposedEvents: true onMouseXChanged: trackActivity() onMouseYChanged: trackActivity() } onModeChanged: { if (mode == "PREVIEW") { hideToolbars() videoWidget.rendererName = "preview" } else if (mode == "CONVERSATION") { videoPreview.started = RingSession.previewManager.previewing videoWidget.rendererName = "peer" } placeholderMessage.mode = mode } onCallChanged: { if (call) { actionToolbar.userActionModel = call.userActionModel placeholderMessage.call = call videoSource.call = call controlToolbar.call = call } videoWidget.hasFailed = false mainMouseArea.visible = call != null || mode == "PREVIEW" } Connections { target: RingSession.previewManager onPreviewingChanged: { if (mode == "PREVIEW") videoWidget.started = RingSession.previewManager.previewing videoPreview.started = RingSession.previewManager.previewing } } Connections { target: call } Connections { target: call onVideoStarted: { videoWidget.started = true } onVideoStopped: { videoWidget.started = false } onLiveMediaIssuesChanaged: { // This isn't using properties because the renderer live in their // own thread and QML doesn't support this yet videoWidget.hasFailed = call.hasIssue(RingQtQuick.Call.VIDEO_ACQUISITION_FAILED) } } Connections { target: videoWidget onStartedChanged: { placeholderMessage.visible = (!videoWidget.started) || (videoWidget.hasFailed) } onHasFailedChanged: { placeholderMessage.visible = (!videoWidget.started) || (videoWidget.hasFailed) } } Connections { target: call onStateChanged: { if (call == null || call.lifeCycleState == RingQtQuick.Call.FINISHED) { call = null hideToolbars() } } } } diff --git a/src/dialview/qml/actiontoolbar.qml b/src/dialview/qml/actiontoolbar.qml index 26aaca91..8c6ec06b 100644 --- a/src/dialview/qml/actiontoolbar.qml +++ b/src/dialview/qml/actiontoolbar.qml @@ -1,287 +1,330 @@ /*************************************************************************** * Copyright (C) 2015 by Emmanuel Lepage Vallee * * 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.0 import QtQuick.Layouts 1.0 as Layouts +import org.kde.kirigami 2.2 as Kirigami import net.lvindustries.ringqtquick 1.0 as RingQtQuick import net.lvindustries.ringqtquick.models 1.0 as RingQtModels import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews Rectangle { id: toolbar color: "#55000000" height: actionGrid.contentHeight width: parent.width y:parent.height-toolbar.height -10 z: 100 property var userActionModel: null Timer { id: hideLabel running: false repeat: false interval: 5000 onTriggered: { currentText.visible = false } } // Use a separate label. This allows to use only icons in the buttons, // this reducing the footprint and avoiding a second row. Rectangle { id: currentText clip: true color: "#333333" height: 20 width: 200 radius: 99 // circle visible: false anchors.horizontalCenter: parent.horizontalCenter y: - 30 Text { id: currentTextText anchors.fill: parent color: "white" font.bold : true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter onContentWidthChanged: parent.width = contentWidth + 20 onContentHeightChanged: parent.height = contentHeight + 10 } Behavior on width { NumberAnimation {duration: 50} } } // Show the accept and hangup buttons in green and red function selectColor(action) { if (action == RingQtModels.UserActionModel.HANGUP) return "#550000"; else if(action == RingQtModels.UserActionModel.ACCEPT) return "#005500" // Default return "#CC222222" } function selectLabelColor(action) { if (action == RingQtModels.UserActionModel.HANGUP || action == RingQtModels.UserActionModel.ACCEPT) return "white" // Default return "white" } Component { id: actionDelegate Item { id: mainArea width: actionGrid.cellWidth height: actionGrid.cellHeight Rectangle { id: background color: mouseArea.containsMouse ? "#CC333333" : selectColor(action) radius: 99 // circle anchors.leftMargin: 5 anchors.rightMargin: 5 anchors.fill: parent border.width: mouseArea.containsMouse ? 3 : 0 border.color: "#dd5555" Layouts.RowLayout { anchors.margins: 15 anchors.fill: parent KQuickItemViews.DecorationAdapter { Layouts.Layout.alignment: Qt.AlignVCenter pixmap: decoration width: 30 height: 30 } Text { id: label text: display visible: false horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: selectLabelColor(action) font.bold: true Layouts.Layout.leftMargin: 10 Layouts.Layout.fillHeight: true Layouts.Layout.fillWidth: true Layouts.Layout.alignment: Qt.AlignVCenter } } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true z: 101 onClicked: { userActionModel.execute(action) } onContainsMouseChanged: { if (containsMouse) { currentText.visible = true currentTextText.text = display } hideLabel.restart() } } Behavior on color { ColorAnimation {duration: 300} } Behavior on border.width { NumberAnimation {duration: 200} } StateGroup { id: stateGroup states: [ State { name: "" when: actionGrid.count > 2 || actionGrid.count == 0 PropertyChanges { target: background radius: 99 anchors.margins: 0 } PropertyChanges { target: mainArea width: 70 } PropertyChanges { target: label visible: false } }, State { name: "single" when: actionGrid.count == 1 PropertyChanges { target: background radius: 5 anchors.margins: 2 } PropertyChanges { target: mainArea width: (toolbar.width/1) } PropertyChanges { target: label visible: true } }, State { name: "two" when: actionGrid.count == 2 PropertyChanges { target: background radius: 5 anchors.margins: 2 } PropertyChanges { target: mainArea width: (toolbar.width/2) } PropertyChanges { target: label visible: true } } ] } } } } GridView { id: actionGrid height: parent.height - model: RingSession.callModel.userActionModel.activeActionModel + + /* + * This filter allows to handle the action differently depending on the + * platform or context. The UserActionModel doesn't care about these + * use case and only tell if the action is available depending on the + * current state. + */ + model: RingQtQuick.UserActionFilter { + id: filterModel + + // Record crashes on Android + RingQtQuick.UserAction { + action: RingQtModels.UserActionModel.RECORD + enabled: !Kirigami.Settings.isMobile + } + + // Not implemented on Android + RingQtQuick.UserAction { + action: RingQtModels.UserActionModel.MUTE_VIDEO + enabled: !Kirigami.Settings.isMobile + } + + // Not implemented on Android + RingQtQuick.UserAction { + action: RingQtModels.UserActionModel.MUTE_AUDIO + enabled: !Kirigami.Settings.isMobile + } + + // As of Feb 2019, this is currently broken upstream + RingQtQuick.UserAction { + action: RingQtModels.UserActionModel.HOLD + enabled: false + } + + // Unsuported by this client + RingQtQuick.UserAction { + action: RingQtModels.UserActionModel.SERVER_TRANSFER + enabled: false + } + + model: RingSession.callModel.userActionModel + } + delegate: actionDelegate cellWidth: 70; cellHeight: 60 anchors.centerIn: parent width: Math.min(toolbar.width, count*cellWidth) implicitWidth: Math.min(toolbar.width, count*cellWidth) StateGroup { id: stateGroup states: [ State { name: "" when: actionGrid.count > 2 || actionGrid.count == 0 PropertyChanges { target: actionGrid cellWidth: 70 } }, State { name: "single2" when: actionGrid.count == 1 PropertyChanges { target: actionGrid cellWidth: (toolbar.width/1) } }, State { name: "two2" when: actionGrid.count == 2 PropertyChanges { target: actionGrid cellWidth: (toolbar.width/2) } } ] } } // Hide the label when the mouse is out MouseArea { z: -100 anchors.fill: parent hoverEnabled: true onContainsMouseChanged: { if (!containsMouse) currentText.visible = false } } onVisibleChanged: { if (!visible) currentText.visible = false } onUserActionModelChanged: { if (!userActionModel) { userActionModel = RingSession.callModel.userActionModel return } - actionGrid.model = (userActionModel && userActionModel.activeActionModel) ? - userActionModel.activeActionModel : RingSession.callModel.userActionModel.activeActionModel + filterModel.model = userActionModel ? + userActionModel : RingSession.callModel.userActionModel } } diff --git a/src/jamichatview/qml/chatview.qml b/src/jamichatview/qml/chatview.qml index 0d07b007..0c518300 100644 --- a/src/jamichatview/qml/chatview.qml +++ b/src/jamichatview/qml/chatview.qml @@ -1,180 +1,182 @@ /*************************************************************************** * 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 org.kde.kirigami 2.2 as Kirigami import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews import net.lvindustries.ringqtquick 1.0 as RingQtQuick import net.lvindustries.ringqtquick.models 1.0 as RingQtModels import org.kde.ringkde.jamichatview 1.0 as JamiChatView import org.kde.ringkde.genericutils 1.0 as GenericUtils KQuickItemViews.HierarchyView { id: chatView clip: true property alias individual: filterModel.individual function jumpTo(idx) { var ridx = filterModel.mapFromSource(idx) var pos = chatView.itemRect(ridx) chatView.contentY = pos.y } + property var treeHelper: GenericUtils.TreeHelper {} + property bool forceTime: false property var bubbleBackground: blendColor() property var bubbleForeground: "" property var unreadBackground: "" property var unreadForeground: "" property alias slideshow: slideshow property bool displayExtraTimePrivate: moving || dragging || forceTime property bool displayExtraTime: false onDisplayExtraTimePrivateChanged: { if (displayExtraTimePrivate) displayExtraTime = true else dateTimer.running = true } Timer { id: dateTimer interval: 1500 repeat: false onTriggered: displayExtraTime = false } model: RingQtQuick.TimelineFilter { id: filterModel showCalls: false showEmptyGroups: true showMessages: true initDelay: 33 } function blendColor() { chatView.bubbleBackground = Qt.tint( Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor //base1 ) chatView.unreadBackground = Qt.tint( Kirigami.Theme.backgroundColor, "#99BB0000" ) chatView.bubbleForeground = Kirigami.Theme.highlightedTextColor chatView.unreadForeground = Kirigami.Theme.highlightedTextColor return chatView.bubbleBackground } JamiChatView.Slideshow { id: slideshow } // Display something when the chat is empty Text { color: Kirigami.Theme.textColor text: i18n("There is nothing yet, enter a message below or place a call using the buttons\nfound in the header") anchors.centerIn: parent visible: chatView.empty horizontalAlignment: Text.AlignHCenter } Component { id: messageDelegate Loader { id: chatLoader // Create a delegate for each type Component { id: sectionDelegate JamiChatView.TextMessageGroup { width: chatView.width } } Component { id: snapshotGroupDelegate JamiChatView.Snapshots { width: chatView.width onViewImage: { chatView.slideshow.active = true chatView.slideshow.model = model chatView.slideshow.source = path } } } Component { id: callDelegate JamiChatView.CallGroup { width: chatView.width } } Component { id: categoryDelegate JamiChatView.CategoryHeader { width: chatView.width } } Component { id: textDelegate JamiChatView.TextBubble { background: isRead ? chatView.bubbleBackground : chatView.unreadBackground foreground: isRead ? chatView.bubbleForeground : chatView.unreadForeground width: chatView.width onClicked: { chatView.treeHelper.setData(rootIndex, true, "isRead") } } } // Some elements don't have delegates because they are handled // by their parent delegates function selectDelegate() { if (nodeType == RingQtModels.IndividualTimelineModel.TIME_CATEGORY) return categoryDelegate if (nodeType == RingQtModels.IndividualTimelineModel.TEXT_MESSAGE) return textDelegate if (nodeType == RingQtModels.IndividualTimelineModel.SNAPSHOT_GROUP) return snapshotGroupDelegate if (nodeType == RingQtModels.IndividualTimelineModel.SECTION_DELIMITER) return sectionDelegate if ( nodeType == RingQtModels.IndividualTimelineModel.CALL_GROUP || nodeType == RingQtModels.IndividualTimelineModel.RECORDINGS ) return callDelegate } sourceComponent: selectDelegate() } } delegate: messageDelegate } diff --git a/views/basic/qml/callpage.qml b/views/basic/qml/callpage.qml index 4458fa57..a65fbe39 100644 --- a/views/basic/qml/callpage.qml +++ b/views/basic/qml/callpage.qml @@ -1,163 +1,160 @@ /* * Copyright 2019 Emmanuel Lepage * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 3, 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.2 import QtQuick.Layouts 1.4 import QtQuick.Controls 2.2 as Controls import org.kde.kirigami 2.6 as Kirigami import org.kde.ringkde.basicview 1.0 as BasicView import org.kde.ringkde.jamichatview 1.0 as JamiChatView import org.kde.ringkde.jamicallview 1.0 as JamiCallView import net.lvindustries.ringqtquick 1.0 as RingQtQuick import net.lvindustries.ringqtquick.media 1.0 as RingQtMedia Kirigami.Page { spacing: 0 leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 padding: 0 globalToolBarStyle: Kirigami.ApplicationHeaderStyle.ToolBar Kirigami.Theme.colorSet: Kirigami.Theme.View titleDelegate: BasicView.DesktopHeader { id: dheader Layout.fillWidth: true } /** * Get an ongoing call if it exists or request a dialing call to be created. */ function getCall(cm) { return workflow.call && workflow.call.lifeCycleState != RingQtQuick.Call.FINISHED ? workflow.call : RingSession.callModel.dialingCall(cm) } /** * An individual can have multiple phone numbers or Ring/Jami accounts. * * Pick one. */ function getDefaultCm() { if (workflow.currentContactMethod) return workflow.currentContactMethod if (workflow.currentIndividual) return workflow.currentIndividual.mainContactMethod return null } - function audioCall() { - var cm = getDefaultCm() - - if (cm.hasInitCall) { - workflow.showCall(cm.firstActiveCall) + function callCommon(media) { + if (!workflow.currentIndividual) return - } - var call = getCall(cm) + var cm = getDefaultCm() - call.performAction(RingQtQuick.Call.ACCEPT) - } + if (!cm) + cm = workflow.currentIndividual.preferredContactMethod(media) - function videoCall() { - var cm = getDefaultCm() + if (!cm) { + console.log("Failed to find a proper contact method for", workflow.currentIndividual) + return + } if (cm.hasInitCall) { workflow.showCall(cm.firstActiveCall) return } var call = getCall(cm) call.performAction(RingQtQuick.Call.ACCEPT) } - function screencast() { - var cm = getDefaultCm() - - if (cm.hasInitCall) { - workflow.showCall(cm.firstActiveCall) - return - } + function audioCall() { + callCommon(RingQtQuick.Media.AUDIO) + } - var call = getCall(cm) + function videoCall() { + callCommon(RingQtQuick.Media.VIDEO) + } - call.performAction(RingQtQuick.Call.ACCEPT) + function screencast() { + callCommon(RingQtQuick.Media.VIDEO) } JamiCallView.CallView { id: callview anchors.fill: parent individual: workflow.currentIndividual mode: "CONVERSATION" call: workflow.call Connections { target: workflow onCallChanged: { callview.call = workflow.call } } onCallWithAudio: { var cm = getDefaultCm() if (!cm) return audioCall() } onCallWithVideo: { var cm = getDefaultCm() if (!cm) return videoCall() } onCallWithScreen: { var cm = getDefaultCm() if (!cm) return screencast() } } actions { main : actionCollection.chatAction } /** * Not worth it on mobile, they are the same as in the call toolbar. */ contextualActions: Kirigami.Settings.isMobile ? [] : [ ActionCollection.holdAction , ActionCollection.recordAction , ActionCollection.muteCaptureAction , ActionCollection.mutePlaybackAction, ActionCollection.hangupAction , ActionCollection.transferAction , ActionCollection.acceptAction , ActionCollection.newCallAction ] } diff --git a/views/basic/qml/globaldrawer.qml b/views/basic/qml/globaldrawer.qml index 5ba839fc..f8ae29ae 100644 --- a/views/basic/qml/globaldrawer.qml +++ b/views/basic/qml/globaldrawer.qml @@ -1,101 +1,125 @@ /* * Copyright 2018 Fabian Riethmayer * Copyright 2019 Emmanuel Lepage * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 3, 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.6 as Kirigami import net.lvindustries.ringqtquick 1.0 as RingQtQuick import org.kde.ringkde.jamicontactview 1.0 as JamiContactView Kirigami.GlobalDrawer { id: globalDrawer topPadding: 0 actions: [ actionCollection.settings, actionCollection.quitAction, ] /** * List the active account profile. * * A profile is "our own" contact. There is one or more account per profile. */ topContent: ListView { y: 5 id: availableAccounts model: RingSession.profileModel.availableProfileModel interactive: false height: contentHeight spacing: 5 Layout.preferredWidth: globalDrawer.width Layout.preferredHeight: contentHeight Layout.leftMargin: -globalDrawer.leftPadding delegate: ToolBar { width: parent.width height: Kirigami.Units.iconSizes.large * 1.5 MouseArea { anchors.fill: parent RowLayout { width: parent.width height: Kirigami.Units.iconSizes.large anchors.verticalCenter: parent.verticalCenter JamiContactView.ContactPhoto { width: Kirigami.Units.iconSizes.large height: Kirigami.Units.iconSizes.large individual: object } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Kirigami.Heading { level: 2 text: object.bestName Layout.fillWidth: true } Kirigami.Heading { level: 3 color: Kirigami.Theme.positiveTextColor text: "online" Layout.fillWidth: true Layout.fillHeight: true } } + + ColumnLayout { + Layout.fillHeight: true + Layout.preferredWidth: Kirigami.Units.iconSizes.small + + Kirigami.Icon { + Layout.preferredHeight: Kirigami.Units.iconSizes.small + Layout.preferredWidth: Kirigami.Units.iconSizes.small + source: "view-refresh" + MouseArea { + anchors.fill: parent + onClicked: { + console.log("RELOAD", model.object) + RingSession.profileModel.reloadAllAccount( + model.object + ) + } + } + } + + Item { + Layout.fillHeight: true + } + } } onClicked: { var component = Qt.createComponent("qrc:/account/qml/presenceselector.qml") if (component.status == Component.Ready) { var window = component.createObject(applicationWindow().contentItem) window.individual = object globalDrawer.drawerOpen = false window.open() } else console.log("ERROR", component.status, component.errorString()) } } } } }