diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-03-22 22:01:59 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-03-22 22:01:59 +0100 |
commit | 51018b7788a87658fd5fccb645a8e808e34d9450 (patch) | |
tree | a865a9800d781f3dae29f32cb85522c8327cf233 | |
parent | 0c91d01eb26793e745138c4598cf15d9a21c0136 (diff) | |
download | kube-51018b7788a87658fd5fccb645a8e808e34d9450.tar.gz kube-51018b7788a87658fd5fccb645a8e808e34d9450.zip |
Mark the currently viewed mail as read.
The listview is absolutely useless with non-uniform entries.
We have to do or own tracking of the current index, we have to do our
own scrolling, the flickable scrolling is horrible with a mouse,
and even though caching all delegates somewhat improves the situation,
it's still laggy every now and then.
However, this now at least works somewhat correctly.
But we'll really have to look for a new solution for this eventually.
-rw-r--r-- | components/package/contents/ui/ConversationView.qml | 115 | ||||
-rw-r--r-- | framework/domain/mailcontroller.cpp | 2 |
2 files changed, 111 insertions, 6 deletions
diff --git a/components/package/contents/ui/ConversationView.qml b/components/package/contents/ui/ConversationView.qml index 3c76928f..6ecc59ae 100644 --- a/components/package/contents/ui/ConversationView.qml +++ b/components/package/contents/ui/ConversationView.qml | |||
@@ -31,11 +31,43 @@ Rectangle { | |||
31 | id: root | 31 | id: root |
32 | 32 | ||
33 | property variant mail; | 33 | property variant mail; |
34 | property int currentIndex: 0; | ||
35 | property bool scrollToEnd: true; | ||
36 | property variant currentMail: null; | ||
37 | onCurrentIndexChanged: { | ||
38 | markAsReadTimer.restart(); | ||
39 | } | ||
40 | onMailChanged: { | ||
41 | scrollToEnd = true; | ||
42 | currentMail = null; | ||
43 | } | ||
34 | 44 | ||
35 | color: Kirigami.Theme.backgroundColor | 45 | color: Kirigami.Theme.backgroundColor |
36 | 46 | ||
37 | ListView { | 47 | ListView { |
38 | id: listView | 48 | id: listView |
49 | function setCurrentIndex() | ||
50 | { | ||
51 | /** | ||
52 | * This will detect the index at the "scrollbar-position" (visibleArea.yPosition). | ||
53 | * This ensures that the first and last entry can become the currentIndex, | ||
54 | * but in the middle of the list the item in the middle is set as the current item. | ||
55 | */ | ||
56 | var yPos = 0.5; | ||
57 | if (listView.visibleArea.yPosition < 0.4) { | ||
58 | yPos = 0.2 + (0.2 * listView.visibleArea.yPosition); | ||
59 | } | ||
60 | if (listView.visibleArea.yPosition > 0.6) { | ||
61 | yPos = 0.6 + (0.2 * listView.visibleArea.yPosition) | ||
62 | } | ||
63 | var indexAtCenter = listView.indexAt(root.width / 2, contentY + root.height * yPos); | ||
64 | if (indexAtCenter >= 0) { | ||
65 | root.currentIndex = indexAtCenter; | ||
66 | } else { | ||
67 | root.currentIndex = count - 1; | ||
68 | } | ||
69 | } | ||
70 | |||
39 | anchors { | 71 | anchors { |
40 | top: parent.top | 72 | top: parent.top |
41 | left: parent.left | 73 | left: parent.left |
@@ -64,13 +96,68 @@ Rectangle { | |||
64 | 96 | ||
65 | boundsBehavior: Flickable.StopAtBounds | 97 | boundsBehavior: Flickable.StopAtBounds |
66 | 98 | ||
67 | //Always scroll to the end of the conversation | 99 | //default is 1500, which is not usable with a mouse |
68 | highlightFollowsCurrentItem: true | 100 | flickDeceleration: 10000 |
69 | //Scroll quickly | 101 | |
70 | highlightMoveDuration: 1 | 102 | //Optimize for view quality |
103 | pixelAligned: true | ||
104 | |||
105 | Timer { | ||
106 | id: scrollToEndTimer | ||
107 | interval: 10 | ||
108 | running: false | ||
109 | repeat: false | ||
110 | onTriggered: { | ||
111 | //Only do this once per conversation | ||
112 | root.scrollToEnd = false; | ||
113 | root.currentIndex = listView.count - 1 | ||
114 | //positionViewAtEnd/Index don't work | ||
115 | listView.contentY = listView.contentHeight - listView.height | ||
116 | } | ||
117 | } | ||
118 | |||
71 | onCountChanged: { | 119 | onCountChanged: { |
72 | //TODO: ideally we should only do this initially, not when new messages enter while you're reading. | 120 | if (root.scrollToEnd) { |
73 | currentIndex = count - 1; | 121 | scrollToEndTimer.restart() |
122 | } | ||
123 | } | ||
124 | |||
125 | onContentHeightChanged: { | ||
126 | //Initially it will resize a lot, so we keep waiting | ||
127 | if (root.scrollToEnd) { | ||
128 | scrollToEndTimer.restart() | ||
129 | } | ||
130 | } | ||
131 | |||
132 | onContentYChanged: { | ||
133 | //We have to track our current mail manually | ||
134 | setCurrentIndex(); | ||
135 | } | ||
136 | |||
137 | //The cacheBuffer needs to be large enough to fit the whole thread. | ||
138 | //Otherwise the contentHeight will constantly increase and decrease, | ||
139 | //which will break lot's of things. | ||
140 | cacheBuffer: 100000 | ||
141 | |||
142 | KubeFramework.MailController { | ||
143 | id: mailController | ||
144 | Binding on mail { | ||
145 | //!! checks for the availability of the type | ||
146 | when: !!root.currentMail | ||
147 | value: root.currentMail | ||
148 | } | ||
149 | } | ||
150 | |||
151 | Timer { | ||
152 | id: markAsReadTimer | ||
153 | interval: 2000 | ||
154 | running: false | ||
155 | repeat: false | ||
156 | onTriggered: { | ||
157 | if (mailController.markAsReadAction.enabled) { | ||
158 | mailController.markAsReadAction.execute(); | ||
159 | } | ||
160 | } | ||
74 | } | 161 | } |
75 | 162 | ||
76 | //Intercept all scroll events, | 163 | //Intercept all scroll events, |
@@ -85,6 +172,13 @@ Rectangle { | |||
85 | id: mailDelegate | 172 | id: mailDelegate |
86 | 173 | ||
87 | Item { | 174 | Item { |
175 | id: wrapper | ||
176 | property bool isCurrent: root.currentIndex === index; | ||
177 | onIsCurrentChanged: { | ||
178 | if (isCurrent) { | ||
179 | root.currentMail = model.mail | ||
180 | } | ||
181 | } | ||
88 | 182 | ||
89 | height: sheet.height + Kirigami.Units.gridUnit | 183 | height: sheet.height + Kirigami.Units.gridUnit |
90 | width: parent.width | 184 | width: parent.width |
@@ -95,6 +189,15 @@ Rectangle { | |||
95 | implicitHeight: header.height + attachments.height + body.height + footer.height + Kirigami.Units.largeSpacing | 189 | implicitHeight: header.height + attachments.height + body.height + footer.height + Kirigami.Units.largeSpacing |
96 | width: parent.width - Kirigami.Units.gridUnit * 2 | 190 | width: parent.width - Kirigami.Units.gridUnit * 2 |
97 | 191 | ||
192 | //Overlay for non-active mails | ||
193 | Rectangle { | ||
194 | anchors.fill: parent | ||
195 | visible: !wrapper.isCurrent | ||
196 | color: "lightGrey" | ||
197 | z: 1 | ||
198 | opacity: 0.2 | ||
199 | } | ||
200 | |||
98 | color: Kirigami.Theme.viewBackgroundColor | 201 | color: Kirigami.Theme.viewBackgroundColor |
99 | 202 | ||
100 | //BEGIN header | 203 | //BEGIN header |
diff --git a/framework/domain/mailcontroller.cpp b/framework/domain/mailcontroller.cpp index 962b785f..b912567a 100644 --- a/framework/domain/mailcontroller.cpp +++ b/framework/domain/mailcontroller.cpp | |||
@@ -61,6 +61,8 @@ void MailController::updateActions() | |||
61 | if (mail) { | 61 | if (mail) { |
62 | action_moveToTrash->setEnabled(!mail->getTrash()); | 62 | action_moveToTrash->setEnabled(!mail->getTrash()); |
63 | action_restoreFromTrash->setEnabled(mail->getTrash()); | 63 | action_restoreFromTrash->setEnabled(mail->getTrash()); |
64 | action_markAsRead->setEnabled(mail->getUnread()); | ||
65 | action_markAsUnread->setEnabled(!mail->getUnread()); | ||
64 | } | 66 | } |
65 | } | 67 | } |
66 | 68 | ||