Merge lp:~phablet-team/messaging-app/improve-participants-screen into lp:messaging-app/staging

Proposed by Tiago Salem Herrmann
Status: Merged
Approved by: Tiago Salem Herrmann
Approved revision: 665
Merged at revision: 659
Proposed branch: lp:~phablet-team/messaging-app/improve-participants-screen
Merge into: lp:messaging-app/staging
Prerequisite: lp:~phablet-team/messaging-app/configure_sort
Diff against target: 832 lines (+325/-189)
11 files modified
debian/control (+1/-1)
src/main.cpp (+0/-3)
src/messagingapplication.cpp (+1/-0)
src/qml/FavoriteChannels.qml (+93/-0)
src/qml/GroupChatInfoPage.qml (+137/-149)
src/qml/MainPage.qml (+15/-4)
src/qml/Messages.qml (+59/-21)
src/qml/ParticipantDelegate.qml (+3/-2)
src/qml/SettingsPage.qml (+3/-3)
src/qml/ThreadDelegate.qml (+6/-6)
src/qml/messaging-app.qml (+7/-0)
To merge this branch: bzr merge lp:~phablet-team/messaging-app/improve-participants-screen
Reviewer Review Type Date Requested Status
Tiago Salem Herrmann (community) Approve
Review via email: mp+316774@code.launchpad.net

Commit message

Improve participants screen performance

Description of the change

Improve participants screen performance

To post a comment you must log in.
642. By Tiago Salem Herrmann

merge parent

643. By Tiago Salem Herrmann

merge parent branch

644. By Tiago Salem Herrmann

merge parent branch

645. By Tiago Salem Herrmann

merge parent branch

646. By Tiago Salem Herrmann

Enable chat states dinamically

647. By Renato Araujo Oliveira Filho

Parent merged.

648. By Renato Araujo Oliveira Filho

Added 'qtdeclarative5-ubuntu-keyboard-extensions0.1' as app dep.

649. By Renato Araujo Oliveira Filho

Add a configaration option to disconnect from server on application exit.

650. By Renato Araujo Oliveira Filho

Allow to favorite a channels and store it on settings.

651. By Renato Araujo Oliveira Filho

Save favorite channes by account.

652. By Renato Araujo Oliveira Filho

Revert changes related with disabling unactive channels.

653. By Renato Araujo Oliveira Filho

Use ChatEntry object on delegates to check if the channel is connected or not.

654. By Renato Araujo Oliveira Filho

Avoid auto-connect on channels.

655. By Renato Araujo Oliveira Filho

Removed deprecated code.

656. By Renato Araujo Oliveira Filho

Fixed favorites settings.

Remove '\' from account id before save on settings to avoid it to be saved as section.

657. By Renato Araujo Oliveira Filho

merged.

658. By Tiago Salem Herrmann

merge parent branch

659. By Tiago Salem Herrmann

merge parent

660. By Tiago Salem Herrmann

fix missing ,

661. By Tiago Salem Herrmann

fix other typos

662. By Tiago Salem Herrmann

merge parent branch

Revision history for this message
Tiago Salem Herrmann (tiagosh) wrote :

Just one request to remove some code, looks good otherwise.

review: Needs Fixing
663. By Tiago Salem Herrmann

remove unused code

664. By Renato Araujo Oliveira Filho

Remove changes about 'disconnectOnQuit' this is not necessary this will be handled by server side.

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

> Just one request to remove some code, looks good otherwise.
Fixed.

665. By Renato Araujo Oliveira Filho

Removed empty function.

Revision history for this message
Tiago Salem Herrmann (tiagosh) wrote :

looks good. thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2017-03-22 20:57:29 +0000
3+++ debian/control 2017-03-22 20:57:29 +0000
4@@ -26,7 +26,6 @@
5 qtdeclarative5-ubuntu-content1,
6 qtdeclarative5-ubuntu-addressbook0.1,
7 qtdeclarative5-ubuntu-thumbnailer0.1,
8- qtdeclarative5-ubuntu-keyboard-extensions0.1,
9 qtdeclarative5-qtcontacts-plugin,
10 qtdeclarative5-folderlistmodel-plugin,
11 qtmultimedia5-dev,
12@@ -52,6 +51,7 @@
13 qtdeclarative5-ubuntu-telephony-phonenumber0.1,
14 qtdeclarative5-ubuntu-history0.1 | qtdeclarative5-ubuntu-history-plugin,
15 qtdeclarative5-ubuntu-telephony0.1 | qtdeclarative5-ubuntu-telephony-plugin,
16+ qtdeclarative5-ubuntu-keyboard-extensions0.1,
17 qtdeclarative5-qtcontacts-plugin,
18 qtdeclarative5-gsettings1.0,
19 qml-module-qt-labs-settings,
20
21=== modified file 'src/main.cpp'
22--- src/main.cpp 2014-08-26 19:07:12 +0000
23+++ src/main.cpp 2017-03-22 20:57:29 +0000
24@@ -42,9 +42,6 @@
25 // as it doesn’t play well with QtFolks.
26 int main(int argc, char** argv)
27 {
28- QGuiApplication::setApplicationName("Messaging App");
29- QGuiApplication::setOrganizationName("com.ubuntu.messaging-app");
30-
31 MessagingApplication application(argc, argv);
32
33 if (!application.setup()) {
34
35=== modified file 'src/messagingapplication.cpp'
36--- src/messagingapplication.cpp 2017-03-22 20:57:29 +0000
37+++ src/messagingapplication.cpp 2017-03-22 20:57:29 +0000
38@@ -90,6 +90,7 @@
39 : QGuiApplication(argc, argv), m_view(0), m_applicationIsReady(false)
40 {
41 setApplicationName("MessagingApp");
42+ setOrganizationName("com.ubuntu.messaging-app");
43 }
44
45 bool MessagingApplication::fullscreen() const
46
47=== added file 'src/qml/FavoriteChannels.qml'
48--- src/qml/FavoriteChannels.qml 1970-01-01 00:00:00 +0000
49+++ src/qml/FavoriteChannels.qml 2017-03-22 20:57:29 +0000
50@@ -0,0 +1,93 @@
51+/*
52+ * Copyright 2012-2016 Canonical Ltd.
53+ *
54+ * This file is part of messaging-app.
55+ *
56+ * messaging-app is free software; you can redistribute it and/or modify
57+ * it under the terms of the GNU General Public License as published by
58+ * the Free Software Foundation; version 3.
59+ *
60+ * messaging-app is distributed in the hope that it will be useful,
61+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
62+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63+ * GNU General Public License for more details.
64+ *
65+ * You should have received a copy of the GNU General Public License
66+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
67+ */
68+
69+import QtQuick 2.2
70+import Qt.labs.settings 1.0
71+
72+
73+Item {
74+ property var _favoritesByAccount: []
75+
76+
77+ function getFavoriteChannels(account)
78+ {
79+ var settings = settingsFromAccount(account)
80+ return favoriteChannels(settings)
81+ }
82+
83+ function favoriteIndex(account, fav)
84+ {
85+ return getFavoriteChannels(account).indexOf(fav)
86+ }
87+
88+ function isFavorite(account, fav)
89+ {
90+ return (favoriteIndex(account, fav) !== -1)
91+ }
92+
93+ function addFavorite(account, fav) {
94+ var settings = settingsFromAccount(account)
95+ if (favoriteIndexFromSettings(settings, fav) === -1) {
96+ settings.favoriteChannels += ";" + fav
97+ }
98+ }
99+
100+ function removeFavorite(account, fav) {
101+ var settings = settingsFromAccount(account)
102+ var index = favoriteIndexFromSettings(settings, fav)
103+ if (index !== -1) {
104+ var list = settings.favoriteChannels.split(";")
105+ list.splice(index, 1)
106+ settings.favoriteChannels = list.join(";")
107+ }
108+ }
109+
110+ // private
111+ function settingsFromAccount(account) {
112+ var account_ = account.replace(/\//g,"#")
113+ if (account_ in _favoritesByAccount) {
114+ return _favoritesByAccount[account_]
115+ } else {
116+ var settings = favoriteByAccountComponent.createObject(this, {'category': account_})
117+ _favoritesByAccount[account_] = settings
118+ return settings
119+ }
120+ }
121+
122+ function favoriteIndexFromSettings(settings, fav)
123+ {
124+ return settings.favoriteChannels.split(";").indexOf(fav)
125+ }
126+
127+ function favoriteChannels(settings)
128+ {
129+ if (settings.favoriteChannels.length > 0) {
130+ return settings.favoriteChannels.split(";")
131+ } else {
132+ return []
133+ }
134+ }
135+
136+ Component {
137+ id: favoriteByAccountComponent
138+ Settings {
139+ objectName: "settings_" + category
140+ property string favoriteChannels: ""
141+ }
142+ }
143+}
144
145=== modified file 'src/qml/GroupChatInfoPage.qml'
146--- src/qml/GroupChatInfoPage.qml 2017-03-22 20:57:29 +0000
147+++ src/qml/GroupChatInfoPage.qml 2017-03-22 20:57:29 +0000
148@@ -56,9 +56,19 @@
149 }
150 return []
151 }
152+
153+ ParticipantsModel {
154+ id: participantsModel
155+ chatEntry: groupChatInfoPage.chatEntry.active ? groupChatInfoPage.chatEntry : null
156+ }
157+
158+ property var participantsSize: participants.length + localPendingParticipants.length + remotePendingParticipants.length
159+
160 property variant allParticipants: {
161 var participantList = []
162-
163+ if (chatEntry.active) {
164+ return participantList
165+ }
166 for (var i in participants) {
167 var participant = participants[i]
168 participant["state"] = 0
169@@ -84,6 +94,7 @@
170 participantList.push(participant)
171 }
172 }
173+ participantList.sort(function(a,b) {return (a.identifier.toLowerCase() > b.identifier.toLowerCase()) ? 1 : ((b.identifier.toLowerCase() > a.identifier.toLowerCase()) ? -1 : 0);} );
174 return participantList
175 }
176
177@@ -158,7 +169,34 @@
178 title: groupChatInfoPage.headerString
179 // FIXME: uncomment once the header supports subtitle
180 //subtitle: i18n.tr("%1 member", "%1 members", allParticipants.length)
181- flickable: contentsFlickable
182+
183+ trailingActionBar {
184+ id: trailingBar
185+ actions: [
186+ Action {
187+ iconName: "close"
188+ text: i18n.tr("End group")
189+ onTriggered: destroyGroup()
190+ enabled: chatRoom && !isPhoneAccount && chatEntry.active && chatEntry.selfContactRoles & 2
191+ visible: enabled
192+ },
193+ Action {
194+ iconName: "system-log-out"
195+ text: groupChatInfoPage.leaveString
196+ visible: enabled
197+ onTriggered: {
198+ if (chatEntry.leaveChat()) {
199+ application.showNotificationMessage(groupChatInfoPage.leaveSuccessString, "tick")
200+ mainView.emptyStack()
201+ } else {
202+ application.showNotificationMessage(groupChatInfoPage.leaveFailedString, "dialog-error-symbolic")
203+ }
204+
205+ }
206+ enabled: chatRoom && !isPhoneAccount && chatEntry.active && !(chatEntry.selfContactRoles & 2)
207+ }
208+ ]
209+ }
210 }
211
212 function addRecipientFromSearch(identifier, alias, avatar) {
213@@ -166,12 +204,25 @@
214 }
215
216 function addRecipient(identifier, contact) {
217- for (var i=0; i < allParticipants; i++) {
218- if (identifier == allParticipants[i].identifier) {
219- application.showNotificationMessage(i18n.tr("This recipient was already selected"), "dialog-error-symbolic")
220- return
221- }
222- }
223+ for (var i=0; i < participants; i++) {
224+ if (identifier == participants[i].identifier) {
225+ application.showNotificationMessage(i18n.tr("This recipient was already selected"), "dialog-error-symbolic")
226+ return
227+ }
228+ }
229+ for (var i=0; i < localPendingParticipants; i++) {
230+ if (identifier == localPendingParticipants[i].identifier) {
231+ application.showNotificationMessage(i18n.tr("This recipient was already selected"), "dialog-error-symbolic")
232+ return
233+ }
234+ }
235+ for (var i=0; i < remotePendingParticipants; i++) {
236+ if (identifier == remotePendingParticipants[i].identifier) {
237+ application.showNotificationMessage(i18n.tr("This recipient was already selected"), "dialog-error-symbolic")
238+ return
239+ }
240+ }
241+
242 searchItem.text = ""
243
244 chatEntry.inviteParticipants([identifier], "")
245@@ -195,30 +246,22 @@
246 }
247 }
248
249- Flickable {
250+ ListView {
251 id: contentsFlickable
252- property var emptySpaceHeight: height - contentsColumn.topItemsHeight+contentsFlickable.contentY
253 anchors {
254- top: parent.top
255+ top: groupChatInfoPage.header.top
256+ topMargin: groupChatInfoPage.header.height
257 left: parent.left
258 right: parent.right
259 bottom: keyboard.top
260 }
261- contentHeight: contentsColumn.height
262- clip: true
263-
264- Column {
265- id: contentsColumn
266- property var topItemsHeight: groupInfo.height+participantsHeader.height+searchItem.height+units.gu(1)
267-
268+
269+ header: Item {
270 anchors {
271- top: parent.top
272 left: parent.left
273 right: parent.right
274 }
275-
276 height: childrenRect.height
277-
278 Item {
279 id: groupInfo
280 height: visible ? groupAvatar.height + groupAvatar.anchors.topMargin + units.gu(1) : 0
281@@ -226,6 +269,7 @@
282 enabled: chatEntry.active
283
284 anchors {
285+ top: parent.top
286 left: parent.left
287 right: parent.right
288 }
289@@ -306,18 +350,11 @@
290 }
291 }
292
293- ListItems.ThinDivider {
294- visible: groupInfo.visible
295- anchors {
296- left: parent.left
297- right: parent.right
298- }
299- }
300-
301 Item {
302 id: participantsHeader
303 enabled: chatEntry.active
304 anchors {
305+ top: groupInfo.bottom
306 left: parent.left
307 right: parent.right
308 }
309@@ -330,7 +367,7 @@
310 leftMargin: units.gu(2)
311 verticalCenter: addParticipantButton.verticalCenter
312 }
313- text: !searchItem.enabled ? i18n.tr("Participants: %1").arg(allParticipants.length) : i18n.tr("Add participant:")
314+ text: !searchItem.enabled ? i18n.tr("Participants: %1").arg(participantsSize) : i18n.tr("Add participant:")
315 }
316
317 Button {
318@@ -360,22 +397,16 @@
319 }
320 }
321
322- ListItems.ThinDivider {
323- anchors {
324- left: parent.left
325- right: parent.right
326- }
327- }
328-
329 ContactSearchWidget {
330 id: searchItem
331 enabled: false
332 height: enabled ? units.gu(6) : 0
333 clip: true
334 parentPage: groupChatInfoPage
335- searchResultsHeight: contentsFlickable.emptySpaceHeight
336+ searchResultsHeight: keyboard.y-y-height
337 onContactPicked: addRecipientFromSearch(identifier, alias, avatar)
338 anchors {
339+ top: participantsHeader.bottom
340 left: parent.left
341 right: parent.right
342 }
343@@ -383,124 +414,81 @@
344 UbuntuNumberAnimation {}
345 }
346 }
347+ }
348
349- ListItems.ThinDivider {
350- visible: searchItem.enabled
351- anchors {
352- left: parent.left
353- right: parent.right
354- }
355+ ListItemActions {
356+ id: participantLeadingActions
357+ delegate: Label {
358+ anchors.verticalCenter: parent.verticalCenter
359+ anchors.horizontalCenter: parent.horizontalCenter
360+ height: contentHeight
361+ width: contentWidth+units.gu(2)
362+ verticalAlignment: Text.AlignVCenter
363+ horizontalAlignment: Text.AlignHCenter
364+ text: i18n.tr("Remove")
365 }
366-
367-
368- ListItemActions {
369- id: participantLeadingActions
370- delegate: Label {
371- anchors.verticalCenter: parent.verticalCenter
372- anchors.horizontalCenter: parent.horizontalCenter
373- height: contentHeight
374- width: contentWidth+units.gu(2)
375- verticalAlignment: Text.AlignVCenter
376- horizontalAlignment: Text.AlignHCenter
377+ actions: [
378+ Action {
379 text: i18n.tr("Remove")
380- }
381- actions: [
382- Action {
383- text: i18n.tr("Remove")
384- onTriggered: {
385- // in case account is not a phone one, alert that if the group is going to have no active participants
386- // it can be dissolved by the server
387- if (chatEntry.chatType == ChatEntry.ChatTypeRoom && chatEntry.participants.length === 1 /*the active participant to remove now*/) {
388- var properties = {}
389- properties["groupName"] = groupName.text
390- PopupUtils.open(Qt.createComponent("Dialogs/EmptyGroupWarningDialog.qml").createObject(groupChatInfoPage), groupChatInfoPage, properties)
391- } else {
392- var delegate = participantsRepeater.itemAt(value)
393- delegate.removeFromGroup();
394- }
395- }
396- }
397- ]
398- }
399-
400- Repeater {
401- id: participantsRepeater
402- model: allParticipants
403-
404- ParticipantDelegate {
405- id: participantDelegate
406- function canRemove() {
407- if (!groupChatInfoPage.chatRoom /*not a group*/
408- || !chatEntry.active /*not active*/
409- || modelData.roles & 2 /*not admin*/
410- || modelData.state === 2 /*remote pending*/) {
411- return false
412- }
413- // temporary workaround
414- if (account && account.protocolInfo.name == "irc") {
415- return false
416- }
417- return (chatEntry.groupFlags & ChatEntry.ChannelGroupFlagCanRemove)
418- }
419- function removeFromGroup() {
420- var participant = participantDelegate.participant
421- chatEntry.removeParticipants([participant.identifier], "")
422- participantDelegate.height = 0
423- }
424- participant: modelData
425- leadingActions: canRemove() ? participantLeadingActions : undefined
426- onClicked: {
427- if (openProfileButton.visible) {
428- mainStack.addPageToCurrentColumn(groupChatInfoPage, Qt.resolvedUrl("ParticipantInfoPage.qml"), {"delegate": participantDelegate, "chatEntry": chatEntry, "chatRoom": chatRoom})
429- }
430- }
431- Icon {
432- id: openProfileButton
433- anchors.right: parent.right
434- anchors.rightMargin: units.gu(1)
435- anchors.verticalCenter: parent.verticalCenter
436- height: units.gu(2)
437- name: "go-next"
438- }
439- }
440- }
441- Item {
442- id: padding
443- height: units.gu(3)
444- anchors.left: parent.left
445+ onTriggered: {
446+ // in case account is not a phone one, alert that if the group is going to have no active participants
447+ // it can be dissolved by the server
448+ if (chatEntry.chatType == ChatEntry.ChatTypeRoom && chatEntry.participants.length === 1 /*the active participant to remove now*/) {
449+ var properties = {}
450+ properties["groupName"] = groupName.text
451+ PopupUtils.open(Qt.createComponent("Dialogs/EmptyGroupWarningDialog.qml").createObject(groupChatInfoPage), groupChatInfoPage, properties)
452+ } else {
453+ var delegate = contentsFlickable.itemAt(value)
454+ delegate.removeFromGroup();
455+ }
456+ }
457+ }
458+ ]
459+ }
460+
461+ model: chatEntry.active ? participantsModel : allParticipants
462+
463+ delegate: ParticipantDelegate {
464+ id: participantDelegate
465+ function canRemove() {
466+ if (!groupChatInfoPage.chatRoom /*not a group*/
467+ || !chatEntry.active /*not active*/
468+ || model.roles & 2 /*not admin*/
469+ || model.state === 2 /*remote pending*/) {
470+ return false
471+ }
472+ // temporary workaround
473+ if (account && account.protocolInfo.name == "irc") {
474+ return false
475+ }
476+ return (chatEntry.groupFlags & ChatEntry.ChannelGroupFlagCanRemove)
477+ }
478+ function removeFromGroup() {
479+ var participant = participantDelegate.participant
480+ chatEntry.removeParticipants([participant.identifier], "")
481+ participantDelegate.height = 0
482+ }
483+ participant: chatEntry.active ? model : modelData
484+ leadingActions: canRemove() ? participantLeadingActions : null
485+ onClicked: {
486+ if (openProfileButton.visible) {
487+ mainStack.addPageToCurrentColumn(groupChatInfoPage, Qt.resolvedUrl("ParticipantInfoPage.qml"), {"delegate": participantDelegate, "chatEntry": chatEntry, "chatRoom": chatRoom})
488+ }
489+ }
490+ Icon {
491+ id: openProfileButton
492 anchors.right: parent.right
493- }
494- Row {
495- enabled: chatEntry.active
496- anchors {
497- right: parent.right
498- rightMargin: units.gu(2)
499- }
500- layoutDirection: Qt.RightToLeft
501- spacing: units.gu(1)
502- Button {
503- id: destroyButton
504- visible: chatRoom && !isPhoneAccount && chatEntry.active && chatEntry.selfContactRoles & 2
505- text: i18n.tr("End group")
506- color: Theme.palette.normal.negative
507- onClicked: destroyGroup()
508- }
509- Button {
510- id: leaveButton
511- visible: chatRoom && !isPhoneAccount && chatEntry.active && !(chatEntry.selfContactRoles & 2)
512- text: groupChatInfoPage.leaveString
513- onClicked: {
514- if (chatEntry.leaveChat()) {
515- application.showNotificationMessage(groupChatInfoPage.leaveSuccessString, "tick")
516- mainView.emptyStack()
517- } else {
518- application.showNotificationMessage(groupChatInfoPage.leaveFailedString, "dialog-error-symbolic")
519- }
520- }
521- }
522+ anchors.rightMargin: units.gu(1)
523+ anchors.verticalCenter: parent.verticalCenter
524+ height: units.gu(2)
525+ name: "go-next"
526 }
527 }
528 }
529+ Scrollbar {
530+ flickableItem: contentsFlickable
531+ align: Qt.AlignTrailing
532+ }
533 KeyboardRectangle {
534 id: keyboard
535 }
536
537=== modified file 'src/qml/MainPage.qml'
538--- src/qml/MainPage.qml 2017-03-22 20:57:29 +0000
539+++ src/qml/MainPage.qml 2017-03-22 20:57:29 +0000
540@@ -210,7 +210,7 @@
541 id: sectionDelegate
542 ThreadsSectionDelegate {
543 function formatSectionTitle(title) {
544- if (mainView.sortTrheadsBy === "timestamp")
545+ if (mainView.sortThreadsBy === "timestamp")
546 return DateUtils.friendlyDay(Qt.formatDate(section, "yyyy/MM/dd"), i18n);
547 else if (telepathyHelper.ready)
548 return telepathyHelper.accountForId(title).displayName
549@@ -238,7 +238,7 @@
550 clip: true
551 currentIndex: -1
552 //spacing: searchField.text === "" ? units.gu(-2) : 0
553- section.property: mainView.sortTrheadsBy === "title" ? "accountId" : "eventDate"
554+ section.property: mainView.sortThreadsBy === "title" ? "accountId" : "eventDate"
555 section.delegate: searching && searchField.text !== "" ? null : sectionDelegate
556 header: ListItem.Standard {
557 // FIXME: update
558@@ -279,15 +279,15 @@
559 if (displayedEvent != null) {
560 properties["scrollToEventId"] = displayedEvent.eventId
561 }
562+ properties["chatEntry"] = chatEntry
563 delete properties["participants"]
564 delete properties["localPendingParticipants"]
565 delete properties["remotePendingParticipants"]
566 mainView.showMessagesView(properties)
567 }
568
569-
570 // FIXME: find a better unique name
571- objectName: "thread%1".arg(participants[0].identifier)
572+ objectName: "thread%1".arg(participants.length > 0 ? participants[0].identifier : "")
573 Component.onCompleted: mainPage.newThreadCreated(model)
574
575 anchors {
576@@ -321,6 +321,17 @@
577 threadList.startSelection()
578 threadList.selectItem(threadDelegate)
579 }
580+
581+ ChatEntry {
582+ id: chatEntry
583+ chatType: model.properties.chatType
584+ participantIds: model.properties.participantIds
585+ chatId: model.properties.threadId
586+ accountId: model.properties.accountId
587+ autoRequest: false
588+ }
589+
590+ opacity: !groupChat || chatEntry.active ? 1.0 : 0.5
591 }
592 onSelectionDone: {
593 var threadsToRemove = []
594
595=== modified file 'src/qml/Messages.qml'
596--- src/qml/Messages.qml 2017-03-22 20:57:29 +0000
597+++ src/qml/Messages.qml 2017-03-22 20:57:29 +0000
598@@ -94,7 +94,7 @@
599 property var accountsModel: getAccountsModel()
600 property alias oskEnabled: keyboard.oskEnabled
601 property bool isReady: false
602- property QtObject chatEntry: chatEntryObject
603+ property QtObject chatEntry
604 property string firstRecipientAlias: ((contactWatcher.isUnknown &&
605 contactWatcher.isInteractive) ||
606 contactWatcher.alias === "") ? contactWatcher.identifier : contactWatcher.alias
607@@ -104,6 +104,19 @@
608 property bool isBroadcast: chatType != ChatEntry.ChatTypeRoom && (participantIds.length > 1 || multiRecipient.recipientCount > 1)
609
610 property alias validator: sendMessageValidator
611+ property string chatTitle: {
612+ if (chatEntry.title !== "") {
613+ return chatEntry.title
614+ }
615+ var roomInfo = threadInformation.chatRoomInfo
616+ if (roomInfo.Title != "") {
617+ return roomInfo.Title
618+ } else if (roomInfo.RoomName != "") {
619+ return roomInfo.RoomName
620+ }
621+ return ""
622+ }
623+
624
625 signal ready
626 signal cancel
627@@ -679,6 +692,17 @@
628 visible: enabled
629 iconName: "view-refresh"
630 onTriggered: messages.chatEntry.startChat()
631+ },
632+ Action {
633+ id: favoriteAction
634+ visible: chatEntry.active && (messages.chatType == HistoryThreadModel.ChatTypeRoom)
635+ iconName: mainView.favoriteChannels.isFavorite(messages.accountId, messages.chatTitle) ? "starred" : "non-starred"
636+ onTriggered: {
637+ if (iconName == "starred")
638+ mainView.favoriteChannels.removeFavorite(messages.accountId, messages.chatTitle)
639+ else
640+ mainView.favoriteChannels.addFavorite(messages.accountId, messages.chatTitle)
641+ }
642 }
643
644 ]
645@@ -689,15 +713,10 @@
646 title: {
647 var finalParticipants = (participants ? participants.length : 0)
648 if (messages.chatType == HistoryThreadModel.ChatTypeRoom) {
649- if (chatEntry.title !== "") {
650- return chatEntry.title
651- }
652- var roomInfo = threadInformation.chatRoomInfo
653- if (roomInfo.Title != "") {
654- return roomInfo.Title
655- } else if (roomInfo.RoomName != "") {
656- return roomInfo.RoomName
657- }
658+ if (messages.chatTitle != "") {
659+ return messages.chatTitle
660+ }
661+
662 // include the "Me" participant to be consistent with
663 // group info page
664 if (roomInfo.Joined) {
665@@ -851,6 +870,10 @@
666 ]
667
668 Component.onCompleted: {
669+ if (!chatEntry) {
670+ chatEntry = chatEntryComponent.createObject(this)
671+ }
672+
673 // we only revert back to phone account if this is a 1-1 chat,
674 // in which case the handler will fallback to multimedia if needed
675 if (messages.accountId !== "" && chatType !== HistoryThreadModel.ChatTypeRoom) {
676@@ -1040,16 +1063,22 @@
677 }
678 }
679
680- ChatEntry {
681- id: chatEntryObject
682- chatType: messages.chatType
683- participantIds: messages.participantIds
684- chatId: messages.threadId
685- accountId: messages.accountId
686- autoRequest: !newMessage && !messages.account.protocolInfo.enableRejoin
687-
688+ Component {
689+ id: chatEntryComponent
690+
691+ ChatEntry {
692+ id: chatEntryObject
693+ chatType: messages.chatType
694+ participantIds: messages.participantIds
695+ chatId: messages.threadId
696+ accountId: messages.accountId
697+ }
698+ }
699+
700+ Connections {
701+ target: messages.chatEntry
702 onChatTypeChanged: {
703- messages.chatType = chatEntryObject.chatType
704+ messages.chatType = chatEntry.chatType
705 }
706
707 onMessageSent: {
708@@ -1066,9 +1095,15 @@
709 }
710 }
711
712+ Binding {
713+ target: messages.chatEntry
714+ property: "autoRequest"
715+ value: !messages.newMessage && !messages.account.protocolInfo.enableRejoin
716+ }
717+
718 Repeater {
719- model: messages.chatEntry.chatStates
720- Item {
721+ model: account.protocolInfo.enableChatStates ? messages.chatEntry.chatStates : null
722+ delegate: Item {
723 function processChatState() {
724 if (modelData.state == ChatEntry.ChannelChatStateComposing) {
725 messages.userTyping = true
726@@ -1458,6 +1493,9 @@
727 maxHeight: messages.height - keyboard.height - screenTop.y
728 text: messages.text
729 onTextChanged: {
730+ if (!account.protocolInfo.enableChatStates) {
731+ return
732+ }
733 if (text == "" && !composeBar.inputMethodComposing) {
734 messages.chatEntry.setChatState(ChatEntry.ChannelChatStateActive)
735 selfTypingTimer.stop()
736
737=== modified file 'src/qml/ParticipantDelegate.qml'
738--- src/qml/ParticipantDelegate.qml 2016-10-18 13:32:28 +0000
739+++ src/qml/ParticipantDelegate.qml 2017-03-22 20:57:29 +0000
740@@ -51,9 +51,10 @@
741 id: avatar
742 enabled: true
743 fallbackAvatarUrl: {
744- if (participant.avatar !== "") {
745+ if (participant && participant.avatar && participant.avatar !== "") {
746+ console.log(participant.avatar)
747 return participant.avatar
748- } else if (participant.alias === "") {
749+ } else if (participant && participant.alias === "") {
750 return "image://theme/contact"
751 }
752 return ""
753
754=== modified file 'src/qml/SettingsPage.qml'
755--- src/qml/SettingsPage.qml 2017-03-22 20:57:29 +0000
756+++ src/qml/SettingsPage.qml 2017-03-22 20:57:29 +0000
757@@ -34,7 +34,7 @@
758 readonly property var setMethods: {
759 "mmsEnabled": function(value) { telepathyHelper.mmsEnabled = value },
760 "threadSort": function(value) { mainView.sortThreadsBy = value },
761- "compactView": function(value) { mainView.compactView = value }
762+ "compactView": function(value) { mainView.compactView = value },
763 //"characterCountEnabled": function(value) { msgSettings.showCharacterCount = value }
764 }
765
766@@ -66,8 +66,8 @@
767 { "type": "options",
768 "data": { "name": "threadSort",
769 "description": i18n.tr("Sort threads"),
770- "currentValue": mainView.sortTrheadsBy,
771- "subtitle": settingsPage.sortByModel[mainView.sortTrheadsBy],
772+ "currentValue": mainView.sortThreadsBy,
773+ "subtitle": settingsPage.sortByModel[mainView.sortThreadsBy],
774 "options": sortByModel,
775 "setMethod": "threadSort"}
776 }
777
778=== modified file 'src/qml/ThreadDelegate.qml'
779--- src/qml/ThreadDelegate.qml 2017-03-22 20:57:29 +0000
780+++ src/qml/ThreadDelegate.qml 2017-03-22 20:57:29 +0000
781@@ -373,10 +373,10 @@
782
783 Item {
784 id: delegateHelper
785- property string phoneNumber: participant.identifier
786- property string alias: participant.alias ? participant.alias : ""
787- property string avatar: participant.avatar ? participant.avatar : ""
788- property string contactId: participant.contactId ? participant.contactId : ""
789+ property string phoneNumber: participant ? participant.identifier : ""
790+ property string alias: participant && participant.alias ? participant.alias : ""
791+ property string avatar: participant && participant.avatar ? participant.avatar : ""
792+ property string contactId: participant && participant.contactId ? participant.contactId : ""
793 property alias subTypes: phoneDetail.subTypes
794 property alias contexts: phoneDetail.contexts
795 property bool isUnknown: contactId === ""
796@@ -509,8 +509,8 @@
797
798 PhoneNumber {
799 id: phoneDetail
800- contexts: participant.phoneContexts ? participant.phoneContexts : []
801- subTypes: participant.phoneSubTypes ? participant.phoneSubTypes : []
802+ contexts: participant && participant.phoneContexts ? participant.phoneContexts : []
803+ subTypes: participant && participant.phoneSubTypes ? participant.phoneSubTypes : []
804 }
805
806 ContactDetailPhoneNumberTypeModel {
807
808=== modified file 'src/qml/messaging-app.qml'
809--- src/qml/messaging-app.qml 2017-03-22 20:57:29 +0000
810+++ src/qml/messaging-app.qml 2017-03-22 20:57:29 +0000
811@@ -39,9 +39,12 @@
812 // settings
813 property alias sortThreadsBy: globalSettings.sortThreadsBy
814 property alias compactView: globalSettings.compactView
815+ property alias favoriteChannels: favoriteChannelsItem
816+
817 // private
818 property var _pendingProperties: null
819
820+
821 function updateNewMessageStatus() {
822 activeMessagesView = application.findMessagingChild("messagesPage", "active", true)
823 }
824@@ -497,4 +500,8 @@
825 layout.completed = true;
826 }
827 }
828+
829+ FavoriteChannels {
830+ id: favoriteChannelsItem
831+ }
832 }

Subscribers

People subscribed via source and target branches

to all changes: