diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-08-16 23:27:51 -0600 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-08-17 20:02:43 -0600 |
commit | de4be82bf141f1eb5f57189bf251123e57996f28 (patch) | |
tree | 28701506e5e77af0120b25f52aed02f252cb12ac /framework/qml/ConversationListView.qml | |
parent | a855b61ace6572e19c305cdee7bd080c5f89eb51 (diff) | |
download | kube-de4be82bf141f1eb5f57189bf251123e57996f28.tar.gz kube-de4be82bf141f1eb5f57189bf251123e57996f28.zip |
Non listview based conversationview
The listview deals badly with non uniformly sized items.
We use the buffer hack to ensure all items are loaded so it works at
all, and setting the current index resulted in unpredictable scrolling.
With this new approach we manage everything ourselves in a Flickable,
and just always load all delegates (which we also did before, but with a
hack). As an optimization it should be possible to avoid loading some
delegates until they become visible.
Note that ConversationView is thightly coupled to ConversationListView
due to dependencies on some properties in the delegate. This could be
handled more elegantly with attached properties.
In any case, this seems to work much, much better.
Diffstat (limited to 'framework/qml/ConversationListView.qml')
-rw-r--r-- | framework/qml/ConversationListView.qml | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/framework/qml/ConversationListView.qml b/framework/qml/ConversationListView.qml new file mode 100644 index 00000000..fb91e14d --- /dev/null +++ b/framework/qml/ConversationListView.qml | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Michael Bohlender, <michael.bohlender@kdemail.net> | ||
3 | * Copyright (C) 2017 Christian Mollekopf, <mollekopf@kolabsystems.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | */ | ||
19 | |||
20 | import QtQuick 2.7 | ||
21 | import QtQuick.Controls 2 | ||
22 | import QtQuick.Layouts 1.1 | ||
23 | import org.kube.framework 1.0 as Kube | ||
24 | |||
25 | import QtQml 2.2 as QtQml | ||
26 | |||
27 | Flickable { | ||
28 | id: root | ||
29 | focus: true | ||
30 | property alias model: repeater.model | ||
31 | property alias delegate: repeater.delegate | ||
32 | property int currentIndex: -1 | ||
33 | |||
34 | property var currentItem: null | ||
35 | |||
36 | function setCurrentItem() { | ||
37 | if (currentItem) { | ||
38 | currentItem.isCurrentItem = false | ||
39 | } | ||
40 | if (currentIndex >= 0 && activeFocus) { | ||
41 | var item = repeater.itemAt(currentIndex) | ||
42 | if (item) { | ||
43 | item.isCurrentItem = true | ||
44 | currentItem = item | ||
45 | } | ||
46 | } else { | ||
47 | currentItem = null | ||
48 | } | ||
49 | } | ||
50 | |||
51 | onCurrentIndexChanged: { | ||
52 | setCurrentItem() | ||
53 | } | ||
54 | |||
55 | onActiveFocusChanged: { | ||
56 | setCurrentItem() | ||
57 | } | ||
58 | |||
59 | //Optimize for view quality | ||
60 | pixelAligned: true | ||
61 | |||
62 | contentWidth: width | ||
63 | contentHeight: col.height | ||
64 | |||
65 | function scrollToIndex(index) { | ||
66 | var item = repeater.itemAt(index) | ||
67 | var pos = item.y | ||
68 | var scrollToEndPos = (root.contentHeight - root.height) | ||
69 | //Avoid scrolling past the end | ||
70 | if (pos < scrollToEndPos) { | ||
71 | root.contentY = pos | ||
72 | } else { | ||
73 | root.contentY = scrollToEndPos | ||
74 | } | ||
75 | } | ||
76 | |||
77 | onContentHeightChanged: { | ||
78 | if (repeater.count) { | ||
79 | //Scroll to the last item | ||
80 | currentIndex = repeater.count - 1 | ||
81 | scrollToIndex(repeater.count - 1) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | property real span : contentY + height | ||
86 | Column { | ||
87 | id: col | ||
88 | width: parent.width | ||
89 | spacing: 2 | ||
90 | Repeater { | ||
91 | id: repeater | ||
92 | onCountChanged: { | ||
93 | for (var i = 0; i < count; i++) { | ||
94 | itemAt(i).index = i | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | function incrementCurrentIndex() { | ||
101 | if (currentIndex < repeater.count - 1) { | ||
102 | currentIndex = currentIndex + 1 | ||
103 | } | ||
104 | } | ||
105 | |||
106 | function decrementCurrentIndex() { | ||
107 | if (currentIndex > 0) { | ||
108 | currentIndex = currentIndex - 1 | ||
109 | } | ||
110 | } | ||
111 | |||
112 | Keys.onDownPressed: { | ||
113 | incrementCurrentIndex() | ||
114 | scrollToIndex(currentIndex) | ||
115 | } | ||
116 | |||
117 | Keys.onUpPressed: { | ||
118 | decrementCurrentIndex() | ||
119 | scrollToIndex(currentIndex) | ||
120 | } | ||
121 | |||
122 | Kube.ScrollHelper { | ||
123 | id: scrollHelper | ||
124 | flickable: root | ||
125 | anchors.fill: parent | ||
126 | } | ||
127 | |||
128 | //Intercept all scroll events, | ||
129 | //necessary due to the webengineview | ||
130 | Kube.MouseProxy { | ||
131 | anchors.fill: parent | ||
132 | target: scrollHelper | ||
133 | forwardWheelEvents: true | ||
134 | } | ||
135 | |||
136 | ScrollBar.vertical: ScrollBar {} | ||
137 | |||
138 | } | ||