Merge lp:~kai-mast/friends-app/new-postview into lp:friends-app

Proposed by Kai Mast
Status: Merged
Approved by: Robert Bruce Park
Approved revision: 139
Merged at revision: 128
Proposed branch: lp:~kai-mast/friends-app/new-postview
Merge into: lp:friends-app
Diff against target: 1836 lines (+827/-610) (has conflicts)
22 files modified
friends-app.pro (+2/-0)
qml/AvatarImage.qml (+29/-0)
qml/ConversationDetails.qml (+39/-101)
qml/ConversationPage.qml (+111/-0)
qml/EntryField.qml (+119/-0)
qml/FavoriteIcon.qml (+50/-0)
qml/Feed.qml (+33/-91)
qml/FeedTab.qml (+23/-0)
qml/FeedTabs.qml (+25/-0)
qml/LinkDescription.qml (+20/-0)
qml/LinkItem.qml (+24/-0)
qml/LocationItem.qml (+25/-0)
qml/Post.qml (+14/-0)
qml/RefreshBar.qml (+3/-0)
qml/RepeatIcon.qml (+43/-0)
qml/ReplyArea.qml (+77/-0)
qml/SenderAndTimeItem.qml (+36/-0)
qml/StatusUpdateContent.qml (+44/-0)
qml/StatusUpdateTile.qml (+52/-298)
qml/ThreadView.qml (+25/-72)
qml/friends-app.qml (+32/-46)
qml/qml.pro (+1/-2)
Text conflict in qml/Post.qml
To merge this branch: bzr merge lp:~kai-mast/friends-app/new-postview
Reviewer Review Type Date Requested Status
Robert Bruce Park Approve
Ken VanDine Needs Fixing
Review via email: mp+197537@code.launchpad.net

Description of the change

This branch moves the post/conversation view to a new page. The reason for this is that the current details view get very cluttered if there are a lot of comments. Also, in the future this can be used to view images in high resolution (which I would like to work on after this branch has been merged).

I also adds the "reply all" button as requested. The code has been refactored, so this seems like a big merge but it it actually isn't that big.

Finally, I kept the amount of clicks needed to comment or view a post the same. So while this introduces a new view, the ease of use should stay the same.

To post a comment you must log in.
122. By Kai Mast

Fixed jumping to Top

123. By Kai Mast

Fixed jumping to Top

Revision history for this message
Ken VanDine (ken-vandine) wrote :

I've been looking forward to seeing this branch since I saw your post on G+, great work!

Looks pretty good, I did notice one typo. In Feed.qml you have an alias "servie". It doesn't appear to be used, if it isn't just remove it. If it is used, fix the typo. Also there are some places where you have commented out code, just remove those lines. Code comments are great, but I'd rather remove the commented out code.

review: Needs Fixing
Revision history for this message
Robert Bruce Park (robru) wrote :

When I look at the new detail page, the contents are visible through the Tabs header.

review: Needs Fixing
Revision history for this message
Robert Bruce Park (robru) wrote :

Looks like you need to add 'flickable: content' to the Page object in ConversationPage.qml.

Revision history for this message
Kai Mast (kai-mast) wrote :

Thanks for the tip. I thought that was a bug in the toolkit :D

Revision history for this message
Ken VanDine (ken-vandine) wrote :

A couple more notes:

* Your merge includes adding a untitled directory which doesn't look intentional.
* The text in the return to feed button should be translatable, add a i18n.tr().
* When the ConverstationPage gets loaded, it scrolls which cuts off the top of the content. Not sure why, but please look into that.

review: Needs Fixing
Revision history for this message
Kai Mast (kai-mast) wrote :

Okay I will do all that later. I also have the problem that on the post view the protocol icons are not shown (which makes it really hard to figure out which social network you are posting to). But I also have this problem on trunk... Not sure where this comes from.

124. By Kai Mast

many fixes to the reply area

125. By Kai Mast

fix url clicking in conversation view

126. By Kai Mast

removed unneeded folder

127. By Kai Mast

Many small fixes

128. By Kai Mast

Cleanups of the Flickable

Revision history for this message
Kai Mast (kai-mast) wrote :

Okay. I think I fixed everything except for the scrolling problem. Is there some SDK guru who can look at this? It really goes beyond my knowledge of the toolkit. Even setting content.contentY manually doesn't seem to work. I tried different anchors of the flickable towards the page (the documentation suggests fill), but that didn't change anything. I also tried increasing the height of the flickable content but that also didn't change anything.

The service property was used for some time to feed can only display specific services. I kept it, because there is a request for custom feeds and I may implement them some day (most of the functionality is already in place, one only needs to add a GUI to create and remove them).

Revision history for this message
Ken VanDine (ken-vandine) wrote :

In trying to fix the scrolling issue, I went a little overboard... see my proposal to merge into your's https://code.launchpad.net/~ken-vandine/friends-app/new-postview/+merge/198810

129. By Kai Mast

Merged changes by Ken

Revision history for this message
Kai Mast (kai-mast) wrote :

I just reviewed the branch again and everything looks fine now.

However, Ken changes aligned the reply area in the postview to the width of the text and not the width of the whole page. Was this on prupose? In my opinion, the reply area is a bit too small now.

Revision history for this message
Ken VanDine (ken-vandine) wrote :

Sorry, that was not intentional

130. By Kai Mast

First attempt to fix layout

131. By Kai Mast

Nicer layout of the reply area

Revision history for this message
Kai Mast (kai-mast) wrote :

It looks fine now in my opinion. I also made the reply area a little bigger as there is now space (maybe we should make its size dynamic depending on its content in the future).

Please review again and merge if you are happy with it.

132. By Kai Mast

Made header hideable again

Revision history for this message
Kai Mast (kai-mast) wrote :

Just discovered that the header did not hide anymore when flicking the content. This bug is already occuring in trunk so I guess it was introduced by my Tabs branch.
To fix this, I made the Feed item a Page and set flickable: listView. Now, the header hides again.

But the content below the header is still clipped, which seems to be this bug: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1250067

@Ken: would be nice if you could review it again :)

133. By Kai Mast

Restore order of update banner

134. By Kai Mast

Fix a warning

135. By Kai Mast

* Only show refresh bar when pulling downwards
* Restore toolbar

136. By Kai Mast

Remove unseen count; never worked for me

Revision history for this message
Robert Bruce Park (robru) wrote :

What's the status of this one, Kai? I see some new commits. You ready for a review?

137. By Kai Mast

Fixed clipping error

Revision history for this message
Kai Mast (kai-mast) wrote :

I just fixed the clipping problem. The header now hides again when scrolling downwards.

So this is ready to be merged.

Revision history for this message
Robert Bruce Park (robru) wrote :

Ok, took a look at this finally, sorry for the delay ;-)

Found some problems though. On the actual postview, there's a margin problem that I find quite ugly -- screenshot attached. Basically the replies should have a larger left margin than the parent, so that they look "set in" from the parent. What I'm seeing instead is zero margin, which is really ugly.

There's also a scrolling problem -- for messages where there are too many replies to fit on the screen, the whole thing just snaps to the top of the message. I can drag the window up to reveal more replies, but if I let go of the screen it just snaps back, so it's impossible to see all the replies.

review: Needs Fixing
Revision history for this message
Robert Bruce Park (robru) wrote :

Sorry, here is the screenshot: http://imgur.com/RWLkqsp

Also the timestamps should be aligned, but as you can see the children have a different alignment than the parent.

Revision history for this message
Kai Mast (kai-mast) wrote :

Okay I think I screwed this up with my last commit. Thanks for spotting it. Will take a look at it tomorrow.

Revision history for this message
Kai Mast (kai-mast) wrote :

@Rob: Did you have the problem that the qml files aren't copied into the build folder? Not sure if I broke something locally or on the branch.

138. By Kai Mast

Fixed scrolling conversation view

Revision history for this message
Kai Mast (kai-mast) wrote :

I think I resolved everything. Please check again :)

Revision history for this message
Robert Bruce Park (robru) wrote :

Sorry for the delay in reviewing, been a bit busy with other projects!

It looks really good now! The scrolling and margin errors I previously mentioned are fixed. There is however one new issue that I didn't notice before: The top Tab header is overlapping the page content poorly. I remember seeing this issue before a long time ago, but this time it's affecting the main timeline view:

http://imgur.com/u6IEdxu

I confirmed that this is happening only in your branch, trunk does not exhibit this behavior. In trunk the header is always visible and always opaque, but in your branch the header scrolls away with the page content fine, but then when you scroll it back into view, the feed is visible behind it.

review: Needs Fixing
Revision history for this message
Kai Mast (kai-mast) wrote :

Oh sorry I forgot to mention this. I am not sure what I am doing wrong there. The issue is described in a bug ( https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1201094 ) but I did everthing described there to fix it: I set the flickable correctly and the ListView still has clip: true.

I have the feeling this is some UI toolkit bug. Maybe it is currently not possible to have a flickable that is not directly the child of the Page.

Revision history for this message
Robert Bruce Park (robru) wrote :

Unfortunately my experience with QML is limited, and Ken is wayyy busier than I am so he can't look at this probably any time soon.

What confuses me is that you have at least one working flickable and one that doesn't. Surely you can compare them and see what's different about them, and make the broken one look more like the working one? Can you experiment with it a little bit further? Can you make the flickable be a direct child of the page somehow? (ie, is it possible to just have one flickable child and then change the content it displays, rather than trying to re-parent the flickable object to the page). Does that make sense?

These changes are looking really good, I'm excited to merge them, but I don't want to regress on this flickable bug since we already fixed it in friends-app back in July according to that bug you linked.

Revision history for this message
Kai Mast (kai-mast) wrote :

well the difference is that one uses Tabs and one doesn't. I simplified the code here: http://pastebin.com/ithdANaQ
What I don't understand is that the flickable is handled correctly (the header hides) but the content is not clipped even though I set "clip: true".
I'll ask some of the QML/SDK "gurus". Maybe they can help.

For now, we could also set "flickable: null", so the behaviour would be the same as on trunk.

Keep in mind that this is just the first change. With the images branch (that is already mostly finished except for some convergence stuff) this will even look nicer ;)

Revision history for this message
Ken VanDine (ken-vandine) wrote :

I just noticed the Tab usage doesn't include a page. The Tab expects the Page to be set to "page", not just declared there. So I think what's happening here is the flickable isn't properly trickling up the stack.

Something like this:

Tabs {
  Tab {
    page: Feed {
    }
}

139. By Kai Mast

Fixed clipping

Revision history for this message
Kai Mast (kai-mast) wrote :

You were right Ken!

So the Feed is a page now and we push the Tabs directly on the PageStack (was wrapped in a Page before). This resolved the clipping issue.

One small problem is left: When you jump to the top the header reappears and you are not completely at the top. There is no way to fix this right now. We need a way to reveal the header first and then jump to the top which is not possible right now.

But I think it looks really good now and is mergeable.

Revision history for this message
Robert Bruce Park (robru) wrote :

Ok, this is looking really good to me now. I can't find anything wrong with it. Thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'friends-app.pro'
2--- friends-app.pro 2013-04-08 14:56:46 +0000
3+++ friends-app.pro 2014-01-23 12:09:15 +0000
4@@ -24,3 +24,5 @@
5 INSTALLS += accounts
6
7 SUBDIRS += src qml po tests
8+
9+
10
11=== added file 'qml/AvatarImage.qml'
12--- qml/AvatarImage.qml 1970-01-01 00:00:00 +0000
13+++ qml/AvatarImage.qml 2014-01-23 12:09:15 +0000
14@@ -0,0 +1,29 @@
15+import QtQuick 2.0
16+import Ubuntu.Components 0.1
17+
18+UbuntuShape {
19+ id: avatarImage
20+ height: units.dp(48)
21+ width: units.dp(48)
22+
23+ // We can only specify top margin, as this is displayed in a Row element
24+ anchors {
25+ topMargin: units.gu(1)
26+ top: parent.top
27+ }
28+
29+ image: Image {
30+ source: Qt.resolvedUrl(avatar)
31+ asynchronous: true
32+ smooth: true
33+ fillMode: Image.PreserveAspectCrop
34+ sourceSize.width: units.dp(48)
35+ }
36+
37+ MouseArea {
38+ anchors.fill: avatarImage
39+ onClicked: {
40+ Qt.openUrlExternally(url);
41+ }
42+ }
43+}
44
45=== renamed file 'qml/StatusUpdateTileDetails.qml' => 'qml/ConversationDetails.qml'
46--- qml/StatusUpdateTileDetails.qml 2013-08-20 15:17:54 +0000
47+++ qml/ConversationDetails.qml 2014-01-23 12:09:15 +0000
48@@ -22,7 +22,11 @@
49
50 Item {
51 id: details
52- height: visible ? childrenRect.height + units.gu(1) : 0
53+ height: childrenRect.height + units.gu(1)
54+
55+ function isMicroblogging() {
56+ return (service === "twitter") || (service === "identica")
57+ }
58
59 FriendsDispatcher {
60 id: friends
61@@ -41,12 +45,18 @@
62
63 Item {
64 id: pictureWrapper
65- anchors.right: parent.right
66+
67+ anchors {
68+ right: parent.right
69+ top: parent.top
70+ }
71+
72 width: parent.width - units.gu(8)
73 height: childrenRect.height
74
75 Image {
76 id: pictureImage
77+ anchors.fill: parent
78 visible: linkPicture.length > 0 && status == Image.Ready
79 source: Qt.resolvedUrl(linkPicture)
80 asynchronous: true
81@@ -73,9 +83,9 @@
82 anchors.top: pictureWrapper.bottom
83 source: {
84 return "http://open.mapquestapi.com/staticmap/v4/getmap?size=" +
85- Math.round(Math.min(parent.width * 0.8, units.gu(20))) + "," +
86- Math.round(Math.min(parent.width * 0.8, units.gu(20))) +
87- "&zoom=12&center=" + latitude + "," + longitude
88+ Math.round(Math.min(parent.width * 0.8, units.gu(20))) + "," +
89+ Math.round(Math.min(parent.width * 0.8, units.gu(20))) +
90+ "&zoom=12&center=" + latitude + "," + longitude
91
92 }
93 visible: location.length > 0
94@@ -84,7 +94,6 @@
95 ThreadView {
96 id: threadView
97 width: parent.width
98- height: childrenRect.height
99
100 anchors {
101 top: mapimage.bottom
102@@ -94,117 +103,46 @@
103 }
104
105 Item {
106- id: entry
107- property var lastCursorPosition
108- height: childrenRect.height
109+ id: bottom
110 anchors {
111+ left: parent.left
112+ right: parent.right
113 top: threadView.bottom
114- left: parent.left
115- right: parent.right
116- topMargin: units.gu(2)
117 }
118
119- TextArea {
120- id: entryArea
121+ height: childrenRect.height
122+
123+ ReplyArea {
124+ id: replyArea
125+
126 anchors {
127+ top: parent.top
128 left: parent.left
129- leftMargin: units.gu(2)
130- right: sendButton.left
131- rightMargin: units.gu(1)
132- bottomMargin: units.gu(1.5)
133- }
134- // send message if return was pressed
135- Keys.onReturnPressed: sendButton.clicked(null)
136- Keys.onEscapePressed: text = ""
137- height: units.gu(4)
138- placeholderText: i18n.tr("Reply")
139- autoSize: true
140- maximumLineCount: 0
141- color: text.length < 140 ? "gray" : "red"
142- textFormat: TextEdit.PlainText
143- contentWidth: width - units.gu(5)
144- onActiveFocusChanged: {
145- if (activeFocus) {
146- if (service == "twitter" || service == "identica") {
147- if (entryArea.text.search("@"+senderNick) == -1) {
148- entryArea.text = "@"+senderNick+" ";
149- cursorPosition = text.length;
150- }
151- }
152- }
153- }
154-
155- onTextChanged: {
156- var enteredText = text.substring(entry.lastCursorPosition, cursorPosition);
157- if (enteredText.substring(0,4) == "http") {
158- var shortUrl = friends.urlShorten(enteredText);
159- if (shortUrl.length > 4) {
160- text = text.replace (enteredText, shortUrl);
161- cursorPosition = text.length;
162- }
163- }
164- entry.lastCursorPosition = cursorPosition;
165- }
166-
167- Item {
168- id: counter
169- anchors {
170- right: entryArea.right
171- top: entryArea.top
172- rightMargin: units.gu(1)
173- }
174- height: units.gu(4)
175- width: childrenRect.width
176- visible: entryArea.text.length > 0 ? true : false
177- Text {
178- text: 140 - entryArea.text.length
179- font.bold: true
180- opacity: 0.3
181- }
182- }
183- Button {
184- id: clearButton
185- anchors {
186- right: entryArea.right
187- bottom: entryArea.bottom
188- rightMargin: units.gu(1)
189- }
190- width: units.gu(2)
191- height: units.gu(2)
192- visible: entryArea.text.length > 0 ? true : false
193- iconSource: "images/clear-search.png"
194- color: "transparent"
195- opacity: 0.3
196- onClicked: {
197- entryArea.text = "";
198- }
199+ right: parent.right
200+ topMargin: units.gu(2)
201 }
202 }
203
204+ // Back button (much faster than using the toolbar)
205+ // At the bottom so it doesn't steal any space (content is flickable)
206 Button {
207- id: sendButton
208+ id: returnButton
209+
210 anchors {
211+ top: replyArea.bottom
212+ left: parent.left
213 right: parent.right
214- rightMargin: units.gu(1)
215- bottom: entryArea.bottom
216+ margins: units.gu(5)
217 }
218- width: units.gu(9)
219- height: units.gu(4)
220- text: i18n.tr("Send")
221- color: main.headerColor
222+
223+ text: i18n.tr("Return to feed")
224+
225+ height: units.gu(6)
226+
227 onClicked: {
228- console.log ("Reply to " + messageId + " from " + accountId + ": " + entryArea.text);
229- sendSpinner.visible = true
230- friends.sendReplyAsync(accountId, messageId, entryArea.text);
231+ conversationPage.close()
232 }
233 }
234-
235- ActivityIndicator {
236- id: sendSpinner
237- anchors.centerIn: entryArea
238- visible: false
239- running: visible
240- }
241 }
242
243 Component {
244
245=== added file 'qml/ConversationPage.qml'
246--- qml/ConversationPage.qml 1970-01-01 00:00:00 +0000
247+++ qml/ConversationPage.qml 2014-01-23 12:09:15 +0000
248@@ -0,0 +1,111 @@
249+import QtQuick 2.0
250+import Ubuntu.Components 0.1
251+
252+Page {
253+ title: i18n.tr("Conversation")
254+ id: conversationPage
255+
256+ flickable: content
257+
258+ function setContent(tile) {
259+ this.tile = tile
260+
261+ //Assign all values of the tile to the conversation page
262+ //This way we can have one page for all tiles
263+ liked = tile.liked
264+ likeCount = tile.likeCount
265+ fromMe = tile.fromMe
266+ service = tile.service
267+ linkUrl = tile.linkUrl
268+ linkName = tile.linkName
269+ linkDescription = tile.linkDescription
270+ avatar = tile.avatar
271+ message = tile.message
272+ timeString = tile.timeString
273+ location = tile.location
274+ sender = tile.sender
275+ linkPicture = tile.linkPicture
276+ latitude = tile.latitude
277+ longitude = tile.longitude
278+ messageId = tile.messageId
279+ stream = tile.stream
280+ senderNick = tile.senderNick
281+ url = tile.url
282+ }
283+
284+ //Forward properties from StatusUpdateTile
285+ property bool liked
286+ property int likeCount
287+ property bool fromMe
288+ property string service
289+ property string linkUrl
290+ property string linkName
291+ property string linkDescription
292+ property variant avatar
293+ property string message
294+ property variant tile
295+ property string timeString
296+ property string location
297+ property string sender
298+ property string linkPicture
299+ property int latitude
300+ property int longitude
301+ property string messageId
302+ property string stream
303+ property string senderNick
304+ property string url
305+
306+ function close() {
307+ main.closeConversation();
308+ }
309+
310+ Flickable {
311+ id: content
312+
313+ anchors {
314+ fill: parent
315+ margins: units.gu(2)
316+ }
317+
318+ contentHeight: column.height
319+
320+ flickableDirection: Flickable.VerticalFlick
321+ boundsBehavior: Flickable.DragOverBounds
322+
323+ // Looks much nicer on broad displays
324+ width: Math.min(parent.width, units.gu(80))
325+
326+ Column {
327+ id: column
328+
329+ width: parent.width
330+ height: childrenRect.height
331+
332+ Row {
333+ width: parent.width
334+ spacing: units.gu(1)
335+
336+ AvatarImage {
337+ id: avatarImage
338+ }
339+
340+ StatusUpdateContent {
341+ id: statusUpdateContent
342+
343+ width: parent.width - avatarImage.width
344+ showDetails: true
345+ }
346+ }
347+
348+ ConversationDetails {
349+ width: parent.width
350+
351+ id: details
352+ }
353+ }
354+
355+ }
356+ Keys.onEscapePressed: {
357+ conversationPage.close()
358+ }
359+}
360
361=== added file 'qml/EntryField.qml'
362--- qml/EntryField.qml 1970-01-01 00:00:00 +0000
363+++ qml/EntryField.qml 2014-01-23 12:09:15 +0000
364@@ -0,0 +1,119 @@
365+import QtQuick 2.0
366+import Ubuntu.Components 0.1
367+
368+Item {
369+ id: entryField
370+
371+ onVisibleChanged: {
372+ if(visible)
373+ entryArea.forceActiveFocus()
374+ }
375+
376+ property var lastCursorPosition
377+ anchors.fill: parent
378+
379+ function setText(text) {
380+ entryArea.text = text + " "
381+ entryArea.cursorPosition = text.length + 1
382+ }
383+
384+ TextArea {
385+ id: entryArea
386+ anchors {
387+ top: parent.top
388+ bottom: parent.bottom
389+ left: parent.left
390+ leftMargin: units.gu(1)
391+ right: sendButton.left
392+ rightMargin: units.gu(1)
393+ }
394+
395+ // send message if return was pressed
396+ Keys.onReturnPressed: sendButton.clicked(null)
397+ Keys.onEscapePressed: text = ""
398+ height: units.gu(4)
399+ placeholderText: i18n.tr("Reply")
400+ autoSize: true
401+ maximumLineCount: 0
402+ color: text.length < 140 ? "gray" : "red"
403+ textFormat: TextEdit.PlainText
404+ contentWidth: width - units.gu(5)
405+
406+ onTextChanged: {
407+ var enteredText = text.substring(entryField.lastCursorPosition, cursorPosition);
408+ if (enteredText.substring(0,4) == "http") {
409+ var shortUrl = friends.urlShorten(enteredText);
410+ if (shortUrl.length > 4) {
411+ text = text.replace (enteredText, shortUrl);
412+ cursorPosition = text.length;
413+ }
414+ }
415+ entryField.lastCursorPosition = cursorPosition;
416+ }
417+
418+ Item {
419+ id: counter
420+ anchors {
421+ right: entryArea.right
422+ top: entryArea.top
423+ rightMargin: units.gu(1)
424+ }
425+ height: units.gu(4)
426+ width: childrenRect.width
427+
428+ visible: (isMicroblogging() && entryArea.text.length > 0) ? true : false
429+ Text {
430+ text: 140 - entryArea.text.length
431+ font.bold: true
432+ opacity: 0.3
433+ }
434+ }
435+ }
436+
437+ Button {
438+ id: sendButton
439+
440+ anchors {
441+ right: parent.right
442+ rightMargin: units.gu(1)
443+ top: parent.top
444+ }
445+
446+ width: units.gu(9)
447+ height: units.gu(4)
448+ text: i18n.tr("Send")
449+ color: main.headerColor
450+ onClicked: {
451+ console.log ("Reply to " + messageId + " from " + accountId + ": " + entryArea.text);
452+ sendSpinner.visible = true
453+ friends.sendReplyAsync(accountId, messageId, entryArea.text);
454+ }
455+ }
456+ Button {
457+ id: clearButton
458+
459+ anchors {
460+ right: parent.right
461+ top: sendButton.bottom
462+ rightMargin: units.gu(1)
463+ topMargin: units.gu(1)
464+ }
465+
466+ height: sendButton.height
467+ width: sendButton.width
468+ iconSource: "images/clear-search.png"
469+ color: main.headerColor
470+
471+ onClicked: {
472+ entryArea.text = ""
473+ entryField.visible = false
474+ }
475+ }
476+
477+ ActivityIndicator {
478+ id: sendSpinner
479+ anchors.centerIn: entryArea
480+ visible: false
481+ running: visible
482+ }
483+}
484
485=== added file 'qml/FavoriteIcon.qml'
486--- qml/FavoriteIcon.qml 1970-01-01 00:00:00 +0000
487+++ qml/FavoriteIcon.qml 2014-01-23 12:09:15 +0000
488@@ -0,0 +1,50 @@
489+import QtQuick 2.0
490+import Ubuntu.Components 0.1
491+
492+Row {
493+ id: favorite
494+
495+ height: favoriteIcon.height + units.gu(1)
496+ anchors {
497+ left: parent.left
498+ right: parent.right
499+ bottomMargin: units.gu(1)
500+ }
501+ spacing: units.dp(3)
502+
503+ Image {
504+ id: favoriteIcon
505+ width: units.gu(3)
506+ height: units.gu(3)
507+ opacity: liked ? 1.0 : 0.1
508+
509+ source: "images/favorite.png"
510+ asynchronous: true
511+ MouseArea {
512+ anchors.fill: favoriteIcon
513+ onClicked: {
514+ favoriteSpinner.visible = true;
515+ if (liked) {
516+ friends.unlikeAsync(accountId, messageId);
517+ }
518+ else {
519+ friends.likeAsync(accountId, messageId);
520+ }
521+ }
522+ }
523+ ActivityIndicator {
524+ id: favoriteSpinner
525+ anchors.centerIn: parent
526+ width: parent.width
527+ visible: false
528+ running: visible
529+ }
530+ }
531+
532+ Label {
533+ id: likesLabel
534+ text: (likeCount > 0) ? likeCount + " " + likesString : ""
535+ fontSize: "small"
536+ color: Theme.palette.normal.baseText
537+ }
538+}
539
540=== modified file 'qml/Feed.qml'
541--- qml/Feed.qml 2013-11-03 10:35:46 +0000
542+++ qml/Feed.qml 2014-01-23 12:09:15 +0000
543@@ -21,9 +21,15 @@
544 import Ubuntu.Components.ListItems 0.1 as ListItem
545 import Friends 0.2
546
547-Tab {
548+Page {
549+ anchors.fill: parent
550+ clip: true
551+
552+ property alias flickable: listView
553+
554 property alias stream: streamModel.stream
555- property int unseen: 0
556+ property alias service: streamModel.service
557+
558 property string search
559
560 /* Jump to the bottom of the view and set the currentIndex */
561@@ -38,12 +44,8 @@
562 listView.currentIndex = 0;
563 }
564
565- onUnseenChanged: {
566- updatesText.text = unseen == 1 ? (unseen + i18n.tr(" new update")) : (unseen + i18n.tr(" new updates"));
567- }
568-
569 Component.onCompleted: {
570- listView.focus = true;
571+ listView.focus = true
572 }
573
574 Timer {
575@@ -57,18 +59,12 @@
576 id: statusDelegate
577
578 ListItem.Empty {
579- anchors {
580- left: parent.left
581- right: parent.right
582- }
583 height: content.height
584
585 StatusUpdateTile {
586 id: content
587 height: childrenRect.height
588- ListView.onAdd: SequentialAnimation {
589- ScriptAction { script: {unseen++; console.log(column_0[0][0] + " " + column_0[0][1] + " " + column_0[0][2]) }}
590- }
591+
592 Connections {
593 target: updateTimestampsTimer
594 onTriggered: {
595@@ -84,23 +80,12 @@
596 objectName: "streamModel"
597 }
598
599- onStreamChanged: {
600- console.log("stream changed to " + stream);
601- streamModel.stream = stream;
602- }
603-
604- onSearchChanged: {
605- console.log ("onSearchChanged");
606- }
607-
608 RefreshBar {
609 id: refreshBar
610
611- anchors.top: parent.top
612- anchors.topMargin: units.gu(1)
613+ opacity: visible ? 1.0 : 0.0
614+ visible: listView.dragging && listView.onTop
615
616- opacity: 0
617- visible: opacity > 0 ? true : false
618 Behavior on opacity {
619 NumberAnimation { duration: 200; }
620 }
621@@ -109,13 +94,13 @@
622 ListView {
623 id: listView
624 objectName: "listView"
625- height: parent.height - toolbar.height - units.gu(2)
626- width: parent.width
627+
628 anchors {
629- top: updatesBanner.bottom
630- topMargin: units.gu(1)
631 fill: parent
632 }
633+
634+ property bool onTop : listView.contentY <= -main.header.height
635+
636 opacity: 1
637 spacing: units.gu(1)
638 model: streamModel
639@@ -128,6 +113,7 @@
640
641 preferredHighlightBegin: 0
642 preferredHighlightEnd: preferredHighlightBegin
643+
644 /* We need highlightRangeMode for keyboard navigation,
645 * but it forces the page header to stay hidden
646 * https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1201936
647@@ -141,81 +127,37 @@
648 }
649 }
650
651- /* Ensure we collapse details when scrolling */
652- onFlickStarted: {
653- if (listView.currentItem.state != "List")
654- listView.currentItem.state = "List";
655- }
656-
657 /* Expand details on enter */
658 Keys.onReturnPressed: {
659- if (listView.currentItem.state != "Details")
660- listView.currentItem.state = "Details";
661- }
662-
663- /* Collapse details on escape */
664- Keys.onEscapePressed: {
665- if (listView.currentItem.state != "List")
666- listView.currentItem.state = "List";
667+ listView.currentItem.showConversation()
668 }
669
670 /* Handle home and end nav */
671 Keys.onPressed: {
672- if (event.key == Qt.Key_Home) {
673+ if (event.key === Qt.Key_Home) {
674 jumpToTop();
675 }
676- else if (event.key == Qt.Key_End) {
677+ else if (event.key === Qt.Key_End) {
678 jumpToBottom();
679 }
680 }
681-
682- onDragStarted: {
683- if (listView.atYBeginning)
684- refreshBar.opacity = 1.0;
685- }
686- onDragEnded: {
687- refreshBar.opacity = 0
688- if (refreshBar.refreshed) {
689- console.log ("Refreshed");
690- friends.refresh ();
691- }
692- }
693- }
694-
695- Item {
696- id: updatesBanner
697- anchors {
698- top: parent.top
699- left: parent.left
700- right: parent.right
701- }
702- visible: unseen > 0
703- height: visible ? units.gu(3) : 0
704- Text {
705- id: updatesText
706- anchors {
707- centerIn: parent
708- bottom: parent.bottom
709- }
710- text: ""
711- font.family: "Ubuntu"
712- font.bold: true
713- font.pointSize: 12
714- color: Theme.palette.normal.baseText
715- }
716- MouseArea {
717- anchors.fill: parent
718- onClicked: {
719- unseen = 0;
720- updatesText.text = "";
721- updatesBanner.visible = false;
722- jumpToTop();
723- }
724- }
725 }
726
727 Scrollbar {
728 flickableItem: listView
729 align: Qt.AlignTrailing
730 }
731+
732+
733+ tools: ToolbarItems {
734+ ToolbarButton {
735+ action: topAction
736+ }
737+ ToolbarButton {
738+ action: refreshAction
739+ }
740+ ToolbarButton {
741+ action: postAction
742+ }
743+ }
744 }
745
746=== added file 'qml/FeedTab.qml'
747--- qml/FeedTab.qml 1970-01-01 00:00:00 +0000
748+++ qml/FeedTab.qml 2014-01-23 12:09:15 +0000
749@@ -0,0 +1,23 @@
750+import QtQuick 2.0
751+import Ubuntu.Components 0.1
752+
753+Tab {
754+ clip: true
755+
756+ //property alias flickable: feed.flickable
757+
758+ property string stream
759+
760+ function jumpToTop() {
761+ feed.jumpToTop()
762+ }
763+
764+ page: feed
765+
766+ Feed {
767+ anchors.fill: parent
768+
769+ id: feed
770+ stream: parent.stream
771+ }
772+}
773
774=== added file 'qml/FeedTabs.qml'
775--- qml/FeedTabs.qml 1970-01-01 00:00:00 +0000
776+++ qml/FeedTabs.qml 2014-01-23 12:09:15 +0000
777@@ -0,0 +1,25 @@
778+import QtQuick 2.0
779+import Ubuntu.Components 0.1
780+
781+Tabs {
782+ id: feedTabs
783+ clip: true
784+
785+ function jumpToTop() {
786+ feedTabs.selectedTab.jumpToTop()
787+ }
788+
789+ FeedTab {
790+ id: timeline
791+
792+ title: i18n.tr("Timeline")
793+ stream: "" //all
794+ }
795+
796+ FeedTab {
797+ id: mentions
798+
799+ title: i18n.tr("Mentions")
800+ stream: "mentions"
801+ }
802+}
803
804=== added file 'qml/LinkDescription.qml'
805--- qml/LinkDescription.qml 1970-01-01 00:00:00 +0000
806+++ qml/LinkDescription.qml 2014-01-23 12:09:15 +0000
807@@ -0,0 +1,20 @@
808+import QtQuick 2.0
809+import Ubuntu.Components 0.1
810+
811+// Show the description link of a status update (if any)
812+// Should only be used by StatusUpdateContent
813+Label {
814+ id: linkDesc
815+
816+ anchors {
817+ right: parent.right
818+ left: parent.left
819+ }
820+
821+ text: linkDescription
822+ elide: Text.ElideRight
823+ visible: linkDescription.length > 0
824+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
825+ textFormat: Text.StyledText
826+ onLinkActivated: Qt.openUrlExternally(link)
827+}
828
829=== added file 'qml/LinkItem.qml'
830--- qml/LinkItem.qml 1970-01-01 00:00:00 +0000
831+++ qml/LinkItem.qml 2014-01-23 12:09:15 +0000
832@@ -0,0 +1,24 @@
833+import QtQuick 2.0
834+import Ubuntu.Components 0.1
835+
836+// Show link of a status update (if any)
837+// Should only be used by StatusUpdateContent
838+UbuntuShape {
839+ height: linkNameShape.height + units.gu(1)
840+ width: linkNameShape.width + units.gu(2)
841+ visible: linkName.length > 0
842+ Label {
843+ id: linkNameShape
844+ anchors.centerIn: parent
845+ text: linkName
846+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
847+ }
848+ MouseArea {
849+ anchors.fill: parent
850+ onClicked: {
851+ if (linkUrl.length > 0)
852+ Qt.openUrlExternally(linkUrl);
853+
854+ }
855+ }
856+}
857
858=== added file 'qml/LocationItem.qml'
859--- qml/LocationItem.qml 1970-01-01 00:00:00 +0000
860+++ qml/LocationItem.qml 2014-01-23 12:09:15 +0000
861@@ -0,0 +1,25 @@
862+import QtQuick 2.0
863+import Ubuntu.Components 0.1
864+
865+// Show location information of a status update (if any)
866+// Should only be used by StatusUpdateContent
867+UbuntuShape {
868+ height: locationName.height + units.gu(1)
869+ width: locationName.width + units.gu(2)
870+ visible: location.length > 0
871+ Label {
872+ id: locationName
873+ anchors.centerIn: parent
874+ text: location
875+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
876+ }
877+ MouseArea {
878+ anchors.fill: parent
879+ onClicked: {
880+ if (url.length > 0)
881+ {
882+ Qt.openUrlExternally(url);
883+ }
884+ }
885+ }
886+}
887
888=== modified file 'qml/Post.qml'
889--- qml/Post.qml 2013-12-12 18:08:32 +0000
890+++ qml/Post.qml 2014-01-23 12:09:15 +0000
891@@ -236,7 +236,21 @@
892 ListItem.Standard {
893 text: displayName
894 opacity: sw.checked ? 1.0 : 0.3
895+<<<<<<< TREE
896 iconName: accountIcon
897+=======
898+
899+ Component.onCompleted: {
900+ //this fixes height if no icon can be found
901+ if(icon) {
902+ height = icon.height
903+ }
904+ }
905+
906+ //Show no icon if none is available
907+ iconSource: iconName.length > 0 ? "image://gicon/"+iconName : ""
908+
909+>>>>>>> MERGE-SOURCE
910 control: CheckBox {
911 id: sw
912 checked: sendEnabled
913
914=== modified file 'qml/RefreshBar.qml'
915--- qml/RefreshBar.qml 2013-08-05 17:39:52 +0000
916+++ qml/RefreshBar.qml 2014-01-23 12:09:15 +0000
917@@ -21,6 +21,9 @@
918 Item {
919 height: units.gu(4)
920 anchors {
921+ topMargin: main.header.height + units.gu(1) // show it below the header
922+
923+ top: parent.top
924 left: parent.left
925 right: parent.right
926 }
927
928=== added file 'qml/RepeatIcon.qml'
929--- qml/RepeatIcon.qml 1970-01-01 00:00:00 +0000
930+++ qml/RepeatIcon.qml 2014-01-23 12:09:15 +0000
931@@ -0,0 +1,43 @@
932+import QtQuick 2.0
933+import Ubuntu.Components 0.1
934+
935+Item {
936+ id: repeatIcon
937+
938+ anchors {
939+ right: parent.right
940+ bottom: parent.bottom
941+ rightMargin: units.gu(2)
942+ bottomMargin: units.gu(1)
943+ }
944+
945+ height: fromMe ? 0 : childrenRect.height
946+
947+ // FIXME: Use features API instead
948+ visible: showDetails &&
949+ (service == "twitter" || service == "identica") && !fromMe && stream !== "private"
950+
951+ Image {
952+ id: repeatIconImage
953+ width: units.gu(3)
954+ height: units.gu(3)
955+ source: "images/share.png"
956+ asynchronous: true
957+ visible: retweetSpinner.visble ? false : true
958+ MouseArea {
959+ anchors.fill: parent
960+ onClicked: {
961+ console.log ("Retweeting " + messageId + " from " + accountId);
962+ retweetSpinner.visible = true
963+ friends.retweetAsync(accountId, messageId);
964+ }
965+ }
966+ ActivityIndicator {
967+ id: retweetSpinner
968+ anchors.centerIn: parent
969+ //width: parent.width
970+ visible: false
971+ running: visible
972+ }
973+ }
974+}
975
976=== added file 'qml/ReplyArea.qml'
977--- qml/ReplyArea.qml 1970-01-01 00:00:00 +0000
978+++ qml/ReplyArea.qml 2014-01-23 12:09:15 +0000
979@@ -0,0 +1,77 @@
980+import QtQuick 2.0
981+import Ubuntu.Components 0.1
982+
983+// This element shows either the reply/reply all buttons
984+// Or a field to compose the reply
985+Item {
986+ id: replyArea
987+ height: units.gu(4)
988+
989+ Button {
990+ id: replyButton
991+ visible: !entryField.visible
992+ width: units.gu(10)
993+
994+ anchors {
995+ leftMargin: units.gu(5)
996+ left: parent.left
997+ top: parent.top
998+ bottom: parent.bottom
999+ }
1000+
1001+ text: isMicroblogging() ? i18n.tr("Reply"): i18n.tr("Comment")
1002+
1003+ property var lastCursorPosition
1004+ height: childrenRect.height
1005+
1006+ onClicked : {
1007+ entryField.visible = true
1008+
1009+ if(isMicroblogging())
1010+ entryField.setText("@"+senderNick)
1011+ }
1012+ }
1013+
1014+ Button {
1015+ id: replyAllButton
1016+
1017+ // Only show if we are using micrblogging.
1018+ visible: !entryField.visible && isMicroblogging()
1019+ width: replyButton.width
1020+
1021+ anchors {
1022+ left: replyButton.right
1023+ leftMargin: units.gu(1)
1024+ top: parent.top
1025+ bottom: parent.bottom
1026+ }
1027+
1028+ text: i18n.tr("Reply All")
1029+
1030+ property var lastCursorPosition
1031+ height: childrenRect.height
1032+
1033+ onClicked : {
1034+ entryField.visible = true
1035+
1036+ if(isMicroblogging()) {
1037+ var text = "@"+senderNick;
1038+
1039+ var nicks = message.match(/[@][\w]+/g);
1040+
1041+ if (nicks !== null) {
1042+ for(var i = 0; i < nicks.length; ++i) {
1043+ text += " " + nicks[i];
1044+ }
1045+ }
1046+
1047+ entryField.setText(text)
1048+ }
1049+ }
1050+ }
1051+
1052+ EntryField {
1053+ id: entryField
1054+ visible: false
1055+ }
1056+}
1057
1058=== added file 'qml/SenderAndTimeItem.qml'
1059--- qml/SenderAndTimeItem.qml 1970-01-01 00:00:00 +0000
1060+++ qml/SenderAndTimeItem.qml 2014-01-23 12:09:15 +0000
1061@@ -0,0 +1,36 @@
1062+import QtQuick 2.0
1063+import Ubuntu.Components 0.1
1064+
1065+// Shows sender and time of a status update
1066+// Should only be used by StatusUpdateContent
1067+Item {
1068+ anchors {
1069+ left: parent.left
1070+ right: parent.right
1071+ rightMargin: units.gu(1)
1072+ }
1073+ height: childrenRect.height
1074+
1075+ Label {
1076+ text: sender
1077+ fontSize: "medium"
1078+ font.bold: true
1079+
1080+ anchors {
1081+ left: parent.left
1082+ right: time.left
1083+ }
1084+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1085+ }
1086+
1087+ Label {
1088+ id: time
1089+ anchors {
1090+ right: parent.right
1091+ }
1092+
1093+ text: timeString
1094+ fontSize: "small"
1095+ color: Theme.palette.normal.baseText
1096+ }
1097+}
1098
1099=== added file 'qml/StatusUpdateContent.qml'
1100--- qml/StatusUpdateContent.qml 1970-01-01 00:00:00 +0000
1101+++ qml/StatusUpdateContent.qml 2014-01-23 12:09:15 +0000
1102@@ -0,0 +1,44 @@
1103+import QtQuick 2.0
1104+import Ubuntu.Components 0.1
1105+
1106+Column {
1107+ property bool showDetails: false
1108+ spacing: units.gu(1)
1109+ anchors.margins: units.gu(1)
1110+
1111+ SenderAndTimeItem {
1112+ }
1113+
1114+ Label {
1115+ id: messageText
1116+ anchors {
1117+ right: parent.right
1118+ left: parent.left
1119+ }
1120+ text: message
1121+
1122+ elide: Text.ElideRight
1123+ visible: message.length > 0 && message != linkDescription
1124+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1125+ textFormat: Text.StyledText
1126+ linkColor: Theme.palette.normal.baseText
1127+ onLinkActivated: Qt.openUrlExternally(link)
1128+ }
1129+
1130+ LocationItem {
1131+ }
1132+
1133+ LinkItem {
1134+ }
1135+
1136+ LinkDescription {
1137+ }
1138+
1139+ FavoriteIcon {
1140+ id: favorite
1141+ }
1142+
1143+ RepeatIcon {
1144+ id: repeatIcon
1145+ }
1146+}
1147
1148=== modified file 'qml/StatusUpdateTile.qml'
1149--- qml/StatusUpdateTile.qml 2013-08-28 19:04:36 +0000
1150+++ qml/StatusUpdateTile.qml 2014-01-23 12:09:15 +0000
1151@@ -25,9 +25,32 @@
1152 id: tile
1153 anchors {
1154 left: parent.left
1155- right: parent.right
1156- }
1157- property real detailsOpacity : 0
1158+ right: parent.right
1159+ }
1160+
1161+ //Forward properties
1162+ property bool liked : liked
1163+ property bool fromMe: fromMe
1164+ property string message: model.message
1165+ property string service: model.service
1166+ property string linkUrl: model.linkUrl
1167+ property string linkName: model.linkName
1168+ property string linkDescription: model.linkDescription
1169+ property string avatar: model.avatar
1170+ property string location: model.location
1171+ property string sender: model.sender
1172+ property string linkPicture: model.linkPicture
1173+ property int latitude: model.latitude
1174+ property int longitude: model.longitude
1175+ property string messageId: model.messageId
1176+ property string stream: model.stream
1177+ property string senderNick: model.senderNick
1178+ property string url: model.url
1179+
1180+ function showConversation() {
1181+ main.addConversation(tile)
1182+ }
1183+
1184 property string timeString: friendsUtils.createTimeString(timestamp)
1185 property int likeCount: likes > 0 ? likes : liked ? 1 : 0
1186 property string likesString: likeCount > 1 ? i18n.tr("people liked this") : i18n.tr("person liked this")
1187@@ -42,8 +65,10 @@
1188 anchors {
1189 right: parent.right
1190 left: parent.left
1191+ leftMargin: units.gu(1)
1192 }
1193- height: status_update_content.height + detailsWrapper.height
1194+
1195+ height: childrenRect.height + units.gu(1)
1196
1197 FriendsUtils {
1198 id: friendsUtils
1199@@ -61,46 +86,24 @@
1200 }
1201 onUnlikeComplete: {
1202 favoriteSpinner.visible = false;
1203- if (success) {
1204- console.log ("Like succeeded");
1205- } else {
1206- console.log ("UnLike failed: " + errorMessage);
1207- }
1208- }
1209+ if (success) {
1210+ console.log ("Like succeeded");
1211+ } else {
1212+ console.log ("UnLike failed: " + errorMessage);
1213+ }
1214+ }
1215 onRetweetComplete: {
1216 retweetSpinner.visible = false;
1217 if (success) {
1218- console.log ("Retweet completed successfully");
1219+ console.log ("Retweet completed successfully");
1220 } else {
1221- console.log ("Retweet failed: " + errorMessage);
1222+ console.log ("Retweet failed: " + errorMessage);
1223 }
1224- }
1225+ }
1226 }
1227
1228- UbuntuShape {
1229+ AvatarImage {
1230 id: avatarImage
1231- height: units.dp(48)
1232- width: units.dp(48)
1233- anchors {
1234- left: parent.left
1235- top: parent.top
1236- leftMargin: units.gu(1)
1237- topMargin: units.gu(1)
1238- }
1239- image: Image {
1240- source: Qt.resolvedUrl(avatar)
1241- asynchronous: true
1242- smooth: true
1243- fillMode: Image.PreserveAspectCrop
1244- sourceSize.width: units.dp(48)
1245- }
1246-
1247- MouseArea {
1248- anchors.fill: avatarImage
1249- onClicked: {
1250- Qt.openUrlExternally(url);
1251- }
1252- }
1253 }
1254
1255 Image {
1256@@ -113,7 +116,7 @@
1257 }
1258 source: "images/private.png"
1259 asynchronous: true
1260- visible: stream == "private"
1261+ visible: stream === "private"
1262 }
1263
1264 Image {
1265@@ -126,14 +129,14 @@
1266 }
1267 source: "images/replies.png"
1268 asynchronous: true
1269- visible: stream == "mentions"
1270+ visible: stream === "mentions"
1271 }
1272
1273 Image {
1274 id: serviceIcon
1275 anchors {
1276 left: parent.left
1277- bottom: status_update_content.bottom
1278+ bottom: statusUpdateContent.bottom
1279 topMargin: units.gu(1)
1280 leftMargin: units.gu(1)
1281 bottomMargin: units.gu(1)
1282@@ -145,269 +148,20 @@
1283 smooth: true
1284 }
1285
1286- Item {
1287- id: status_update_content
1288+ StatusUpdateContent {
1289+ id: statusUpdateContent
1290 anchors {
1291 left: avatarImage.right
1292 right: parent.right
1293 top: parent.top
1294- topMargin: units.gu(1)
1295- leftMargin: units.gu(1)
1296- bottomMargin: units.gu(1)
1297- rightMargin: units.gu(1)
1298- }
1299- height: childrenRect.height
1300-
1301- MouseArea {
1302- anchors.fill: status_update_content
1303- onClicked: {
1304- if (tile.state != 'Details') {
1305- tile.state = 'Details';
1306- } else {
1307- tile.state = 'List';
1308- }
1309- }
1310- }
1311-
1312- Column {
1313- spacing: units.gu(1)
1314- anchors {
1315- left: parent.left;
1316- right: parent.right
1317- bottomMargin: units.gu(2)
1318- }
1319- Item {
1320- anchors {
1321- left: parent.left
1322- right: parent.right
1323- rightMargin: units.gu(1)
1324- }
1325- height: childrenRect.height
1326- Label {
1327- text: sender
1328- fontSize: "medium"
1329- font.bold: true
1330- anchors {
1331- left: parent.left
1332- right: time.left
1333- }
1334- wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1335- }
1336- Label {
1337- id: time
1338- anchors {
1339- right: parent.right
1340- }
1341-
1342- text: timeString
1343- fontSize: "small"
1344- color: Theme.palette.normal.baseText
1345- }
1346- }
1347-
1348- Label {
1349- id: messageText
1350- anchors {
1351- right: parent.right
1352- left: parent.left
1353- }
1354- text: message
1355- maximumLineCount: tile.state != 'Details' ? 10 : 0
1356- elide: Text.ElideRight
1357- visible: message.length > 0 && message != linkDescription
1358- wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1359- textFormat: Text.StyledText
1360- linkColor: Theme.palette.normal.baseText
1361- onLinkActivated: Qt.openUrlExternally(link)
1362- }
1363- UbuntuShape {
1364- height: locationName.height + units.gu(1)
1365- width: locationName.width + units.gu(2)
1366- visible: location.length > 0
1367- Label {
1368- id: locationName
1369- anchors.centerIn: parent
1370- text: location
1371- wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1372- }
1373- MouseArea {
1374- anchors.fill: parent
1375- onClicked: {
1376- if (url.length > 0)
1377- {
1378- Qt.openUrlExternally(url);
1379- }
1380- }
1381- }
1382- }
1383- UbuntuShape {
1384- height: linkNameShape.height + units.gu(1)
1385- width: linkNameShape.width + units.gu(2)
1386- visible: linkName.length > 0
1387- Label {
1388- id: linkNameShape
1389- anchors.centerIn: parent
1390- text: linkName
1391- wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1392- }
1393- MouseArea {
1394- anchors.fill: parent
1395- onClicked: {
1396- if (linkUrl.length > 0)
1397- Qt.openUrlExternally(linkUrl);
1398-
1399- }
1400- }
1401- }
1402- Label {
1403- id: linkDesc
1404- anchors {
1405- right: parent.right
1406- left: parent.left
1407- }
1408- text: linkDescription
1409- maximumLineCount: tile.state != 'Details' ? 10 : 0
1410- elide: Text.ElideRight
1411- visible: linkDescription.length > 0
1412- wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1413- //width: parent.width - units.gu(3)
1414- textFormat: Text.StyledText
1415- onLinkActivated: Qt.openUrlExternally(link)
1416- }
1417-
1418- Row {
1419- id: favorite
1420- height: favoriteIcon.height + units.gu(1)
1421- anchors {
1422- left: parent.left
1423- right: parent.right
1424- bottomMargin: units.gu(1)
1425- }
1426- spacing: units.dp(3)
1427- Image {
1428- id: favoriteIcon
1429- width: units.gu(3)
1430- height: units.gu(3)
1431- opacity: liked ? 1.0 : 0.1
1432-
1433- source: "images/favorite.png"
1434- asynchronous: true
1435- MouseArea {
1436- anchors.fill: favoriteIcon
1437- onClicked: {
1438- favoriteSpinner.visible = true;
1439- if (liked) {
1440- friends.unlikeAsync(accountId, messageId);
1441- }
1442- else {
1443- friends.likeAsync(accountId, messageId);
1444- }
1445- }
1446- }
1447- ActivityIndicator {
1448- id: favoriteSpinner
1449- anchors.centerIn: parent
1450- width: parent.width
1451- visible: false
1452- running: visible
1453- }
1454- }
1455- Label {
1456- id: likesLabel
1457- text: (likeCount > 0) ? likeCount + " " + likesString : ""
1458- fontSize: "small"
1459- color: Theme.palette.normal.baseText
1460- }
1461- }
1462-
1463- Item {
1464- id: repeatIcon
1465- anchors {
1466- right: parent.right
1467- bottom: parent.bottom
1468- rightMargin: units.gu(2)
1469- bottomMargin: units.gu(1)
1470- }
1471-
1472- opacity: detailsOpacity
1473- height: fromMe ? 0 : childrenRect.height
1474- // FIXME: Use features API instead
1475- visible: (service == "twitter" || service == "identica") && !fromMe && stream != "private"
1476- Image {
1477- id: repeatIconImage
1478- width: units.gu(3)
1479- height: units.gu(3)
1480- source: "images/share.png"
1481- asynchronous: true
1482- visible: retweetSpinner.visble ? false : true
1483- MouseArea {
1484- anchors.fill: parent
1485- onClicked: {
1486- console.log ("Retweeting " + messageId + " from " + accountId);
1487- retweetSpinner.visible = true
1488- friends.retweetAsync(accountId, messageId);
1489- }
1490- }
1491- ActivityIndicator {
1492- id: retweetSpinner
1493- anchors.centerIn: parent
1494- //width: parent.width
1495- visible: false
1496- running: visible
1497- }
1498- }
1499- }
1500-
1501- }
1502- }
1503-
1504- Item {
1505- id: detailsWrapper
1506- height: detailsLoader.height + units.gu(1)
1507- opacity: detailsOpacity
1508- visible: detailsOpacity > 0
1509- anchors {
1510- top: status_update_content.bottom
1511- left: parent.left
1512- right: parent.right
1513- }
1514-
1515- Loader {
1516- id: detailsLoader
1517- anchors {
1518- right: parent.right
1519- left: parent.left
1520- }
1521- visible: true
1522- }
1523-
1524- onVisibleChanged: {
1525- if (visible && detailsLoader.state != Loader.Ready) {
1526- detailsLoader.source = "StatusUpdateTileDetails.qml";
1527- }
1528- }
1529- }
1530- }
1531-
1532- states: [State {
1533- name: "Details"
1534- PropertyChanges { target: tile; detailsOpacity: 1; x: 0 }
1535- StateChangeScript {
1536- script: {
1537- listView.positionViewAtIndex(listView.indexAt(tile.x, tile.y), ListView.Contain);
1538- }
1539- }
1540-
1541- },
1542- State {
1543- name: "List"
1544- PropertyChanges { target: tile; detailsOpacity: 0; x: 0 }
1545- }]
1546-
1547-
1548- transitions: Transition {
1549- NumberAnimation {
1550- duration: 300; properties: "detailsOpacity,x,height,width"
1551+ }
1552+ }
1553+
1554+ MouseArea {
1555+ anchors.fill: statusUpdateContent
1556+ onClicked: {
1557+ showConversation();
1558+ }
1559 }
1560 }
1561 }
1562
1563=== modified file 'qml/ThreadView.qml'
1564--- qml/ThreadView.qml 2013-08-20 15:17:54 +0000
1565+++ qml/ThreadView.qml 2014-01-23 12:09:15 +0000
1566@@ -3,9 +3,15 @@
1567 import Friends 0.2
1568
1569 Item {
1570- height: threadListView.height + pictureImage.height
1571+ id: threadView
1572+
1573+ height: threadListView.height
1574+
1575 width: parent.width
1576+
1577 anchors {
1578+ left: parent.left
1579+ right: parent.right
1580 bottomMargin: units.gu(2)
1581 }
1582
1583@@ -14,102 +20,49 @@
1584 stream: "reply_to/"+messageId
1585 }
1586
1587-
1588 FriendsUtils {
1589 id: friendsUtils
1590 }
1591
1592 Column {
1593 id: threadListView
1594+ anchors {
1595+ left: parent.left
1596+ right: parent.right
1597+ }
1598+
1599 width: parent.width
1600+ height: childrenRect.height
1601+
1602 Repeater {
1603+ id: repeater
1604 width: parent.width
1605 model: streamModel
1606 delegate: Item {
1607 id: threadItem
1608- width: parent.width - units.gu(8)
1609+
1610 anchors {
1611 right: parent.right
1612- leftMargin: units.gu(8)
1613- rightMargin: units.gu(2)
1614+ left: parent.left
1615+
1616+ leftMargin: units.gu(4)
1617 bottomMargin: units.gu(2)
1618 }
1619- height: status_update_content.height
1620-
1621- UbuntuShape {
1622+
1623+ height: childrenRect.height
1624+
1625+ AvatarImage {
1626 id: avatarImage
1627- radius: "small"
1628- height: units.dp(32)
1629- width: units.dp(32)
1630- anchors {
1631- left: parent.left
1632- top: parent.top
1633- leftMargin: units.gu(1)
1634- topMargin: units.gu(1)
1635- }
1636- image: Image {
1637- source: Qt.resolvedUrl(avatar)
1638- asynchronous: true
1639- fillMode: Image.PreserveAspectFit
1640- }
1641 }
1642
1643- Item {
1644- id: status_update_content
1645+ StatusUpdateContent {
1646 anchors {
1647 left: avatarImage.right
1648 right: parent.right
1649 top: parent.top
1650- topMargin: units.gu(1)
1651- leftMargin: units.gu(1)
1652- bottomMargin: units.gu(1)
1653- rightMargin: units.gu(1)
1654- }
1655- width: parent.width - avatarImage.width
1656- height: childrenRect.height + units.gu(1)
1657-
1658- Column {
1659- width: parent.width
1660- spacing: 0
1661- anchors {
1662- left: parent.left;
1663- right: parent.right
1664- bottomMargin: units.gu(2)
1665- }
1666- Label {
1667- text: sender
1668- fontSize: "small"
1669- font.bold: true
1670- width: parent.width
1671- }
1672- Label {
1673- id: messageText
1674- text: message
1675- wrapMode: Text.WrapAtWordBoundaryOrAnywhere
1676- width: parent.width - units.gu(3)
1677- fontSize: "small"
1678- onLinkActivated: {
1679- console.log(link + " link activated");
1680- Qt.openUrlExternally(link);
1681- }
1682- }
1683- }
1684- Row {
1685- anchors.right: parent.right
1686- anchors.rightMargin: units.gu(1)
1687- anchors.top: parent.top
1688- spacing: units.gu(1)
1689-
1690- Text {
1691- id: time
1692- text: friendsUtils.createTimeString(timestamp)
1693- font.family: "Ubuntu"
1694- font.pointSize: 8
1695- color: Theme.palette.normal.baseText
1696- }
1697 }
1698 }
1699- }
1700+ }
1701 }
1702 }
1703 }
1704
1705=== modified file 'qml/friends-app.qml'
1706--- qml/friends-app.qml 2013-12-11 21:06:40 +0000
1707+++ qml/friends-app.qml 2014-01-23 12:09:15 +0000
1708@@ -19,9 +19,24 @@
1709 import Ubuntu.Components 0.1
1710 import Ubuntu.Unity.Action 1.0 as UnityActions
1711 import Ubuntu.OnlineAccounts 0.1
1712+import Ubuntu.Layouts 0.1
1713 import Friends 0.2
1714
1715 MainView {
1716+ function addConversation(tile) {
1717+ conversationPage.setContent(tile)
1718+
1719+ pageStack.push(conversationPage)
1720+ }
1721+
1722+ function closeConversation() {
1723+ pageStack.pop()
1724+ }
1725+
1726+ function refresh() {
1727+ friends.refresh()
1728+ }
1729+
1730 id: main
1731 applicationName: "friends-app"
1732 // objectName for functional testing purposes (autopilot-qt5)
1733@@ -34,6 +49,8 @@
1734 backgroundColor: "#273d66"
1735 headerColor: "#395996"
1736
1737+ property bool loaded: false
1738+
1739 property bool isPortrait: (height > width)
1740 property bool loaded: false
1741
1742@@ -57,7 +74,7 @@
1743 id: topAction
1744 text: i18n.tr("Top")
1745 iconSource: ("images/go-top.png")
1746- onTriggered: feedTabs.selectedTab.jumpToTop()
1747+ onTriggered: feedTabs.jumpToTop()
1748 }
1749
1750 actions: [topAction, refreshAction, postAction]
1751@@ -87,12 +104,12 @@
1752 id: pageStack
1753
1754 Component.onCompleted: {
1755- console.log ("accounts.count: "+accounts.count);
1756- pageStack.push(mainPage);
1757+ console.log ("accounts.count: "+accounts.count)
1758+
1759 if (accounts.count < 1)
1760- pageStack.push(noAccountsPage);
1761-
1762- loaded = true
1763+ pageStack.push(noAccountsPage)
1764+ else
1765+ pageStack.push(feedTabs)
1766 }
1767
1768 Page {
1769@@ -126,47 +143,16 @@
1770 }
1771 }
1772
1773- Page {
1774- id: mainPage
1775+ FeedTabs {
1776 visible: false
1777-
1778- Tabs {
1779- id: feedTabs
1780-
1781- Feed {
1782- id: timeline
1783- title: i18n.tr("Timeline")
1784-
1785- stream: "" //all
1786- }
1787-
1788- Feed {
1789- id: mentions
1790- title: i18n.tr("Mentions")
1791-
1792- stream: "mentions"
1793- }
1794-
1795- /* The stream filter doesn't seem to work yet
1796- TimeLine {
1797- id: privateMessages
1798- title: i18n.tr("Private")
1799-
1800- stream: "private"
1801- }*/
1802- }
1803-
1804- tools: ToolbarItems {
1805- ToolbarButton {
1806- action: topAction
1807- }
1808- ToolbarButton {
1809- action: refreshAction
1810- }
1811- ToolbarButton {
1812- action: postAction
1813- }
1814- }
1815+ id: feedTabs
1816+ }
1817+
1818+ // Pages cannot be nested so we have to work around this restriction
1819+ // See this bug for some infos: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1256420
1820+ ConversationPage {
1821+ visible: false
1822+ id: conversationPage
1823 }
1824 }
1825 }
1826
1827=== modified file 'qml/qml.pro'
1828--- qml/qml.pro 2013-03-30 18:20:11 +0000
1829+++ qml/qml.pro 2014-01-23 12:09:15 +0000
1830@@ -13,5 +13,4 @@
1831 INSTALLS = install_resources
1832
1833 OTHER_FILES += \
1834- ThreadView.qml \
1835- RefreshBar.qml
1836+ FeedTabs.qml

Subscribers

People subscribed via source and target branches

to all changes: