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
=== modified file 'friends-app.pro'
--- friends-app.pro 2013-04-08 14:56:46 +0000
+++ friends-app.pro 2014-01-23 12:09:15 +0000
@@ -24,3 +24,5 @@
24INSTALLS += accounts24INSTALLS += accounts
2525
26SUBDIRS += src qml po tests26SUBDIRS += src qml po tests
27
28
2729
=== added file 'qml/AvatarImage.qml'
--- qml/AvatarImage.qml 1970-01-01 00:00:00 +0000
+++ qml/AvatarImage.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,29 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4UbuntuShape {
5 id: avatarImage
6 height: units.dp(48)
7 width: units.dp(48)
8
9 // We can only specify top margin, as this is displayed in a Row element
10 anchors {
11 topMargin: units.gu(1)
12 top: parent.top
13 }
14
15 image: Image {
16 source: Qt.resolvedUrl(avatar)
17 asynchronous: true
18 smooth: true
19 fillMode: Image.PreserveAspectCrop
20 sourceSize.width: units.dp(48)
21 }
22
23 MouseArea {
24 anchors.fill: avatarImage
25 onClicked: {
26 Qt.openUrlExternally(url);
27 }
28 }
29}
030
=== renamed file 'qml/StatusUpdateTileDetails.qml' => 'qml/ConversationDetails.qml'
--- qml/StatusUpdateTileDetails.qml 2013-08-20 15:17:54 +0000
+++ qml/ConversationDetails.qml 2014-01-23 12:09:15 +0000
@@ -22,7 +22,11 @@
2222
23Item {23Item {
24 id: details24 id: details
25 height: visible ? childrenRect.height + units.gu(1) : 025 height: childrenRect.height + units.gu(1)
26
27 function isMicroblogging() {
28 return (service === "twitter") || (service === "identica")
29 }
2630
27 FriendsDispatcher {31 FriendsDispatcher {
28 id: friends32 id: friends
@@ -41,12 +45,18 @@
4145
42 Item {46 Item {
43 id: pictureWrapper47 id: pictureWrapper
44 anchors.right: parent.right48
49 anchors {
50 right: parent.right
51 top: parent.top
52 }
53
45 width: parent.width - units.gu(8)54 width: parent.width - units.gu(8)
46 height: childrenRect.height55 height: childrenRect.height
4756
48 Image {57 Image {
49 id: pictureImage58 id: pictureImage
59 anchors.fill: parent
50 visible: linkPicture.length > 0 && status == Image.Ready60 visible: linkPicture.length > 0 && status == Image.Ready
51 source: Qt.resolvedUrl(linkPicture)61 source: Qt.resolvedUrl(linkPicture)
52 asynchronous: true62 asynchronous: true
@@ -73,9 +83,9 @@
73 anchors.top: pictureWrapper.bottom83 anchors.top: pictureWrapper.bottom
74 source: {84 source: {
75 return "http://open.mapquestapi.com/staticmap/v4/getmap?size=" +85 return "http://open.mapquestapi.com/staticmap/v4/getmap?size=" +
76 Math.round(Math.min(parent.width * 0.8, units.gu(20))) + "," +86 Math.round(Math.min(parent.width * 0.8, units.gu(20))) + "," +
77 Math.round(Math.min(parent.width * 0.8, units.gu(20))) +87 Math.round(Math.min(parent.width * 0.8, units.gu(20))) +
78 "&zoom=12&center=" + latitude + "," + longitude88 "&zoom=12&center=" + latitude + "," + longitude
7989
80 }90 }
81 visible: location.length > 091 visible: location.length > 0
@@ -84,7 +94,6 @@
84 ThreadView {94 ThreadView {
85 id: threadView95 id: threadView
86 width: parent.width96 width: parent.width
87 height: childrenRect.height
8897
89 anchors {98 anchors {
90 top: mapimage.bottom99 top: mapimage.bottom
@@ -94,117 +103,46 @@
94 }103 }
95104
96 Item {105 Item {
97 id: entry106 id: bottom
98 property var lastCursorPosition
99 height: childrenRect.height
100 anchors {107 anchors {
108 left: parent.left
109 right: parent.right
101 top: threadView.bottom110 top: threadView.bottom
102 left: parent.left
103 right: parent.right
104 topMargin: units.gu(2)
105 }111 }
106112
107 TextArea {113 height: childrenRect.height
108 id: entryArea114
115 ReplyArea {
116 id: replyArea
117
109 anchors {118 anchors {
119 top: parent.top
110 left: parent.left120 left: parent.left
111 leftMargin: units.gu(2)121 right: parent.right
112 right: sendButton.left122 topMargin: units.gu(2)
113 rightMargin: units.gu(1)
114 bottomMargin: units.gu(1.5)
115 }
116 // send message if return was pressed
117 Keys.onReturnPressed: sendButton.clicked(null)
118 Keys.onEscapePressed: text = ""
119 height: units.gu(4)
120 placeholderText: i18n.tr("Reply")
121 autoSize: true
122 maximumLineCount: 0
123 color: text.length < 140 ? "gray" : "red"
124 textFormat: TextEdit.PlainText
125 contentWidth: width - units.gu(5)
126 onActiveFocusChanged: {
127 if (activeFocus) {
128 if (service == "twitter" || service == "identica") {
129 if (entryArea.text.search("@"+senderNick) == -1) {
130 entryArea.text = "@"+senderNick+" ";
131 cursorPosition = text.length;
132 }
133 }
134 }
135 }
136
137 onTextChanged: {
138 var enteredText = text.substring(entry.lastCursorPosition, cursorPosition);
139 if (enteredText.substring(0,4) == "http") {
140 var shortUrl = friends.urlShorten(enteredText);
141 if (shortUrl.length > 4) {
142 text = text.replace (enteredText, shortUrl);
143 cursorPosition = text.length;
144 }
145 }
146 entry.lastCursorPosition = cursorPosition;
147 }
148
149 Item {
150 id: counter
151 anchors {
152 right: entryArea.right
153 top: entryArea.top
154 rightMargin: units.gu(1)
155 }
156 height: units.gu(4)
157 width: childrenRect.width
158 visible: entryArea.text.length > 0 ? true : false
159 Text {
160 text: 140 - entryArea.text.length
161 font.bold: true
162 opacity: 0.3
163 }
164 }
165 Button {
166 id: clearButton
167 anchors {
168 right: entryArea.right
169 bottom: entryArea.bottom
170 rightMargin: units.gu(1)
171 }
172 width: units.gu(2)
173 height: units.gu(2)
174 visible: entryArea.text.length > 0 ? true : false
175 iconSource: "images/clear-search.png"
176 color: "transparent"
177 opacity: 0.3
178 onClicked: {
179 entryArea.text = "";
180 }
181 }123 }
182 }124 }
183125
126 // Back button (much faster than using the toolbar)
127 // At the bottom so it doesn't steal any space (content is flickable)
184 Button {128 Button {
185 id: sendButton129 id: returnButton
130
186 anchors {131 anchors {
132 top: replyArea.bottom
133 left: parent.left
187 right: parent.right134 right: parent.right
188 rightMargin: units.gu(1)135 margins: units.gu(5)
189 bottom: entryArea.bottom
190 }136 }
191 width: units.gu(9)137
192 height: units.gu(4)138 text: i18n.tr("Return to feed")
193 text: i18n.tr("Send")139
194 color: main.headerColor140 height: units.gu(6)
141
195 onClicked: {142 onClicked: {
196 console.log ("Reply to " + messageId + " from " + accountId + ": " + entryArea.text);143 conversationPage.close()
197 sendSpinner.visible = true
198 friends.sendReplyAsync(accountId, messageId, entryArea.text);
199 }144 }
200 }145 }
201
202 ActivityIndicator {
203 id: sendSpinner
204 anchors.centerIn: entryArea
205 visible: false
206 running: visible
207 }
208 }146 }
209147
210 Component {148 Component {
211149
=== added file 'qml/ConversationPage.qml'
--- qml/ConversationPage.qml 1970-01-01 00:00:00 +0000
+++ qml/ConversationPage.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,111 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4Page {
5 title: i18n.tr("Conversation")
6 id: conversationPage
7
8 flickable: content
9
10 function setContent(tile) {
11 this.tile = tile
12
13 //Assign all values of the tile to the conversation page
14 //This way we can have one page for all tiles
15 liked = tile.liked
16 likeCount = tile.likeCount
17 fromMe = tile.fromMe
18 service = tile.service
19 linkUrl = tile.linkUrl
20 linkName = tile.linkName
21 linkDescription = tile.linkDescription
22 avatar = tile.avatar
23 message = tile.message
24 timeString = tile.timeString
25 location = tile.location
26 sender = tile.sender
27 linkPicture = tile.linkPicture
28 latitude = tile.latitude
29 longitude = tile.longitude
30 messageId = tile.messageId
31 stream = tile.stream
32 senderNick = tile.senderNick
33 url = tile.url
34 }
35
36 //Forward properties from StatusUpdateTile
37 property bool liked
38 property int likeCount
39 property bool fromMe
40 property string service
41 property string linkUrl
42 property string linkName
43 property string linkDescription
44 property variant avatar
45 property string message
46 property variant tile
47 property string timeString
48 property string location
49 property string sender
50 property string linkPicture
51 property int latitude
52 property int longitude
53 property string messageId
54 property string stream
55 property string senderNick
56 property string url
57
58 function close() {
59 main.closeConversation();
60 }
61
62 Flickable {
63 id: content
64
65 anchors {
66 fill: parent
67 margins: units.gu(2)
68 }
69
70 contentHeight: column.height
71
72 flickableDirection: Flickable.VerticalFlick
73 boundsBehavior: Flickable.DragOverBounds
74
75 // Looks much nicer on broad displays
76 width: Math.min(parent.width, units.gu(80))
77
78 Column {
79 id: column
80
81 width: parent.width
82 height: childrenRect.height
83
84 Row {
85 width: parent.width
86 spacing: units.gu(1)
87
88 AvatarImage {
89 id: avatarImage
90 }
91
92 StatusUpdateContent {
93 id: statusUpdateContent
94
95 width: parent.width - avatarImage.width
96 showDetails: true
97 }
98 }
99
100 ConversationDetails {
101 width: parent.width
102
103 id: details
104 }
105 }
106
107 }
108 Keys.onEscapePressed: {
109 conversationPage.close()
110 }
111}
0112
=== added file 'qml/EntryField.qml'
--- qml/EntryField.qml 1970-01-01 00:00:00 +0000
+++ qml/EntryField.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,119 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4Item {
5 id: entryField
6
7 onVisibleChanged: {
8 if(visible)
9 entryArea.forceActiveFocus()
10 }
11
12 property var lastCursorPosition
13 anchors.fill: parent
14
15 function setText(text) {
16 entryArea.text = text + " "
17 entryArea.cursorPosition = text.length + 1
18 }
19
20 TextArea {
21 id: entryArea
22 anchors {
23 top: parent.top
24 bottom: parent.bottom
25 left: parent.left
26 leftMargin: units.gu(1)
27 right: sendButton.left
28 rightMargin: units.gu(1)
29 }
30
31 // send message if return was pressed
32 Keys.onReturnPressed: sendButton.clicked(null)
33 Keys.onEscapePressed: text = ""
34 height: units.gu(4)
35 placeholderText: i18n.tr("Reply")
36 autoSize: true
37 maximumLineCount: 0
38 color: text.length < 140 ? "gray" : "red"
39 textFormat: TextEdit.PlainText
40 contentWidth: width - units.gu(5)
41
42 onTextChanged: {
43 var enteredText = text.substring(entryField.lastCursorPosition, cursorPosition);
44 if (enteredText.substring(0,4) == "http") {
45 var shortUrl = friends.urlShorten(enteredText);
46 if (shortUrl.length > 4) {
47 text = text.replace (enteredText, shortUrl);
48 cursorPosition = text.length;
49 }
50 }
51 entryField.lastCursorPosition = cursorPosition;
52 }
53
54 Item {
55 id: counter
56 anchors {
57 right: entryArea.right
58 top: entryArea.top
59 rightMargin: units.gu(1)
60 }
61 height: units.gu(4)
62 width: childrenRect.width
63
64 visible: (isMicroblogging() && entryArea.text.length > 0) ? true : false
65 Text {
66 text: 140 - entryArea.text.length
67 font.bold: true
68 opacity: 0.3
69 }
70 }
71 }
72
73 Button {
74 id: sendButton
75
76 anchors {
77 right: parent.right
78 rightMargin: units.gu(1)
79 top: parent.top
80 }
81
82 width: units.gu(9)
83 height: units.gu(4)
84 text: i18n.tr("Send")
85 color: main.headerColor
86 onClicked: {
87 console.log ("Reply to " + messageId + " from " + accountId + ": " + entryArea.text);
88 sendSpinner.visible = true
89 friends.sendReplyAsync(accountId, messageId, entryArea.text);
90 }
91 }
92 Button {
93 id: clearButton
94
95 anchors {
96 right: parent.right
97 top: sendButton.bottom
98 rightMargin: units.gu(1)
99 topMargin: units.gu(1)
100 }
101
102 height: sendButton.height
103 width: sendButton.width
104 iconSource: "images/clear-search.png"
105 color: main.headerColor
106
107 onClicked: {
108 entryArea.text = ""
109 entryField.visible = false
110 }
111 }
112
113 ActivityIndicator {
114 id: sendSpinner
115 anchors.centerIn: entryArea
116 visible: false
117 running: visible
118 }
119}
0120
=== added file 'qml/FavoriteIcon.qml'
--- qml/FavoriteIcon.qml 1970-01-01 00:00:00 +0000
+++ qml/FavoriteIcon.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,50 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4Row {
5 id: favorite
6
7 height: favoriteIcon.height + units.gu(1)
8 anchors {
9 left: parent.left
10 right: parent.right
11 bottomMargin: units.gu(1)
12 }
13 spacing: units.dp(3)
14
15 Image {
16 id: favoriteIcon
17 width: units.gu(3)
18 height: units.gu(3)
19 opacity: liked ? 1.0 : 0.1
20
21 source: "images/favorite.png"
22 asynchronous: true
23 MouseArea {
24 anchors.fill: favoriteIcon
25 onClicked: {
26 favoriteSpinner.visible = true;
27 if (liked) {
28 friends.unlikeAsync(accountId, messageId);
29 }
30 else {
31 friends.likeAsync(accountId, messageId);
32 }
33 }
34 }
35 ActivityIndicator {
36 id: favoriteSpinner
37 anchors.centerIn: parent
38 width: parent.width
39 visible: false
40 running: visible
41 }
42 }
43
44 Label {
45 id: likesLabel
46 text: (likeCount > 0) ? likeCount + " " + likesString : ""
47 fontSize: "small"
48 color: Theme.palette.normal.baseText
49 }
50}
051
=== modified file 'qml/Feed.qml'
--- qml/Feed.qml 2013-11-03 10:35:46 +0000
+++ qml/Feed.qml 2014-01-23 12:09:15 +0000
@@ -21,9 +21,15 @@
21import Ubuntu.Components.ListItems 0.1 as ListItem21import Ubuntu.Components.ListItems 0.1 as ListItem
22import Friends 0.222import Friends 0.2
2323
24Tab {24Page {
25 anchors.fill: parent
26 clip: true
27
28 property alias flickable: listView
29
25 property alias stream: streamModel.stream30 property alias stream: streamModel.stream
26 property int unseen: 031 property alias service: streamModel.service
32
27 property string search33 property string search
2834
29 /* Jump to the bottom of the view and set the currentIndex */35 /* Jump to the bottom of the view and set the currentIndex */
@@ -38,12 +44,8 @@
38 listView.currentIndex = 0;44 listView.currentIndex = 0;
39 }45 }
4046
41 onUnseenChanged: {
42 updatesText.text = unseen == 1 ? (unseen + i18n.tr(" new update")) : (unseen + i18n.tr(" new updates"));
43 }
44
45 Component.onCompleted: {47 Component.onCompleted: {
46 listView.focus = true;48 listView.focus = true
47 }49 }
4850
49 Timer {51 Timer {
@@ -57,18 +59,12 @@
57 id: statusDelegate59 id: statusDelegate
5860
59 ListItem.Empty {61 ListItem.Empty {
60 anchors {
61 left: parent.left
62 right: parent.right
63 }
64 height: content.height62 height: content.height
6563
66 StatusUpdateTile {64 StatusUpdateTile {
67 id: content65 id: content
68 height: childrenRect.height66 height: childrenRect.height
69 ListView.onAdd: SequentialAnimation {67
70 ScriptAction { script: {unseen++; console.log(column_0[0][0] + " " + column_0[0][1] + " " + column_0[0][2]) }}
71 }
72 Connections {68 Connections {
73 target: updateTimestampsTimer69 target: updateTimestampsTimer
74 onTriggered: {70 onTriggered: {
@@ -84,23 +80,12 @@
84 objectName: "streamModel"80 objectName: "streamModel"
85 }81 }
8682
87 onStreamChanged: {
88 console.log("stream changed to " + stream);
89 streamModel.stream = stream;
90 }
91
92 onSearchChanged: {
93 console.log ("onSearchChanged");
94 }
95
96 RefreshBar {83 RefreshBar {
97 id: refreshBar84 id: refreshBar
9885
99 anchors.top: parent.top86 opacity: visible ? 1.0 : 0.0
100 anchors.topMargin: units.gu(1)87 visible: listView.dragging && listView.onTop
10188
102 opacity: 0
103 visible: opacity > 0 ? true : false
104 Behavior on opacity {89 Behavior on opacity {
105 NumberAnimation { duration: 200; }90 NumberAnimation { duration: 200; }
106 }91 }
@@ -109,13 +94,13 @@
109 ListView {94 ListView {
110 id: listView95 id: listView
111 objectName: "listView"96 objectName: "listView"
112 height: parent.height - toolbar.height - units.gu(2)97
113 width: parent.width
114 anchors {98 anchors {
115 top: updatesBanner.bottom
116 topMargin: units.gu(1)
117 fill: parent99 fill: parent
118 }100 }
101
102 property bool onTop : listView.contentY <= -main.header.height
103
119 opacity: 1104 opacity: 1
120 spacing: units.gu(1)105 spacing: units.gu(1)
121 model: streamModel106 model: streamModel
@@ -128,6 +113,7 @@
128113
129 preferredHighlightBegin: 0114 preferredHighlightBegin: 0
130 preferredHighlightEnd: preferredHighlightBegin115 preferredHighlightEnd: preferredHighlightBegin
116
131 /* We need highlightRangeMode for keyboard navigation,117 /* We need highlightRangeMode for keyboard navigation,
132 * but it forces the page header to stay hidden118 * but it forces the page header to stay hidden
133 * https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1201936119 * https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1201936
@@ -141,81 +127,37 @@
141 }127 }
142 }128 }
143129
144 /* Ensure we collapse details when scrolling */
145 onFlickStarted: {
146 if (listView.currentItem.state != "List")
147 listView.currentItem.state = "List";
148 }
149
150 /* Expand details on enter */130 /* Expand details on enter */
151 Keys.onReturnPressed: {131 Keys.onReturnPressed: {
152 if (listView.currentItem.state != "Details")132 listView.currentItem.showConversation()
153 listView.currentItem.state = "Details";
154 }
155
156 /* Collapse details on escape */
157 Keys.onEscapePressed: {
158 if (listView.currentItem.state != "List")
159 listView.currentItem.state = "List";
160 }133 }
161134
162 /* Handle home and end nav */135 /* Handle home and end nav */
163 Keys.onPressed: {136 Keys.onPressed: {
164 if (event.key == Qt.Key_Home) {137 if (event.key === Qt.Key_Home) {
165 jumpToTop();138 jumpToTop();
166 }139 }
167 else if (event.key == Qt.Key_End) {140 else if (event.key === Qt.Key_End) {
168 jumpToBottom();141 jumpToBottom();
169 }142 }
170 }143 }
171
172 onDragStarted: {
173 if (listView.atYBeginning)
174 refreshBar.opacity = 1.0;
175 }
176 onDragEnded: {
177 refreshBar.opacity = 0
178 if (refreshBar.refreshed) {
179 console.log ("Refreshed");
180 friends.refresh ();
181 }
182 }
183 }
184
185 Item {
186 id: updatesBanner
187 anchors {
188 top: parent.top
189 left: parent.left
190 right: parent.right
191 }
192 visible: unseen > 0
193 height: visible ? units.gu(3) : 0
194 Text {
195 id: updatesText
196 anchors {
197 centerIn: parent
198 bottom: parent.bottom
199 }
200 text: ""
201 font.family: "Ubuntu"
202 font.bold: true
203 font.pointSize: 12
204 color: Theme.palette.normal.baseText
205 }
206 MouseArea {
207 anchors.fill: parent
208 onClicked: {
209 unseen = 0;
210 updatesText.text = "";
211 updatesBanner.visible = false;
212 jumpToTop();
213 }
214 }
215 }144 }
216145
217 Scrollbar {146 Scrollbar {
218 flickableItem: listView147 flickableItem: listView
219 align: Qt.AlignTrailing148 align: Qt.AlignTrailing
220 }149 }
150
151
152 tools: ToolbarItems {
153 ToolbarButton {
154 action: topAction
155 }
156 ToolbarButton {
157 action: refreshAction
158 }
159 ToolbarButton {
160 action: postAction
161 }
162 }
221}163}
222164
=== added file 'qml/FeedTab.qml'
--- qml/FeedTab.qml 1970-01-01 00:00:00 +0000
+++ qml/FeedTab.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,23 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4Tab {
5 clip: true
6
7 //property alias flickable: feed.flickable
8
9 property string stream
10
11 function jumpToTop() {
12 feed.jumpToTop()
13 }
14
15 page: feed
16
17 Feed {
18 anchors.fill: parent
19
20 id: feed
21 stream: parent.stream
22 }
23}
024
=== added file 'qml/FeedTabs.qml'
--- qml/FeedTabs.qml 1970-01-01 00:00:00 +0000
+++ qml/FeedTabs.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,25 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4Tabs {
5 id: feedTabs
6 clip: true
7
8 function jumpToTop() {
9 feedTabs.selectedTab.jumpToTop()
10 }
11
12 FeedTab {
13 id: timeline
14
15 title: i18n.tr("Timeline")
16 stream: "" //all
17 }
18
19 FeedTab {
20 id: mentions
21
22 title: i18n.tr("Mentions")
23 stream: "mentions"
24 }
25}
026
=== added file 'qml/LinkDescription.qml'
--- qml/LinkDescription.qml 1970-01-01 00:00:00 +0000
+++ qml/LinkDescription.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,20 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4// Show the description link of a status update (if any)
5// Should only be used by StatusUpdateContent
6Label {
7 id: linkDesc
8
9 anchors {
10 right: parent.right
11 left: parent.left
12 }
13
14 text: linkDescription
15 elide: Text.ElideRight
16 visible: linkDescription.length > 0
17 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
18 textFormat: Text.StyledText
19 onLinkActivated: Qt.openUrlExternally(link)
20}
021
=== added file 'qml/LinkItem.qml'
--- qml/LinkItem.qml 1970-01-01 00:00:00 +0000
+++ qml/LinkItem.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,24 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4// Show link of a status update (if any)
5// Should only be used by StatusUpdateContent
6UbuntuShape {
7 height: linkNameShape.height + units.gu(1)
8 width: linkNameShape.width + units.gu(2)
9 visible: linkName.length > 0
10 Label {
11 id: linkNameShape
12 anchors.centerIn: parent
13 text: linkName
14 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
15 }
16 MouseArea {
17 anchors.fill: parent
18 onClicked: {
19 if (linkUrl.length > 0)
20 Qt.openUrlExternally(linkUrl);
21
22 }
23 }
24}
025
=== added file 'qml/LocationItem.qml'
--- qml/LocationItem.qml 1970-01-01 00:00:00 +0000
+++ qml/LocationItem.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,25 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4// Show location information of a status update (if any)
5// Should only be used by StatusUpdateContent
6UbuntuShape {
7 height: locationName.height + units.gu(1)
8 width: locationName.width + units.gu(2)
9 visible: location.length > 0
10 Label {
11 id: locationName
12 anchors.centerIn: parent
13 text: location
14 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
15 }
16 MouseArea {
17 anchors.fill: parent
18 onClicked: {
19 if (url.length > 0)
20 {
21 Qt.openUrlExternally(url);
22 }
23 }
24 }
25}
026
=== modified file 'qml/Post.qml'
--- qml/Post.qml 2013-12-12 18:08:32 +0000
+++ qml/Post.qml 2014-01-23 12:09:15 +0000
@@ -236,7 +236,21 @@
236 ListItem.Standard {236 ListItem.Standard {
237 text: displayName237 text: displayName
238 opacity: sw.checked ? 1.0 : 0.3238 opacity: sw.checked ? 1.0 : 0.3
239<<<<<<< TREE
239 iconName: accountIcon240 iconName: accountIcon
241=======
242
243 Component.onCompleted: {
244 //this fixes height if no icon can be found
245 if(icon) {
246 height = icon.height
247 }
248 }
249
250 //Show no icon if none is available
251 iconSource: iconName.length > 0 ? "image://gicon/"+iconName : ""
252
253>>>>>>> MERGE-SOURCE
240 control: CheckBox {254 control: CheckBox {
241 id: sw255 id: sw
242 checked: sendEnabled256 checked: sendEnabled
243257
=== modified file 'qml/RefreshBar.qml'
--- qml/RefreshBar.qml 2013-08-05 17:39:52 +0000
+++ qml/RefreshBar.qml 2014-01-23 12:09:15 +0000
@@ -21,6 +21,9 @@
21Item {21Item {
22 height: units.gu(4)22 height: units.gu(4)
23 anchors {23 anchors {
24 topMargin: main.header.height + units.gu(1) // show it below the header
25
26 top: parent.top
24 left: parent.left27 left: parent.left
25 right: parent.right28 right: parent.right
26 }29 }
2730
=== added file 'qml/RepeatIcon.qml'
--- qml/RepeatIcon.qml 1970-01-01 00:00:00 +0000
+++ qml/RepeatIcon.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,43 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4Item {
5 id: repeatIcon
6
7 anchors {
8 right: parent.right
9 bottom: parent.bottom
10 rightMargin: units.gu(2)
11 bottomMargin: units.gu(1)
12 }
13
14 height: fromMe ? 0 : childrenRect.height
15
16 // FIXME: Use features API instead
17 visible: showDetails &&
18 (service == "twitter" || service == "identica") && !fromMe && stream !== "private"
19
20 Image {
21 id: repeatIconImage
22 width: units.gu(3)
23 height: units.gu(3)
24 source: "images/share.png"
25 asynchronous: true
26 visible: retweetSpinner.visble ? false : true
27 MouseArea {
28 anchors.fill: parent
29 onClicked: {
30 console.log ("Retweeting " + messageId + " from " + accountId);
31 retweetSpinner.visible = true
32 friends.retweetAsync(accountId, messageId);
33 }
34 }
35 ActivityIndicator {
36 id: retweetSpinner
37 anchors.centerIn: parent
38 //width: parent.width
39 visible: false
40 running: visible
41 }
42 }
43}
044
=== added file 'qml/ReplyArea.qml'
--- qml/ReplyArea.qml 1970-01-01 00:00:00 +0000
+++ qml/ReplyArea.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,77 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4// This element shows either the reply/reply all buttons
5// Or a field to compose the reply
6Item {
7 id: replyArea
8 height: units.gu(4)
9
10 Button {
11 id: replyButton
12 visible: !entryField.visible
13 width: units.gu(10)
14
15 anchors {
16 leftMargin: units.gu(5)
17 left: parent.left
18 top: parent.top
19 bottom: parent.bottom
20 }
21
22 text: isMicroblogging() ? i18n.tr("Reply"): i18n.tr("Comment")
23
24 property var lastCursorPosition
25 height: childrenRect.height
26
27 onClicked : {
28 entryField.visible = true
29
30 if(isMicroblogging())
31 entryField.setText("@"+senderNick)
32 }
33 }
34
35 Button {
36 id: replyAllButton
37
38 // Only show if we are using micrblogging.
39 visible: !entryField.visible && isMicroblogging()
40 width: replyButton.width
41
42 anchors {
43 left: replyButton.right
44 leftMargin: units.gu(1)
45 top: parent.top
46 bottom: parent.bottom
47 }
48
49 text: i18n.tr("Reply All")
50
51 property var lastCursorPosition
52 height: childrenRect.height
53
54 onClicked : {
55 entryField.visible = true
56
57 if(isMicroblogging()) {
58 var text = "@"+senderNick;
59
60 var nicks = message.match(/[@][\w]+/g);
61
62 if (nicks !== null) {
63 for(var i = 0; i < nicks.length; ++i) {
64 text += " " + nicks[i];
65 }
66 }
67
68 entryField.setText(text)
69 }
70 }
71 }
72
73 EntryField {
74 id: entryField
75 visible: false
76 }
77}
078
=== added file 'qml/SenderAndTimeItem.qml'
--- qml/SenderAndTimeItem.qml 1970-01-01 00:00:00 +0000
+++ qml/SenderAndTimeItem.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,36 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4// Shows sender and time of a status update
5// Should only be used by StatusUpdateContent
6Item {
7 anchors {
8 left: parent.left
9 right: parent.right
10 rightMargin: units.gu(1)
11 }
12 height: childrenRect.height
13
14 Label {
15 text: sender
16 fontSize: "medium"
17 font.bold: true
18
19 anchors {
20 left: parent.left
21 right: time.left
22 }
23 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
24 }
25
26 Label {
27 id: time
28 anchors {
29 right: parent.right
30 }
31
32 text: timeString
33 fontSize: "small"
34 color: Theme.palette.normal.baseText
35 }
36}
037
=== added file 'qml/StatusUpdateContent.qml'
--- qml/StatusUpdateContent.qml 1970-01-01 00:00:00 +0000
+++ qml/StatusUpdateContent.qml 2014-01-23 12:09:15 +0000
@@ -0,0 +1,44 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4Column {
5 property bool showDetails: false
6 spacing: units.gu(1)
7 anchors.margins: units.gu(1)
8
9 SenderAndTimeItem {
10 }
11
12 Label {
13 id: messageText
14 anchors {
15 right: parent.right
16 left: parent.left
17 }
18 text: message
19
20 elide: Text.ElideRight
21 visible: message.length > 0 && message != linkDescription
22 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
23 textFormat: Text.StyledText
24 linkColor: Theme.palette.normal.baseText
25 onLinkActivated: Qt.openUrlExternally(link)
26 }
27
28 LocationItem {
29 }
30
31 LinkItem {
32 }
33
34 LinkDescription {
35 }
36
37 FavoriteIcon {
38 id: favorite
39 }
40
41 RepeatIcon {
42 id: repeatIcon
43 }
44}
045
=== modified file 'qml/StatusUpdateTile.qml'
--- qml/StatusUpdateTile.qml 2013-08-28 19:04:36 +0000
+++ qml/StatusUpdateTile.qml 2014-01-23 12:09:15 +0000
@@ -25,9 +25,32 @@
25 id: tile25 id: tile
26 anchors {26 anchors {
27 left: parent.left27 left: parent.left
28 right: parent.right 28 right: parent.right
29 }29 }
30 property real detailsOpacity : 030
31 //Forward properties
32 property bool liked : liked
33 property bool fromMe: fromMe
34 property string message: model.message
35 property string service: model.service
36 property string linkUrl: model.linkUrl
37 property string linkName: model.linkName
38 property string linkDescription: model.linkDescription
39 property string avatar: model.avatar
40 property string location: model.location
41 property string sender: model.sender
42 property string linkPicture: model.linkPicture
43 property int latitude: model.latitude
44 property int longitude: model.longitude
45 property string messageId: model.messageId
46 property string stream: model.stream
47 property string senderNick: model.senderNick
48 property string url: model.url
49
50 function showConversation() {
51 main.addConversation(tile)
52 }
53
31 property string timeString: friendsUtils.createTimeString(timestamp)54 property string timeString: friendsUtils.createTimeString(timestamp)
32 property int likeCount: likes > 0 ? likes : liked ? 1 : 055 property int likeCount: likes > 0 ? likes : liked ? 1 : 0
33 property string likesString: likeCount > 1 ? i18n.tr("people liked this") : i18n.tr("person liked this")56 property string likesString: likeCount > 1 ? i18n.tr("people liked this") : i18n.tr("person liked this")
@@ -42,8 +65,10 @@
42 anchors {65 anchors {
43 right: parent.right66 right: parent.right
44 left: parent.left67 left: parent.left
68 leftMargin: units.gu(1)
45 }69 }
46 height: status_update_content.height + detailsWrapper.height70
71 height: childrenRect.height + units.gu(1)
4772
48 FriendsUtils {73 FriendsUtils {
49 id: friendsUtils74 id: friendsUtils
@@ -61,46 +86,24 @@
61 }86 }
62 onUnlikeComplete: {87 onUnlikeComplete: {
63 favoriteSpinner.visible = false;88 favoriteSpinner.visible = false;
64 if (success) {89 if (success) {
65 console.log ("Like succeeded");90 console.log ("Like succeeded");
66 } else {91 } else {
67 console.log ("UnLike failed: " + errorMessage);92 console.log ("UnLike failed: " + errorMessage);
68 }93 }
69 }94 }
70 onRetweetComplete: {95 onRetweetComplete: {
71 retweetSpinner.visible = false;96 retweetSpinner.visible = false;
72 if (success) {97 if (success) {
73 console.log ("Retweet completed successfully");98 console.log ("Retweet completed successfully");
74 } else {99 } else {
75 console.log ("Retweet failed: " + errorMessage);100 console.log ("Retweet failed: " + errorMessage);
76 }101 }
77 }102 }
78 }103 }
79104
80 UbuntuShape {105 AvatarImage {
81 id: avatarImage106 id: avatarImage
82 height: units.dp(48)
83 width: units.dp(48)
84 anchors {
85 left: parent.left
86 top: parent.top
87 leftMargin: units.gu(1)
88 topMargin: units.gu(1)
89 }
90 image: Image {
91 source: Qt.resolvedUrl(avatar)
92 asynchronous: true
93 smooth: true
94 fillMode: Image.PreserveAspectCrop
95 sourceSize.width: units.dp(48)
96 }
97
98 MouseArea {
99 anchors.fill: avatarImage
100 onClicked: {
101 Qt.openUrlExternally(url);
102 }
103 }
104 }107 }
105108
106 Image {109 Image {
@@ -113,7 +116,7 @@
113 }116 }
114 source: "images/private.png"117 source: "images/private.png"
115 asynchronous: true118 asynchronous: true
116 visible: stream == "private"119 visible: stream === "private"
117 }120 }
118121
119 Image {122 Image {
@@ -126,14 +129,14 @@
126 }129 }
127 source: "images/replies.png"130 source: "images/replies.png"
128 asynchronous: true131 asynchronous: true
129 visible: stream == "mentions"132 visible: stream === "mentions"
130 }133 }
131134
132 Image {135 Image {
133 id: serviceIcon136 id: serviceIcon
134 anchors {137 anchors {
135 left: parent.left138 left: parent.left
136 bottom: status_update_content.bottom139 bottom: statusUpdateContent.bottom
137 topMargin: units.gu(1)140 topMargin: units.gu(1)
138 leftMargin: units.gu(1)141 leftMargin: units.gu(1)
139 bottomMargin: units.gu(1)142 bottomMargin: units.gu(1)
@@ -145,269 +148,20 @@
145 smooth: true148 smooth: true
146 }149 }
147150
148 Item {151 StatusUpdateContent {
149 id: status_update_content152 id: statusUpdateContent
150 anchors {153 anchors {
151 left: avatarImage.right154 left: avatarImage.right
152 right: parent.right155 right: parent.right
153 top: parent.top156 top: parent.top
154 topMargin: units.gu(1)157 }
155 leftMargin: units.gu(1)158 }
156 bottomMargin: units.gu(1)159
157 rightMargin: units.gu(1)160 MouseArea {
158 }161 anchors.fill: statusUpdateContent
159 height: childrenRect.height162 onClicked: {
160163 showConversation();
161 MouseArea {164 }
162 anchors.fill: status_update_content
163 onClicked: {
164 if (tile.state != 'Details') {
165 tile.state = 'Details';
166 } else {
167 tile.state = 'List';
168 }
169 }
170 }
171
172 Column {
173 spacing: units.gu(1)
174 anchors {
175 left: parent.left;
176 right: parent.right
177 bottomMargin: units.gu(2)
178 }
179 Item {
180 anchors {
181 left: parent.left
182 right: parent.right
183 rightMargin: units.gu(1)
184 }
185 height: childrenRect.height
186 Label {
187 text: sender
188 fontSize: "medium"
189 font.bold: true
190 anchors {
191 left: parent.left
192 right: time.left
193 }
194 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
195 }
196 Label {
197 id: time
198 anchors {
199 right: parent.right
200 }
201
202 text: timeString
203 fontSize: "small"
204 color: Theme.palette.normal.baseText
205 }
206 }
207
208 Label {
209 id: messageText
210 anchors {
211 right: parent.right
212 left: parent.left
213 }
214 text: message
215 maximumLineCount: tile.state != 'Details' ? 10 : 0
216 elide: Text.ElideRight
217 visible: message.length > 0 && message != linkDescription
218 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
219 textFormat: Text.StyledText
220 linkColor: Theme.palette.normal.baseText
221 onLinkActivated: Qt.openUrlExternally(link)
222 }
223 UbuntuShape {
224 height: locationName.height + units.gu(1)
225 width: locationName.width + units.gu(2)
226 visible: location.length > 0
227 Label {
228 id: locationName
229 anchors.centerIn: parent
230 text: location
231 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
232 }
233 MouseArea {
234 anchors.fill: parent
235 onClicked: {
236 if (url.length > 0)
237 {
238 Qt.openUrlExternally(url);
239 }
240 }
241 }
242 }
243 UbuntuShape {
244 height: linkNameShape.height + units.gu(1)
245 width: linkNameShape.width + units.gu(2)
246 visible: linkName.length > 0
247 Label {
248 id: linkNameShape
249 anchors.centerIn: parent
250 text: linkName
251 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
252 }
253 MouseArea {
254 anchors.fill: parent
255 onClicked: {
256 if (linkUrl.length > 0)
257 Qt.openUrlExternally(linkUrl);
258
259 }
260 }
261 }
262 Label {
263 id: linkDesc
264 anchors {
265 right: parent.right
266 left: parent.left
267 }
268 text: linkDescription
269 maximumLineCount: tile.state != 'Details' ? 10 : 0
270 elide: Text.ElideRight
271 visible: linkDescription.length > 0
272 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
273 //width: parent.width - units.gu(3)
274 textFormat: Text.StyledText
275 onLinkActivated: Qt.openUrlExternally(link)
276 }
277
278 Row {
279 id: favorite
280 height: favoriteIcon.height + units.gu(1)
281 anchors {
282 left: parent.left
283 right: parent.right
284 bottomMargin: units.gu(1)
285 }
286 spacing: units.dp(3)
287 Image {
288 id: favoriteIcon
289 width: units.gu(3)
290 height: units.gu(3)
291 opacity: liked ? 1.0 : 0.1
292
293 source: "images/favorite.png"
294 asynchronous: true
295 MouseArea {
296 anchors.fill: favoriteIcon
297 onClicked: {
298 favoriteSpinner.visible = true;
299 if (liked) {
300 friends.unlikeAsync(accountId, messageId);
301 }
302 else {
303 friends.likeAsync(accountId, messageId);
304 }
305 }
306 }
307 ActivityIndicator {
308 id: favoriteSpinner
309 anchors.centerIn: parent
310 width: parent.width
311 visible: false
312 running: visible
313 }
314 }
315 Label {
316 id: likesLabel
317 text: (likeCount > 0) ? likeCount + " " + likesString : ""
318 fontSize: "small"
319 color: Theme.palette.normal.baseText
320 }
321 }
322
323 Item {
324 id: repeatIcon
325 anchors {
326 right: parent.right
327 bottom: parent.bottom
328 rightMargin: units.gu(2)
329 bottomMargin: units.gu(1)
330 }
331
332 opacity: detailsOpacity
333 height: fromMe ? 0 : childrenRect.height
334 // FIXME: Use features API instead
335 visible: (service == "twitter" || service == "identica") && !fromMe && stream != "private"
336 Image {
337 id: repeatIconImage
338 width: units.gu(3)
339 height: units.gu(3)
340 source: "images/share.png"
341 asynchronous: true
342 visible: retweetSpinner.visble ? false : true
343 MouseArea {
344 anchors.fill: parent
345 onClicked: {
346 console.log ("Retweeting " + messageId + " from " + accountId);
347 retweetSpinner.visible = true
348 friends.retweetAsync(accountId, messageId);
349 }
350 }
351 ActivityIndicator {
352 id: retweetSpinner
353 anchors.centerIn: parent
354 //width: parent.width
355 visible: false
356 running: visible
357 }
358 }
359 }
360
361 }
362 }
363
364 Item {
365 id: detailsWrapper
366 height: detailsLoader.height + units.gu(1)
367 opacity: detailsOpacity
368 visible: detailsOpacity > 0
369 anchors {
370 top: status_update_content.bottom
371 left: parent.left
372 right: parent.right
373 }
374
375 Loader {
376 id: detailsLoader
377 anchors {
378 right: parent.right
379 left: parent.left
380 }
381 visible: true
382 }
383
384 onVisibleChanged: {
385 if (visible && detailsLoader.state != Loader.Ready) {
386 detailsLoader.source = "StatusUpdateTileDetails.qml";
387 }
388 }
389 }
390 }
391
392 states: [State {
393 name: "Details"
394 PropertyChanges { target: tile; detailsOpacity: 1; x: 0 }
395 StateChangeScript {
396 script: {
397 listView.positionViewAtIndex(listView.indexAt(tile.x, tile.y), ListView.Contain);
398 }
399 }
400
401 },
402 State {
403 name: "List"
404 PropertyChanges { target: tile; detailsOpacity: 0; x: 0 }
405 }]
406
407
408 transitions: Transition {
409 NumberAnimation {
410 duration: 300; properties: "detailsOpacity,x,height,width"
411 }165 }
412 }166 }
413}167}
414168
=== modified file 'qml/ThreadView.qml'
--- qml/ThreadView.qml 2013-08-20 15:17:54 +0000
+++ qml/ThreadView.qml 2014-01-23 12:09:15 +0000
@@ -3,9 +3,15 @@
3import Friends 0.23import Friends 0.2
44
5Item {5Item {
6 height: threadListView.height + pictureImage.height6 id: threadView
7
8 height: threadListView.height
9
7 width: parent.width10 width: parent.width
11
8 anchors {12 anchors {
13 left: parent.left
14 right: parent.right
9 bottomMargin: units.gu(2)15 bottomMargin: units.gu(2)
10 }16 }
1117
@@ -14,102 +20,49 @@
14 stream: "reply_to/"+messageId20 stream: "reply_to/"+messageId
15 }21 }
1622
17
18 FriendsUtils {23 FriendsUtils {
19 id: friendsUtils24 id: friendsUtils
20 }25 }
2126
22 Column {27 Column {
23 id: threadListView28 id: threadListView
29 anchors {
30 left: parent.left
31 right: parent.right
32 }
33
24 width: parent.width34 width: parent.width
35 height: childrenRect.height
36
25 Repeater {37 Repeater {
38 id: repeater
26 width: parent.width39 width: parent.width
27 model: streamModel40 model: streamModel
28 delegate: Item {41 delegate: Item {
29 id: threadItem42 id: threadItem
30 width: parent.width - units.gu(8)43
31 anchors {44 anchors {
32 right: parent.right45 right: parent.right
33 leftMargin: units.gu(8)46 left: parent.left
34 rightMargin: units.gu(2)47
48 leftMargin: units.gu(4)
35 bottomMargin: units.gu(2)49 bottomMargin: units.gu(2)
36 }50 }
37 height: status_update_content.height51
3852 height: childrenRect.height
39 UbuntuShape {53
54 AvatarImage {
40 id: avatarImage55 id: avatarImage
41 radius: "small"
42 height: units.dp(32)
43 width: units.dp(32)
44 anchors {
45 left: parent.left
46 top: parent.top
47 leftMargin: units.gu(1)
48 topMargin: units.gu(1)
49 }
50 image: Image {
51 source: Qt.resolvedUrl(avatar)
52 asynchronous: true
53 fillMode: Image.PreserveAspectFit
54 }
55 }56 }
5657
57 Item {58 StatusUpdateContent {
58 id: status_update_content
59 anchors {59 anchors {
60 left: avatarImage.right60 left: avatarImage.right
61 right: parent.right61 right: parent.right
62 top: parent.top62 top: parent.top
63 topMargin: units.gu(1)
64 leftMargin: units.gu(1)
65 bottomMargin: units.gu(1)
66 rightMargin: units.gu(1)
67 }
68 width: parent.width - avatarImage.width
69 height: childrenRect.height + units.gu(1)
70
71 Column {
72 width: parent.width
73 spacing: 0
74 anchors {
75 left: parent.left;
76 right: parent.right
77 bottomMargin: units.gu(2)
78 }
79 Label {
80 text: sender
81 fontSize: "small"
82 font.bold: true
83 width: parent.width
84 }
85 Label {
86 id: messageText
87 text: message
88 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
89 width: parent.width - units.gu(3)
90 fontSize: "small"
91 onLinkActivated: {
92 console.log(link + " link activated");
93 Qt.openUrlExternally(link);
94 }
95 }
96 }
97 Row {
98 anchors.right: parent.right
99 anchors.rightMargin: units.gu(1)
100 anchors.top: parent.top
101 spacing: units.gu(1)
102
103 Text {
104 id: time
105 text: friendsUtils.createTimeString(timestamp)
106 font.family: "Ubuntu"
107 font.pointSize: 8
108 color: Theme.palette.normal.baseText
109 }
110 }63 }
111 }64 }
112 }65 }
113 }66 }
114 }67 }
115}68}
11669
=== modified file 'qml/friends-app.qml'
--- qml/friends-app.qml 2013-12-11 21:06:40 +0000
+++ qml/friends-app.qml 2014-01-23 12:09:15 +0000
@@ -19,9 +19,24 @@
19import Ubuntu.Components 0.119import Ubuntu.Components 0.1
20import Ubuntu.Unity.Action 1.0 as UnityActions20import Ubuntu.Unity.Action 1.0 as UnityActions
21import Ubuntu.OnlineAccounts 0.121import Ubuntu.OnlineAccounts 0.1
22import Ubuntu.Layouts 0.1
22import Friends 0.223import Friends 0.2
2324
24MainView {25MainView {
26 function addConversation(tile) {
27 conversationPage.setContent(tile)
28
29 pageStack.push(conversationPage)
30 }
31
32 function closeConversation() {
33 pageStack.pop()
34 }
35
36 function refresh() {
37 friends.refresh()
38 }
39
25 id: main40 id: main
26 applicationName: "friends-app"41 applicationName: "friends-app"
27 // objectName for functional testing purposes (autopilot-qt5)42 // objectName for functional testing purposes (autopilot-qt5)
@@ -34,6 +49,8 @@
34 backgroundColor: "#273d66"49 backgroundColor: "#273d66"
35 headerColor: "#395996"50 headerColor: "#395996"
3651
52 property bool loaded: false
53
37 property bool isPortrait: (height > width)54 property bool isPortrait: (height > width)
38 property bool loaded: false55 property bool loaded: false
3956
@@ -57,7 +74,7 @@
57 id: topAction74 id: topAction
58 text: i18n.tr("Top")75 text: i18n.tr("Top")
59 iconSource: ("images/go-top.png")76 iconSource: ("images/go-top.png")
60 onTriggered: feedTabs.selectedTab.jumpToTop()77 onTriggered: feedTabs.jumpToTop()
61 }78 }
6279
63 actions: [topAction, refreshAction, postAction]80 actions: [topAction, refreshAction, postAction]
@@ -87,12 +104,12 @@
87 id: pageStack104 id: pageStack
88105
89 Component.onCompleted: {106 Component.onCompleted: {
90 console.log ("accounts.count: "+accounts.count);107 console.log ("accounts.count: "+accounts.count)
91 pageStack.push(mainPage);108
92 if (accounts.count < 1)109 if (accounts.count < 1)
93 pageStack.push(noAccountsPage);110 pageStack.push(noAccountsPage)
94111 else
95 loaded = true112 pageStack.push(feedTabs)
96 }113 }
97114
98 Page {115 Page {
@@ -126,47 +143,16 @@
126 }143 }
127 }144 }
128145
129 Page {146 FeedTabs {
130 id: mainPage
131 visible: false147 visible: false
132148 id: feedTabs
133 Tabs {149 }
134 id: feedTabs150
135151 // Pages cannot be nested so we have to work around this restriction
136 Feed {152 // See this bug for some infos: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1256420
137 id: timeline153 ConversationPage {
138 title: i18n.tr("Timeline")154 visible: false
139155 id: conversationPage
140 stream: "" //all
141 }
142
143 Feed {
144 id: mentions
145 title: i18n.tr("Mentions")
146
147 stream: "mentions"
148 }
149
150 /* The stream filter doesn't seem to work yet
151 TimeLine {
152 id: privateMessages
153 title: i18n.tr("Private")
154
155 stream: "private"
156 }*/
157 }
158
159 tools: ToolbarItems {
160 ToolbarButton {
161 action: topAction
162 }
163 ToolbarButton {
164 action: refreshAction
165 }
166 ToolbarButton {
167 action: postAction
168 }
169 }
170 }156 }
171 }157 }
172}158}
173159
=== modified file 'qml/qml.pro'
--- qml/qml.pro 2013-03-30 18:20:11 +0000
+++ qml/qml.pro 2014-01-23 12:09:15 +0000
@@ -13,5 +13,4 @@
13INSTALLS = install_resources13INSTALLS = install_resources
1414
15OTHER_FILES += \15OTHER_FILES += \
16 ThreadView.qml \16 FeedTabs.qml
17 RefreshBar.qml

Subscribers

People subscribed via source and target branches

to all changes: