Merge lp:~phablet-team/messaging-app/rtm-fit-finish into lp:messaging-app
- rtm-fit-finish
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Gustavo Pichorim Boiko |
Approved revision: | 218 |
Merged at revision: | 176 |
Proposed branch: | lp:~phablet-team/messaging-app/rtm-fit-finish |
Merge into: | lp:messaging-app |
Diff against target: |
3252 lines (+1303/-1212) 26 files modified
debian/control (+1/-0) debian/rules (+1/-1) src/qml/CMakeLists.txt (+2/-1) src/qml/KeyboardRectangle.qml (+0/-4) src/qml/LocalPageWithBottomEdge.qml (+406/-0) src/qml/MMS/CMakeLists.txt (+4/-0) src/qml/MMS/MMSBase.qml (+97/-0) src/qml/MMS/MMSContact.qml (+25/-28) src/qml/MMS/MMSDefault.qml (+8/-9) src/qml/MMS/MMSImage.qml (+34/-53) src/qml/MMS/MMSVideo.qml (+8/-9) src/qml/MMS/PreviewerContact.qml (+27/-0) src/qml/MainPage.qml (+74/-90) src/qml/MessageBubble.qml (+94/-3) src/qml/MessageDelegate.qml (+157/-291) src/qml/Messages.qml (+217/-241) src/qml/MultiRecipientInput.qml (+2/-2) src/qml/NewRecipientPage.qml (+44/-20) src/qml/PageWithBottomEdge.qml (+0/-367) src/qml/ThreadDelegate.qml (+43/-65) src/qml/assets/conversation_error@27.sci (+5/-0) src/qml/assets/conversation_pending@27.sci (+5/-0) src/qml/messaging-app.qml (+6/-3) tests/autopilot/messaging_app/emulators.py (+38/-21) tests/autopilot/messaging_app/tests/test_messaging.py (+5/-1) tests/qml/tst_MessageBubble.qml (+0/-3) |
To merge this branch: | bzr merge lp:~phablet-team/messaging-app/rtm-fit-finish |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gustavo Pichorim Boiko (community) | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Review via email: mp+228532@code.launchpad.net |
Commit message
- Visual update
- Added qtdeclarative5-
- Created a new MMS source dir with files necessary for MMS visual.
Description of the change
- 172. By Tiago Salem Herrmann
-
multiple fixes
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:172
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 173. By Tiago Salem Herrmann
-
use ListItemWithActions also for mms's
- 174. By Tiago Salem Herrmann
-
add transitions back and set image loading to be synchronous, as it breaks the transitions
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:173
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:174
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 175. By Renato Araujo Oliveira Filho
-
Implemente MessageBubble new visuals.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:175
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 176. By Renato Araujo Oliveira Filho
-
Fixed MessageBubble visuals.
- 177. By Renato Araujo Oliveira Filho
-
Fixed visuals for MMS pictures.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:176
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:177
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 178. By Renato Araujo Oliveira Filho
-
Margin fix.
- 179. By Renato Araujo Oliveira Filho
-
Fixed MessageBubble minimum size.
- 180. By Renato Araujo Oliveira Filho
-
Fixed item selection.
- 181. By Tiago Salem Herrmann
-
add unread count indicator
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:181
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 182. By Tiago Salem Herrmann
-
use a different delegate for mms text attachments
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:182
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:183
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:184
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 183. By Renato Araujo Oliveira Filho
-
Revert last commit.
- 184. By Renato Araujo Oliveira Filho
-
Morre fixes.
- 185. By Renato Araujo Oliveira Filho
-
Parent branch merged.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:185
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 186. By Renato Araujo Oliveira Filho
-
Initial message section implementation.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:186
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 187. By Renato Araujo Oliveira Filho
-
Remove dual sim section.
- 188. By Renato Araujo Oliveira Filho
-
Removed references to old section.
- 189. By Renato Araujo Oliveira Filho
-
Implemented dual sim switch.
- 190. By Renato Araujo Oliveira Filho
-
Parent merged.
- 191. By Renato Araujo Oliveira Filho
-
Allows only one item to be swipped.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:187
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:192
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 192. By Renato Araujo Oliveira Filho
-
Fixed typo.
- 193. By Renato Araujo Oliveira Filho
-
Added retry button for failed messages.
- 194. By Renato Araujo Oliveira Filho
-
Fixed application installation.
- 195. By Renato Araujo Oliveira Filho
-
Trunk merged.
- 196. By Tiago Salem Herrmann
-
fix contact delegate and add simple previewer
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:196
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 197. By Tiago Salem Herrmann
-
add PageWithBottomEdge again
Francis Ginther (fginther) wrote : | # |
Build 333 failed due to a job update that didn't go as planned. A rebuild has been triggered.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:197
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 198. By Renato Araujo Oliveira Filho
-
Fixed Header sections for single simcard.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:197
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:198
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 199. By Tiago Salem Herrmann
-
fix message status indicator and attachment removal
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:199
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 200. By Renato Araujo Oliveira Filho
-
Trunk merged.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:200
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:201
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 201. By Renato Araujo Oliveira Filho
-
Fix account switch.
- 202. By Renato Araujo Oliveira Filho
-
Does not hid keyborad if list is flickering.
- 203. By Renato Araujo Oliveira Filho
-
Parent merged.
- 204. By Renato Araujo Oliveira Filho
-
Make unit test quicker.
- 205. By Renato Araujo Oliveira Filho
-
Run verbose tests.
- 206. By Renato Araujo Oliveira Filho
-
Added qtdeclarative5-
ubuntu- history0. 1 as a build dependency. - 207. By Renato Araujo Oliveira Filho
-
Parent merged.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:204
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 208. By Renato Araujo Oliveira Filho
-
Revert removal of KeryboardRectangle.
- 209. By Renato Araujo Oliveira Filho
-
Parent merged.
- 210. By Renato Araujo Oliveira Filho
-
Fixed Messaging margins.
- 211. By Renato Araujo Oliveira Filho
-
Parent merged.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:207
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 212. By Tiago Salem Herrmann
-
fix send button color
clip contact list loader
increase text filed size to avoid text being cut off - 213. By Tiago Salem Herrmann
-
dont dismiss keyboard when selecting recipients
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:212
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:213
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 214. By Tiago Salem Herrmann
-
fix autopilot tests
- 215. By Tiago Salem Herrmann
-
more autopilot fixes
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:215
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 216. By Tiago Salem Herrmann
-
implement onAddDetailClicked signal
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:216
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 217. By Gustavo Pichorim Boiko
-
Wait until the OSD is gone before clicking the notification.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:217
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 218. By Gustavo Pichorim Boiko
-
Fix autopilot tests.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:218
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Renato Araujo Oliveira Filho (renatofilho) wrote : | # |
Are there any related MPs required for this MP to build/function as expected? YES
- https:/
Is your branch in sync with latest trunk? YES
Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator? YES
Did you successfully run all tests found in your component's Test Plan on device or emulator? YES
If you changed the UI, was the change specified/approved by design? YES
If you changed the packaging (debian), did you add a core-dev as a reviewer to this MP? NO PACKAGE CHANGE
Gustavo Pichorim Boiko (boiko) wrote : | # |
Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator?
Yes
Did CI run pass? If not, please explain why.
No, but it is because it needs the dependent MR to work.
Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?
Yes
- 219. By Renato Araujo Oliveira Filho
-
Fixed indentation
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2014-07-25 02:48:01 +0000 |
3 | +++ debian/control 2014-08-05 11:46:55 +0000 |
4 | @@ -14,6 +14,7 @@ |
5 | qtdeclarative5-dev (>= 5.0), |
6 | qtdeclarative5-dev-tools, |
7 | qtdeclarative5-ubuntu-ui-toolkit-plugin, |
8 | + qtdeclarative5-ubuntu-history0.1, |
9 | qtpim5-dev, |
10 | xvfb, |
11 | Standards-Version: 3.9.4 |
12 | |
13 | === modified file 'debian/rules' |
14 | --- debian/rules 2014-03-25 01:56:39 +0000 |
15 | +++ debian/rules 2014-08-05 11:46:55 +0000 |
16 | @@ -14,7 +14,7 @@ |
17 | |
18 | override_dh_auto_test: |
19 | flake8 tests/autopilot/messaging_app/ |
20 | - make -C obj-$(DEB_HOST_GNU_TYPE) test |
21 | + cd obj-$(DEB_HOST_GNU_TYPE); ctest -V |
22 | |
23 | override_dh_translations: |
24 | # Override dh_translations to work around http://pad.lv/1183262. |
25 | |
26 | === modified file 'src/qml/CMakeLists.txt' |
27 | --- src/qml/CMakeLists.txt 2014-07-22 18:42:03 +0000 |
28 | +++ src/qml/CMakeLists.txt 2014-08-05 11:46:55 +0000 |
29 | @@ -12,6 +12,7 @@ |
30 | set(3RD_PARTY_DIR 3rd_party) |
31 | |
32 | install(FILES ${QML_JS_FILES} DESTINATION ${MESSAGING_APP_DIR}) |
33 | -install(DIRECTORY ${QML_DIRS} DESTINATION ${MESSAGING_APP_DIR}) |
34 | install(DIRECTORY ${ASSETS_DIR} DESTINATION ${MESSAGING_APP_DIR}) |
35 | install(DIRECTORY ${3RD_PARTY_DIR} DESTINATION ${MESSAGING_APP_DIR}) |
36 | + |
37 | +add_subdirectory(MMS) |
38 | |
39 | === modified file 'src/qml/KeyboardRectangle.qml' |
40 | --- src/qml/KeyboardRectangle.qml 2013-07-17 21:47:45 +0000 |
41 | +++ src/qml/KeyboardRectangle.qml 2014-08-05 11:46:55 +0000 |
42 | @@ -25,10 +25,6 @@ |
43 | anchors.bottom: parent.bottom |
44 | height: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0 |
45 | |
46 | - Behavior on height { |
47 | - StandardAnimation { } |
48 | - } |
49 | - |
50 | function recursiveFindFocusedItem(parent) { |
51 | if (parent.activeFocus) { |
52 | return parent; |
53 | |
54 | === added file 'src/qml/LocalPageWithBottomEdge.qml' |
55 | --- src/qml/LocalPageWithBottomEdge.qml 1970-01-01 00:00:00 +0000 |
56 | +++ src/qml/LocalPageWithBottomEdge.qml 2014-08-05 11:46:55 +0000 |
57 | @@ -0,0 +1,406 @@ |
58 | +/* |
59 | + * Copyright (C) 2014 Canonical, Ltd. |
60 | + * |
61 | + * This program is free software; you can redistribute it and/or modify |
62 | + * it under the terms of the GNU General Public License as published by |
63 | + * the Free Software Foundation; version 3. |
64 | + * |
65 | + * This program is distributed in the hope that it will be useful, |
66 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
67 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
68 | + * GNU General Public License for more details. |
69 | + * |
70 | + * You should have received a copy of the GNU General Public License |
71 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
72 | + */ |
73 | + |
74 | +/* |
75 | + Example: |
76 | + |
77 | + MainView { |
78 | + objectName: "mainView" |
79 | + |
80 | + applicationName: "com.ubuntu.developer.boiko.bottomedge" |
81 | + |
82 | + width: units.gu(100) |
83 | + height: units.gu(75) |
84 | + |
85 | + Component { |
86 | + id: pageComponent |
87 | + |
88 | + PageWithBottomEdge { |
89 | + id: mainPage |
90 | + title: i18n.tr("Main Page") |
91 | + |
92 | + Rectangle { |
93 | + anchors.fill: parent |
94 | + color: "white" |
95 | + } |
96 | + |
97 | + bottomEdgePageComponent: Page { |
98 | + title: "Contents" |
99 | + anchors.fill: parent |
100 | + //anchors.topMargin: contentsPage.flickable.contentY |
101 | + |
102 | + ListView { |
103 | + anchors.fill: parent |
104 | + model: 50 |
105 | + delegate: ListItems.Standard { |
106 | + text: "One Content Item: " + index |
107 | + } |
108 | + } |
109 | + } |
110 | + bottomEdgeTitle: i18n.tr("Bottom edge action") |
111 | + } |
112 | + } |
113 | + |
114 | + PageStack { |
115 | + id: stack |
116 | + Component.onCompleted: stack.push(pageComponent) |
117 | + } |
118 | + } |
119 | + |
120 | +*/ |
121 | + |
122 | +import QtQuick 2.2 |
123 | +import Ubuntu.Components 1.1 |
124 | + |
125 | +Page { |
126 | + id: page |
127 | + |
128 | + property alias bottomEdgePageComponent: edgeLoader.sourceComponent |
129 | + property alias bottomEdgePageSource: edgeLoader.source |
130 | + property alias bottomEdgeTitle: tipLabel.text |
131 | + property alias bottomEdgeEnabled: bottomEdge.visible |
132 | + property int bottomEdgeExpandThreshold: page.height * 0.2 |
133 | + property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded |
134 | + property bool reloadBottomEdgePage: true |
135 | + |
136 | + readonly property alias bottomEdgePage: edgeLoader.item |
137 | + readonly property bool isReady: (bottomEdge.y === 0) |
138 | + readonly property bool isCollapsed: (bottomEdge.y === page.height) |
139 | + readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready) |
140 | + property var temporaryProperties: null |
141 | + |
142 | + property bool _showEdgePageWhenReady: false |
143 | + property int _areaWhenExpanded: 0 |
144 | + |
145 | + signal bottomEdgeReleased() |
146 | + signal bottomEdgeDismissed() |
147 | + |
148 | + |
149 | + function showBottomEdgePage(source, properties) |
150 | + { |
151 | + edgeLoader.setSource(source, properties) |
152 | + temporaryProperties = properties |
153 | + _showEdgePageWhenReady = true |
154 | + } |
155 | + |
156 | + function setBottomEdgePage(source, properties) |
157 | + { |
158 | + edgeLoader.setSource(source, properties) |
159 | + } |
160 | + |
161 | + function _pushPage() |
162 | + { |
163 | + if (edgeLoader.status === Loader.Ready) { |
164 | + edgeLoader.item.active = true |
165 | + page.pageStack.push(edgeLoader.item) |
166 | + if (edgeLoader.item.flickable) { |
167 | + edgeLoader.item.flickable.contentY = -page.header.height |
168 | + edgeLoader.item.flickable.returnToBounds() |
169 | + } |
170 | + if (edgeLoader.item.ready) |
171 | + edgeLoader.item.ready() |
172 | + } |
173 | + } |
174 | + |
175 | + |
176 | + Component.onCompleted: { |
177 | + // avoid a binding on the expanded height value |
178 | + var expandedHeight = height; |
179 | + _areaWhenExpanded = expandedHeight; |
180 | + } |
181 | + |
182 | + onActiveChanged: { |
183 | + if (active) { |
184 | + bottomEdge.state = "collapsed" |
185 | + } |
186 | + } |
187 | + |
188 | + onBottomEdgePageLoadedChanged: { |
189 | + if (_showEdgePageWhenReady && bottomEdgePageLoaded) { |
190 | + bottomEdge.state = "expanded" |
191 | + _showEdgePageWhenReady = false |
192 | + } |
193 | + } |
194 | + |
195 | + Rectangle { |
196 | + id: bgVisual |
197 | + |
198 | + color: "black" |
199 | + anchors.fill: page |
200 | + opacity: 0.7 * ((page.height - bottomEdge.y) / page.height) |
201 | + z: 1 |
202 | + } |
203 | + |
204 | + Timer { |
205 | + id: hideIndicator |
206 | + |
207 | + interval: 3000 |
208 | + running: true |
209 | + repeat: false |
210 | + onTriggered: tip.hiden = true |
211 | + } |
212 | + |
213 | + Rectangle { |
214 | + id: bottomEdge |
215 | + objectName: "bottomEdge" |
216 | + |
217 | + readonly property int tipHeight: units.gu(3) |
218 | + readonly property int pageStartY: 0 |
219 | + |
220 | + z: 1 |
221 | + color: Theme.palette.normal.background |
222 | + parent: page |
223 | + anchors { |
224 | + left: parent.left |
225 | + right: parent.right |
226 | + } |
227 | + height: page.height |
228 | + y: height |
229 | + |
230 | + UbuntuShape { |
231 | + id: tip |
232 | + objectName: "bottomEdgeTip" |
233 | + |
234 | + property bool hiden: false |
235 | + |
236 | + readonly property double visiblePosition: (page.height - bottomEdge.y) < units.gu(1) ? -bottomEdge.tipHeight + (page.height - bottomEdge.y) : 0 |
237 | + readonly property double invisiblePosition: (page.height - bottomEdge.y) < units.gu(1) ? -units.gu(1) : 0 |
238 | + |
239 | + z: -1 |
240 | + anchors.horizontalCenter: parent.horizontalCenter |
241 | + y: hiden ? invisiblePosition : visiblePosition |
242 | + |
243 | + width: tipLabel.paintedWidth + units.gu(6) |
244 | + height: bottomEdge.tipHeight + units.gu(1) |
245 | + color: Theme.palette.normal.overlay |
246 | + Label { |
247 | + id: tipLabel |
248 | + |
249 | + anchors { |
250 | + top: parent.top |
251 | + left: parent.left |
252 | + right: parent.right |
253 | + } |
254 | + height: bottomEdge.tipHeight |
255 | + verticalAlignment: Text.AlignVCenter |
256 | + horizontalAlignment: Text.AlignHCenter |
257 | + opacity: tip.hiden ? 0.0 : 1.0 |
258 | + Behavior on opacity { |
259 | + UbuntuNumberAnimation { |
260 | + duration: UbuntuAnimation.SnapDuration |
261 | + } |
262 | + } |
263 | + } |
264 | + Behavior on y { |
265 | + UbuntuNumberAnimation { |
266 | + duration: UbuntuAnimation.SnapDuration |
267 | + } |
268 | + } |
269 | + } |
270 | + |
271 | + Rectangle { |
272 | + id: shadow |
273 | + |
274 | + anchors { |
275 | + left: parent.left |
276 | + right: parent.right |
277 | + } |
278 | + height: units.gu(1) |
279 | + y: -height |
280 | + z: -2 |
281 | + opacity: 0.0 |
282 | + gradient: Gradient { |
283 | + GradientStop { position: 0.0; color: "transparent" } |
284 | + GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) } |
285 | + } |
286 | + } |
287 | + |
288 | + MouseArea { |
289 | + id: mouseArea |
290 | + |
291 | + preventStealing: true |
292 | + drag { |
293 | + axis: Drag.YAxis |
294 | + target: bottomEdge |
295 | + minimumY: bottomEdge.pageStartY |
296 | + maximumY: page.height |
297 | + threshold: 100 |
298 | + } |
299 | + |
300 | + anchors { |
301 | + left: parent.left |
302 | + right: parent.right |
303 | + } |
304 | + height: bottomEdge.tipHeight |
305 | + y: -height |
306 | + |
307 | + onReleased: { |
308 | + page.bottomEdgeReleased() |
309 | + if (bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) { |
310 | + bottomEdge.state = "expanded" |
311 | + } else { |
312 | + bottomEdge.state = "collapsed" |
313 | + bottomEdge.y = bottomEdge.height |
314 | + } |
315 | + } |
316 | + |
317 | + onClicked: { |
318 | + tip.hiden = false |
319 | + hideIndicator.restart() |
320 | + } |
321 | + } |
322 | + |
323 | + state: "collapsed" |
324 | + onStateChanged: console.debug("State Changed:" + state) |
325 | + states: [ |
326 | + State { |
327 | + name: "collapsed" |
328 | + PropertyChanges { |
329 | + target: bottomEdge |
330 | + y: bottomEdge.height |
331 | + } |
332 | + PropertyChanges { |
333 | + target: tip |
334 | + opacity: 1.0 |
335 | + } |
336 | + PropertyChanges { |
337 | + target: hideIndicator |
338 | + running: true |
339 | + } |
340 | + }, |
341 | + State { |
342 | + name: "expanded" |
343 | + PropertyChanges { |
344 | + target: bottomEdge |
345 | + y: bottomEdge.pageStartY |
346 | + } |
347 | + PropertyChanges { |
348 | + target: hideIndicator |
349 | + running: false |
350 | + } |
351 | + }, |
352 | + State { |
353 | + name: "floating" |
354 | + when: mouseArea.drag.active |
355 | + PropertyChanges { |
356 | + target: shadow |
357 | + opacity: 1.0 |
358 | + } |
359 | + PropertyChanges { |
360 | + target: hideIndicator |
361 | + running: false |
362 | + } |
363 | + PropertyChanges { |
364 | + target: tip |
365 | + hiden: false |
366 | + } |
367 | + } |
368 | + ] |
369 | + |
370 | + transitions: [ |
371 | + Transition { |
372 | + to: "expanded" |
373 | + SequentialAnimation { |
374 | + UbuntuNumberAnimation { |
375 | + target: bottomEdge |
376 | + property: "y" |
377 | + duration: UbuntuAnimation.SlowDuration |
378 | + } |
379 | + ScriptAction { |
380 | + script: page._pushPage() |
381 | + } |
382 | + } |
383 | + }, |
384 | + Transition { |
385 | + from: "expanded" |
386 | + to: "collapsed" |
387 | + SequentialAnimation { |
388 | + ScriptAction { |
389 | + script: { |
390 | + Qt.inputMethod.hide() |
391 | + edgeLoader.item.parent = edgeLoader |
392 | + edgeLoader.item.anchors.fill = edgeLoader |
393 | + edgeLoader.item.active = false |
394 | + } |
395 | + } |
396 | + UbuntuNumberAnimation { |
397 | + target: bottomEdge |
398 | + property: "y" |
399 | + duration: UbuntuAnimation.SlowDuration |
400 | + } |
401 | + ScriptAction { |
402 | + script: { |
403 | + // destroy current bottom page |
404 | + if (page.reloadBottomEdgePage) { |
405 | + edgeLoader.active = false |
406 | + // remove properties from old instance |
407 | + if (edgeLoader.source !== "") { |
408 | + var properties = {} |
409 | + if (temporaryProperties !== null) { |
410 | + properties = temporaryProperties |
411 | + temporaryProperties = null |
412 | + } |
413 | + |
414 | + edgeLoader.setSource(edgeLoader.source, properties) |
415 | + } |
416 | + } |
417 | + |
418 | + // notify |
419 | + page.bottomEdgeDismissed() |
420 | + |
421 | + // load a new bottom page in memory |
422 | + edgeLoader.active = true |
423 | + |
424 | + tip.hiden = false |
425 | + hideIndicator.restart() |
426 | + } |
427 | + } |
428 | + } |
429 | + }, |
430 | + Transition { |
431 | + from: "floating" |
432 | + to: "collapsed" |
433 | + UbuntuNumberAnimation { |
434 | + target: bottomEdge |
435 | + property: "opacity" |
436 | + } |
437 | + } |
438 | + ] |
439 | + |
440 | + Loader { |
441 | + id: edgeLoader |
442 | + |
443 | + z: 1 |
444 | + active: true |
445 | + asynchronous: true |
446 | + anchors.fill: parent |
447 | + |
448 | + //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging |
449 | + Binding { |
450 | + target: edgeLoader |
451 | + property: "anchors.topMargin" |
452 | + value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0 |
453 | + when: (edgeLoader.status === Loader.Ready && !page.isReady) |
454 | + } |
455 | + |
456 | + onLoaded: { |
457 | + if (page.isReady && edgeLoader.item.active != true) { |
458 | + page._pushPage() |
459 | + } |
460 | + } |
461 | + } |
462 | + } |
463 | +} |
464 | |
465 | === added file 'src/qml/MMS/CMakeLists.txt' |
466 | --- src/qml/MMS/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
467 | +++ src/qml/MMS/CMakeLists.txt 2014-08-05 11:46:55 +0000 |
468 | @@ -0,0 +1,4 @@ |
469 | +file(GLOB MMS_QML_JS_FILES *.qml *.js) |
470 | + |
471 | +add_custom_target(messaging_app_MMS_QMlFiles ALL SOURCES ${MMS_QML_JS_FILES}) |
472 | +install(FILES ${MMS_QML_JS_FILES} DESTINATION ${MESSAGING_APP_DIR}/MMS) |
473 | |
474 | === added file 'src/qml/MMS/MMSBase.qml' |
475 | --- src/qml/MMS/MMSBase.qml 1970-01-01 00:00:00 +0000 |
476 | +++ src/qml/MMS/MMSBase.qml 2014-08-05 11:46:55 +0000 |
477 | @@ -0,0 +1,97 @@ |
478 | +/* |
479 | + * Copyright 2012, 2013, 2014 Canonical Ltd. |
480 | + * |
481 | + * This file is part of messaging-app. |
482 | + * |
483 | + * messaging-app is free software; you can redistribute it and/or modify |
484 | + * it under the terms of the GNU General Public License as published by |
485 | + * the Free Software Foundation; version 3. |
486 | + * |
487 | + * messaging-app is distributed in the hope that it will be useful, |
488 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
489 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
490 | + * GNU General Public License for more details. |
491 | + * |
492 | + * You should have received a copy of the GNU General Public License |
493 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
494 | + */ |
495 | +import QtQuick 2.2 |
496 | +import Ubuntu.Components 1.1 |
497 | +import Ubuntu.Contacts 0.1 |
498 | + |
499 | +ListItemWithActions { |
500 | + id: baseDelegate |
501 | + |
502 | + property var attachment |
503 | + property bool parentSelected: false |
504 | + property bool incoming |
505 | + property bool showInfo: false |
506 | + |
507 | + signal itemRemoved() |
508 | + signal attachmentClicked() |
509 | + |
510 | + function checkClick(bubble, mouse) { |
511 | + var itemX1 = bubble.x |
512 | + var itemX2 = itemX1+bubble.width |
513 | + var itemY1 = bubble.y |
514 | + var itemY2 = itemY1+bubble.height |
515 | + if (mouse.x >= itemX1 && mouse.x <= itemX2 && |
516 | + mouse.y >= itemY1 && mouse.y <= itemY2) { |
517 | + return true |
518 | + } |
519 | + return false |
520 | + } |
521 | + |
522 | + Component.onCompleted: { |
523 | + visibleAttachments++ |
524 | + } |
525 | + Component.onDestruction: { |
526 | + visibleAttachments-- |
527 | + } |
528 | + |
529 | + leftSideAction: Action { |
530 | + iconName: "delete" |
531 | + text: i18n.tr("Delete") |
532 | + onTriggered: baseDelegate.itemRemoved() |
533 | + } |
534 | + |
535 | + internalAnchors { |
536 | + topMargin: 0 |
537 | + bottomMargin: 0 |
538 | + } |
539 | + |
540 | + color: parentSelected ? selectedColor : Theme.palette.normal.background |
541 | + states: [ |
542 | + State { |
543 | + when: incoming |
544 | + name: "incoming" |
545 | + AnchorChanges { |
546 | + target: bubble |
547 | + anchors.left: parent.left |
548 | + anchors.right: undefined |
549 | + } |
550 | + PropertyChanges { |
551 | + target: bubble |
552 | + anchors.leftMargin: units.gu(1) |
553 | + anchors.rightMargin: 0 |
554 | + } |
555 | + }, |
556 | + State { |
557 | + when: !incoming |
558 | + name: "outgoing" |
559 | + AnchorChanges { |
560 | + target: bubble |
561 | + anchors.left: undefined |
562 | + anchors.right: parent.right |
563 | + } |
564 | + PropertyChanges { |
565 | + target: bubble |
566 | + anchors.leftMargin: 0 |
567 | + anchors.rightMargin: units.gu(1) |
568 | + } |
569 | + } |
570 | + ] |
571 | + |
572 | + onSwippingChanged: messageList.updateSwippedItem(baseDelegate) |
573 | + onSwipeStateChanged: messageList.updateSwippedItem(baseDelegate) |
574 | +} |
575 | |
576 | === modified file 'src/qml/MMS/MMSContact.qml' |
577 | --- src/qml/MMS/MMSContact.qml 2014-07-01 18:10:31 +0000 |
578 | +++ src/qml/MMS/MMSContact.qml 2014-08-05 11:46:55 +0000 |
579 | @@ -17,19 +17,18 @@ |
580 | */ |
581 | |
582 | import QtQuick 2.0 |
583 | -import Ubuntu.Components.ListItems 0.1 as ListItem |
584 | import Ubuntu.Components 0.1 |
585 | +import Ubuntu.Contacts 0.1 |
586 | import ".." |
587 | |
588 | -ListItem.Empty { |
589 | +MMSBase { |
590 | id: vcardDelegate |
591 | - property var attachment |
592 | - property bool incoming |
593 | - property string previewer: "" |
594 | - property string textColor: incoming ? "#333333" : "#ffffff" |
595 | - anchors.left: parent.left |
596 | - anchors.right: parent.right |
597 | - state: incoming ? "incoming" : "outgoing" |
598 | + property string previewer: "MMS/PreviewerContact.qml" |
599 | + onItemClicked: { |
600 | + if (checkClick(bubble, mouse)) { |
601 | + attachmentClicked() |
602 | + } |
603 | + } |
604 | states: [ |
605 | State { |
606 | name: "incoming" |
607 | @@ -50,8 +49,8 @@ |
608 | } |
609 | PropertyChanges { |
610 | target: contactName |
611 | - anchors.leftMargin: units.gu(1) |
612 | - anchors.rightMargin: units.gu(1) |
613 | + anchors.leftMargin: units.gu(2) |
614 | + anchors.rightMargin: units.gu(2) |
615 | } |
616 | }, |
617 | State { |
618 | @@ -73,37 +72,35 @@ |
619 | } |
620 | PropertyChanges { |
621 | target: contactName |
622 | - anchors.leftMargin: units.gu(1) |
623 | - anchors.rightMargin: units.gu(1) |
624 | + anchors.leftMargin: units.gu(2) |
625 | + anchors.rightMargin: units.gu(2) |
626 | } |
627 | } |
628 | ] |
629 | - removable: true |
630 | - confirmRemoval: true |
631 | - height: bubble.height |
632 | - clip: true |
633 | - showDivider: false |
634 | - highlightWhenPressed: false |
635 | - MessageBubble { |
636 | + height: bubble.height + units.gu(2) |
637 | + Item { |
638 | id: bubble |
639 | - incoming: vcardDelegate.incoming |
640 | anchors.top: parent.top |
641 | - width: image.width + units.gu(4) |
642 | - height: image.height + units.gu(2) |
643 | + width: avatar.width |
644 | + height: avatar.height |
645 | + ContactAvatar { |
646 | + id: avatar |
647 | |
648 | - Icon { |
649 | - id: image |
650 | + fallbackAvatarUrl: "image://theme/contact" |
651 | + fallbackDisplayName: contactName.name |
652 | + anchors.centerIn: parent |
653 | height: units.gu(6) |
654 | width: units.gu(6) |
655 | - name: "contact" |
656 | - anchors.centerIn: parent |
657 | - anchors.horizontalCenterOffset: incoming ? units.gu(0.5) : -units.gu(0.5) |
658 | } |
659 | } |
660 | Label { |
661 | id: contactName |
662 | property string name: application.contactNameFromVCard(attachment.filePath) |
663 | anchors.bottom: bubble.bottom |
664 | + anchors.left: incoming ? bubble.right : undefined |
665 | + anchors.right: !incoming ? bubble.left : undefined |
666 | + anchors.rightMargin: !incoming ? units.gu(1) : undefined |
667 | + anchors.leftMargin: incoming ? units.gu(1) : undefined |
668 | text: name !== "" ? name : i18n.tr("Unknown contact") |
669 | height: paintedHeight |
670 | width: paintedWidth |
671 | |
672 | === modified file 'src/qml/MMS/MMSDefault.qml' |
673 | --- src/qml/MMS/MMSDefault.qml 2014-05-05 16:56:56 +0000 |
674 | +++ src/qml/MMS/MMSDefault.qml 2014-08-05 11:46:55 +0000 |
675 | @@ -17,11 +17,10 @@ |
676 | */ |
677 | |
678 | import QtQuick 2.0 |
679 | -import Ubuntu.Components.ListItems 0.1 as ListItem |
680 | import Ubuntu.Components 0.1 |
681 | import ".." |
682 | |
683 | -ListItem.Empty { |
684 | +MMSBase { |
685 | id: defaultDelegate |
686 | property var attachment |
687 | property bool incoming |
688 | @@ -29,6 +28,11 @@ |
689 | property string textColor: incoming ? "#333333" : "#ffffff" |
690 | anchors.left: parent.left |
691 | anchors.right: parent.right |
692 | + onItemClicked: { |
693 | + if (checkClick(bubble, mouse)) { |
694 | + attachmentClicked() |
695 | + } |
696 | + } |
697 | state: incoming ? "incoming" : "outgoing" |
698 | states: [ |
699 | State { |
700 | @@ -58,15 +62,10 @@ |
701 | } |
702 | } |
703 | ] |
704 | - removable: true |
705 | - confirmRemoval: true |
706 | - height: bubble.height |
707 | + height: bubble.height + units.gu(1) |
708 | clip: true |
709 | - showDivider: false |
710 | - highlightWhenPressed: false |
711 | - MessageBubble { |
712 | + Item { |
713 | id: bubble |
714 | - incoming: defaultDelegate.incoming |
715 | anchors.top: parent.top |
716 | width: label.width + units.gu(4) |
717 | height: label.height + units.gu(2) |
718 | |
719 | === modified file 'src/qml/MMS/MMSImage.qml' |
720 | --- src/qml/MMS/MMSImage.qml 2014-05-05 16:56:56 +0000 |
721 | +++ src/qml/MMS/MMSImage.qml 2014-08-05 11:46:55 +0000 |
722 | @@ -17,67 +17,48 @@ |
723 | */ |
724 | |
725 | import QtQuick 2.0 |
726 | -import Ubuntu.Components.ListItems 0.1 as ListItem |
727 | +import Ubuntu.Components 1.1 |
728 | +import Ubuntu.Contacts 0.1 |
729 | import ".." |
730 | |
731 | -ListItem.Empty { |
732 | +MMSBase { |
733 | id: imageDelegate |
734 | - property var attachment |
735 | - property bool incoming |
736 | property string previewer: "MMS/PreviewerImage.qml" |
737 | - anchors.left: parent.left |
738 | - anchors.right: parent.right |
739 | - state: incoming ? "incoming" : "outgoing" |
740 | - states: [ |
741 | - State { |
742 | - name: "incoming" |
743 | - AnchorChanges { |
744 | - target: bubble |
745 | - anchors.left: parent.left |
746 | - anchors.right: undefined |
747 | - } |
748 | - PropertyChanges { |
749 | - target: bubble |
750 | - anchors.leftMargin: units.gu(1) |
751 | - anchors.rightMargin: units.gu(1) |
752 | - } |
753 | - }, |
754 | - State { |
755 | - name: "outgoing" |
756 | - AnchorChanges { |
757 | - target: bubble |
758 | - anchors.left: undefined |
759 | - anchors.right: parent.right |
760 | - } |
761 | - PropertyChanges { |
762 | - target: bubble |
763 | - anchors.leftMargin: units.gu(1) |
764 | - anchors.rightMargin: units.gu(1) |
765 | - } |
766 | + onItemClicked: { |
767 | + if (checkClick(bubble, mouse)) { |
768 | + attachmentClicked() |
769 | } |
770 | - ] |
771 | - removable: true |
772 | - confirmRemoval: true |
773 | - height: bubble.height |
774 | - clip: true |
775 | - showDivider: false |
776 | - highlightWhenPressed: false |
777 | - MessageBubble { |
778 | + } |
779 | + |
780 | + height: imageAttachment.height |
781 | + UbuntuShape { |
782 | id: bubble |
783 | - incoming: imageDelegate.incoming |
784 | - anchors.top: parent.top |
785 | - width: image.width + units.gu(3) |
786 | - height: image.height + units.gu(2) |
787 | - |
788 | - Image { |
789 | - id: image |
790 | - anchors.centerIn: parent |
791 | - anchors.horizontalCenterOffset: incoming ? units.gu(0.5) : -units.gu(0.5) |
792 | - height: sourceSize.height < units.gu(20) ? sourceSize.height : units.gu(20) |
793 | - fillMode: Image.PreserveAspectFit |
794 | - asynchronous: true |
795 | + anchors { |
796 | + top: parent.top |
797 | + bottom: parent.bottom |
798 | + } |
799 | + width: image.width |
800 | + height: image.height |
801 | + |
802 | + image: Image { |
803 | + id: imageAttachment |
804 | + |
805 | + width: sourceSize.width > units.gu(30) ? units.gu(30) : sourceSize.width |
806 | + height: Math.min(sourceSize.height, units.gu(14)) |
807 | + fillMode: Image.PreserveAspectCrop |
808 | smooth: true |
809 | source: attachment.filePath |
810 | + visible: false |
811 | } |
812 | } |
813 | + |
814 | + Loader { |
815 | + active: (index == visibleAttachments-1) && !incoming && mmsText == "" && (inProgress || failed) |
816 | + visible: active |
817 | + height: active ? item.height : 0 |
818 | + sourceComponent: statusIcon |
819 | + anchors.right: bubble.left |
820 | + anchors.rightMargin: units.gu(1) |
821 | + anchors.verticalCenter: bubble.verticalCenter |
822 | + } |
823 | } |
824 | |
825 | === modified file 'src/qml/MMS/MMSVideo.qml' |
826 | --- src/qml/MMS/MMSVideo.qml 2014-05-05 16:56:56 +0000 |
827 | +++ src/qml/MMS/MMSVideo.qml 2014-08-05 11:46:55 +0000 |
828 | @@ -17,18 +17,22 @@ |
829 | */ |
830 | |
831 | import QtQuick 2.0 |
832 | -import Ubuntu.Components.ListItems 0.1 as ListItem |
833 | import Ubuntu.Components 0.1 |
834 | import QtMultimedia 5.0 |
835 | import ".." |
836 | |
837 | -ListItem.Empty { |
838 | +MMSBase { |
839 | id: videoDelegate |
840 | property var attachment |
841 | property bool incoming |
842 | property string previewer: "MMS/PreviewerVideo.qml" |
843 | anchors.left: parent.left |
844 | anchors.right: parent.right |
845 | + onItemClicked: { |
846 | + if (checkClick(bubble, mouse)) { |
847 | + attachmentClicked() |
848 | + } |
849 | + } |
850 | state: incoming ? "incoming" : "outgoing" |
851 | states: [ |
852 | State { |
853 | @@ -58,15 +62,10 @@ |
854 | } |
855 | } |
856 | ] |
857 | - removable: true |
858 | - confirmRemoval: true |
859 | - height: bubble.height |
860 | + height: bubble.height + units.gu(1) |
861 | clip: true |
862 | - showDivider: false |
863 | - highlightWhenPressed: false |
864 | - MessageBubble { |
865 | + Item { |
866 | id: bubble |
867 | - incoming: videoDelegate.incoming |
868 | anchors.top: parent.top |
869 | width: videoOutput.width + units.gu(3) |
870 | height: videoOutput.height + units.gu(2) |
871 | |
872 | === added file 'src/qml/MMS/PreviewerContact.qml' |
873 | --- src/qml/MMS/PreviewerContact.qml 1970-01-01 00:00:00 +0000 |
874 | +++ src/qml/MMS/PreviewerContact.qml 2014-08-05 11:46:55 +0000 |
875 | @@ -0,0 +1,27 @@ |
876 | +/* |
877 | + * Copyright 2012, 2013, 2014 Canonical Ltd. |
878 | + * |
879 | + * This file is part of messaging-app. |
880 | + * |
881 | + * messaging-app is free software; you can redistribute it and/or modify |
882 | + * it under the terms of the GNU General Public License as published by |
883 | + * the Free Software Foundation; version 3. |
884 | + * |
885 | + * messaging-app is distributed in the hope that it will be useful, |
886 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
887 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
888 | + * GNU General Public License for more details. |
889 | + * |
890 | + * You should have received a copy of the GNU General Public License |
891 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
892 | + */ |
893 | + |
894 | +import QtQuick 2.0 |
895 | +import Ubuntu.Components 0.1 |
896 | +import Ubuntu.Content 0.1 |
897 | +import ".." |
898 | + |
899 | +Previewer { |
900 | + title: application.contactNameFromVCard(attachment.filePath) |
901 | + clip: true |
902 | +} |
903 | |
904 | === modified file 'src/qml/MainPage.qml' |
905 | --- src/qml/MainPage.qml 2014-07-25 16:20:57 +0000 |
906 | +++ src/qml/MainPage.qml 2014-08-05 11:46:55 +0000 |
907 | @@ -17,43 +17,41 @@ |
908 | */ |
909 | |
910 | import QtQuick 2.0 |
911 | -import Ubuntu.Components 0.1 |
912 | +import Ubuntu.Components 1.1 |
913 | import Ubuntu.Components.ListItems 0.1 as ListItem |
914 | import Ubuntu.History 0.1 |
915 | import Ubuntu.Contacts 0.1 |
916 | import "dateUtils.js" as DateUtils |
917 | |
918 | -PageWithBottomEdge { |
919 | +LocalPageWithBottomEdge { |
920 | id: mainPage |
921 | property alias selectionMode: threadList.isInSelectionMode |
922 | property bool searching: false |
923 | - tools: selectionMode ? selectionToolbar : searching ? searchToolbar : regularToolbar |
924 | - title: selectionMode ? i18n.tr("Edit") : i18n.tr("Chats") |
925 | - __customHeaderContents: mainPage.searching ? searchField : null |
926 | - |
927 | - bottomEdgeEnabled: !selectionMode |
928 | + property alias threadCount: threadList.count |
929 | + |
930 | + function startSelection() { |
931 | + threadList.startSelection() |
932 | + } |
933 | + |
934 | + state: selectionMode ? "select" : searching ? "search" : "default" |
935 | + title: selectionMode ? i18n.tr(" ") : i18n.tr("Chats") |
936 | + |
937 | + bottomEdgeEnabled: !selectionMode && !searching |
938 | bottomEdgePageComponent: Messages { |
939 | active: false |
940 | } |
941 | - |
942 | bottomEdgeTitle: i18n.tr("New Chat") |
943 | - property alias threadCount: threadList.count |
944 | - |
945 | - function startSelection() { |
946 | - threadList.startSelection() |
947 | - } |
948 | |
949 | TextField { |
950 | id: searchField |
951 | visible: mainPage.searching |
952 | anchors { |
953 | left: parent.left |
954 | - topMargin: units.gu(1.5) |
955 | - rightMargin: units.gu(1.5) |
956 | - bottomMargin: units.gu(1.5) |
957 | - verticalCenter: parent.verticalCenter |
958 | + right: parent.right |
959 | + rightMargin: units.gu(2) |
960 | } |
961 | inputMethodHints: Qt.ImhNoPredictiveText |
962 | + placeholderText: i18n.tr("Search...") |
963 | onActiveFocusChanged: { |
964 | if (!activeFocus) { |
965 | searchField.text = "" |
966 | @@ -62,13 +60,25 @@ |
967 | } |
968 | } |
969 | |
970 | - ToolbarItems { |
971 | - id: searchToolbar |
972 | - |
973 | - visible: false |
974 | - back: ToolbarButton { |
975 | - visible: false |
976 | - action: Action { |
977 | + states: [ |
978 | + PageHeadState { |
979 | + name: "default" |
980 | + head: mainPage.head |
981 | + actions: [ |
982 | + Action { |
983 | + objectName: "searchAction" |
984 | + iconName: "search" |
985 | + onTriggered: { |
986 | + mainPage.searching = true |
987 | + searchField.forceActiveFocus() |
988 | + } |
989 | + } |
990 | + ] |
991 | + }, |
992 | + PageHeadState { |
993 | + name: "search" |
994 | + head: mainPage.head |
995 | + backAction: Action { |
996 | objectName: "cancelSearch" |
997 | visible: mainPage.searching |
998 | iconName: "close" |
999 | @@ -78,58 +88,31 @@ |
1000 | mainPage.searching = false |
1001 | } |
1002 | } |
1003 | - } |
1004 | - } |
1005 | - |
1006 | - ToolbarItems { |
1007 | - id: regularToolbar |
1008 | - visible: false |
1009 | - ToolbarButton { |
1010 | - id: searchButton |
1011 | - objectName: "searchButton" |
1012 | - action: Action { |
1013 | - objectName: "searchAction" |
1014 | - iconSource: "image://theme/search" |
1015 | - onTriggered: { |
1016 | - mainPage.searching = true |
1017 | - searchField.forceActiveFocus() |
1018 | - } |
1019 | - } |
1020 | - } |
1021 | - } |
1022 | - |
1023 | - ToolbarItems { |
1024 | - id: selectionToolbar |
1025 | - visible: false |
1026 | - back: ToolbarButton { |
1027 | - id: selectionModeCancelButton |
1028 | - objectName: "selectionModeCancelButton" |
1029 | - action: Action { |
1030 | + contents: searchField |
1031 | + }, |
1032 | + PageHeadState { |
1033 | + name: "select" |
1034 | + head: mainPage.head |
1035 | + backAction: Action { |
1036 | objectName: "selectionModeCancelAction" |
1037 | - iconSource: "image://theme/close" |
1038 | + iconName: "close" |
1039 | onTriggered: threadList.cancelSelection() |
1040 | } |
1041 | - } |
1042 | - ToolbarButton { |
1043 | - id: selectionModeSelectAllButton |
1044 | - objectName: "selectionModeSelectAllButton" |
1045 | - action: Action { |
1046 | - objectName: "selectionModeSelectAllAction" |
1047 | - iconSource: "image://theme/filter" |
1048 | - onTriggered: threadList.selectAll() |
1049 | - } |
1050 | - } |
1051 | - ToolbarButton { |
1052 | - id: selectionModeDeleteButton |
1053 | - objectName: "selectionModeDeleteButton" |
1054 | - action: Action { |
1055 | - objectName: "selectionModeDeleteAction" |
1056 | - enabled: threadList.selectedItems.count > 0 |
1057 | - iconSource: "image://theme/delete" |
1058 | - onTriggered: threadList.endSelection() |
1059 | - } |
1060 | - } |
1061 | - } |
1062 | + actions: [ |
1063 | + Action { |
1064 | + objectName: "selectionModeSelectAllAction" |
1065 | + iconName: "select" |
1066 | + onTriggered: threadList.selectAll() |
1067 | + }, |
1068 | + Action { |
1069 | + objectName: "selectionModeDeleteAction" |
1070 | + enabled: threadList.selectedItems.count > 0 |
1071 | + iconName: "delete" |
1072 | + onTriggered: threadList.endSelection() |
1073 | + } |
1074 | + ] |
1075 | + } |
1076 | + ] |
1077 | |
1078 | HistoryThreadGroupingProxyModel { |
1079 | id: sortProxy |
1080 | @@ -153,24 +136,21 @@ |
1081 | Component { |
1082 | id: sectionDelegate |
1083 | Item { |
1084 | - anchors.left: parent.left |
1085 | - anchors.right: parent.right |
1086 | - height: units.gu(5) |
1087 | + anchors { |
1088 | + left: parent.left |
1089 | + right: parent.right |
1090 | + margins: units.gu(2) |
1091 | + } |
1092 | + height: units.gu(3) |
1093 | Label { |
1094 | - anchors.left: parent.left |
1095 | - anchors.leftMargin: units.gu(2) |
1096 | - anchors.verticalCenter: parent.verticalCenter |
1097 | - fontSize: "medium" |
1098 | + anchors.fill: parent |
1099 | elide: Text.ElideRight |
1100 | - color: "#5d5d5d" |
1101 | text: DateUtils.friendlyDay(Qt.formatDate(section, "yyyy/MM/dd")); |
1102 | verticalAlignment: Text.AlignVCenter |
1103 | + fontSize: "small" |
1104 | } |
1105 | ListItem.ThinDivider { |
1106 | - anchors.leftMargin: units.gu(2) |
1107 | - anchors.rightMargin: units.gu(2) |
1108 | anchors.bottom: parent.bottom |
1109 | - opacity: 0.6 |
1110 | } |
1111 | } |
1112 | } |
1113 | @@ -178,26 +158,30 @@ |
1114 | MultipleSelectionListView { |
1115 | id: threadList |
1116 | objectName: "threadList" |
1117 | + |
1118 | anchors { |
1119 | top: parent.top |
1120 | left: parent.left |
1121 | right: parent.right |
1122 | bottom: keyboard.top |
1123 | } |
1124 | - |
1125 | listModel: sortProxy |
1126 | section.property: "eventDate" |
1127 | - spacing: searchField.text === "" ? units.gu(-2) : 0 |
1128 | + //spacing: searchField.text === "" ? units.gu(-2) : 0 |
1129 | section.delegate: searching && searchField.text !== "" ? null : sectionDelegate |
1130 | listDelegate: ThreadDelegate { |
1131 | id: threadDelegate |
1132 | objectName: "thread%1".arg(participants) |
1133 | + |
1134 | + anchors { |
1135 | + left: parent.left |
1136 | + right: parent.right |
1137 | + } |
1138 | + height: units.gu(8) |
1139 | selectionMode: threadList.isInSelectionMode |
1140 | selected: threadList.isSelected(threadDelegate) |
1141 | - removable: !selectionMode |
1142 | - confirmRemoval: true |
1143 | searchTerm: mainPage.searching ? searchField.text : "" |
1144 | - onClicked: { |
1145 | + onItemClicked: { |
1146 | if (threadList.isInSelectionMode) { |
1147 | if (!threadList.selectItem(threadDelegate)) { |
1148 | threadList.deselectItem(threadDelegate) |
1149 | @@ -210,7 +194,7 @@ |
1150 | mainStack.push(Qt.resolvedUrl("Messages.qml"), properties) |
1151 | } |
1152 | } |
1153 | - onPressAndHold: { |
1154 | + onItemPressAndHold: { |
1155 | threadList.startSelection() |
1156 | threadList.selectItem(threadDelegate) |
1157 | } |
1158 | |
1159 | === modified file 'src/qml/MessageBubble.qml' |
1160 | --- src/qml/MessageBubble.qml 2014-05-05 16:56:56 +0000 |
1161 | +++ src/qml/MessageBubble.qml 2014-08-05 11:46:55 +0000 |
1162 | @@ -16,19 +16,110 @@ |
1163 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1164 | */ |
1165 | |
1166 | -import QtQuick 2.0 |
1167 | +import QtQuick 2.2 |
1168 | +import Ubuntu.Components 1.1 |
1169 | +import Ubuntu.History 0.1 |
1170 | + |
1171 | +import "dateUtils.js" as DateUtils |
1172 | +import "3rd_party/ba-linkify.js" as BaLinkify |
1173 | |
1174 | BorderImage { |
1175 | - property bool incoming |
1176 | + id: root |
1177 | + |
1178 | + property int messageStatus: -1 |
1179 | + property bool incoming: false |
1180 | + property alias sender: senderName.text |
1181 | + property string messageText |
1182 | + property var messageTimeStamp |
1183 | + property int maxDelegateWidth: units.gu(30) |
1184 | + |
1185 | + readonly property bool error: (messageStatus === HistoryThreadModel.MessageStatusPermanentlyFailed) |
1186 | + readonly property bool sending: (messageStatus === HistoryThreadModel.MessageStatusUnknown || |
1187 | + messageStatus === HistoryThreadModel.MessageStatusTemporarilyFailed) && !incoming |
1188 | + |
1189 | function selectBubble() { |
1190 | var fileName = "assets/conversation_"; |
1191 | - if (incoming) { |
1192 | + if (error) { |
1193 | + fileName += "error.sci" |
1194 | + } else if (sending) { |
1195 | + fileName += "pending.sci" |
1196 | + } else if (incoming) { |
1197 | fileName += "incoming.sci"; |
1198 | } else { |
1199 | fileName += "outgoing.sci"; |
1200 | } |
1201 | return fileName; |
1202 | } |
1203 | + |
1204 | + function parseText(text) { |
1205 | + var phoneExp = /(\+?([0-9]+[ ]?)?\(?([0-9]+)\)?[-. ]?([0-9]+)[-. ]?([0-9]+)[-. ]?([0-9]+))/img; |
1206 | + // remove html tags |
1207 | + text = text.replace(/</g,'<').replace(/>/g,'<tt>></tt>'); |
1208 | + // replace line breaks |
1209 | + text = text.replace(/(\n)+/g, '<br />'); |
1210 | + // check for links |
1211 | + text = BaLinkify.linkify(text); |
1212 | + // linkify phone numbers |
1213 | + return text.replace(phoneExp, '<a href="tel:///$1">$1</a>'); |
1214 | + } |
1215 | + |
1216 | onIncomingChanged: source = selectBubble() |
1217 | source: selectBubble() |
1218 | + height: childrenRect.height + units.gu(2) |
1219 | + width: Math.min(units.gu(27), |
1220 | + Math.max(textLabel.text.length, textTimestamp.text.length) * units.gu(1)) |
1221 | + + border.left + border.right |
1222 | + Label { |
1223 | + id: senderName |
1224 | + |
1225 | + anchors { |
1226 | + top: parent.top |
1227 | + topMargin: units.gu(1) |
1228 | + left: parent.left |
1229 | + leftMargin: incoming ? units.gu(2) : units.gu(1) |
1230 | + } |
1231 | + height: text === "" ? 0 : paintedHeight |
1232 | + fontSize: "large" |
1233 | + //color: Ubuntu.Colors. |
1234 | + } |
1235 | + |
1236 | + Label { |
1237 | + id: textLabel |
1238 | + objectName: "messageText" |
1239 | + |
1240 | + anchors { |
1241 | + top: sender == "" ? parent.top : senderName.bottom |
1242 | + topMargin: units.gu(1) |
1243 | + left: parent.left |
1244 | + leftMargin: incoming ? units.gu(2) : units.gu(1) |
1245 | + right: parent.right |
1246 | + rightMargin: incoming ? units.gu(1) : units.gu(1) |
1247 | + } |
1248 | + width: maxDelegateWidth |
1249 | + fontSize: "medium" |
1250 | + height: text === "" ? 0 : paintedHeight |
1251 | + onLinkActivated: Qt.openUrlExternally(link) |
1252 | + text: root.parseText(messageText) |
1253 | + wrapMode: Text.Wrap |
1254 | + color: root.incoming ? UbuntuColors.darkGrey : "white" |
1255 | + } |
1256 | + |
1257 | + Label { |
1258 | + id: textTimestamp |
1259 | + objectName: "messageDate" |
1260 | + |
1261 | + anchors{ |
1262 | + top: textLabel.bottom |
1263 | + topMargin: units.gu(0.5) |
1264 | + left: parent.left |
1265 | + leftMargin: incoming ? units.gu(2) : units.gu(1) |
1266 | + } |
1267 | + |
1268 | + visible: !root.sending |
1269 | + height: visible ? paintedHeight : 0 |
1270 | + fontSize: "xx-small" |
1271 | + color: root.incoming ? UbuntuColors.lightGrey : "white" |
1272 | + opacity: root.incoming ? 1.0 : 0.8 |
1273 | + text: Qt.formatDateTime(messageTimeStamp, "hh:mm AP") |
1274 | + } |
1275 | } |
1276 | |
1277 | === modified file 'src/qml/MessageDelegate.qml' |
1278 | --- src/qml/MessageDelegate.qml 2014-07-22 20:29:11 +0000 |
1279 | +++ src/qml/MessageDelegate.qml 2014-08-05 11:46:55 +0000 |
1280 | @@ -17,68 +17,91 @@ |
1281 | */ |
1282 | |
1283 | import QtQuick 2.0 |
1284 | -import Ubuntu.Components 0.1 |
1285 | -import Ubuntu.Components.ListItems 0.1 as ListItem |
1286 | +import Ubuntu.Components 1.1 |
1287 | import Ubuntu.Components.Popups 0.1 |
1288 | import Ubuntu.History 0.1 |
1289 | import Ubuntu.Telephony 0.1 |
1290 | import Ubuntu.Content 0.1 |
1291 | +import Ubuntu.Contacts 0.1 |
1292 | |
1293 | import "dateUtils.js" as DateUtils |
1294 | -import "3rd_party/ba-linkify.js" as BaLinkify |
1295 | |
1296 | Item { |
1297 | id: messageDelegate |
1298 | - property bool incoming: false |
1299 | + |
1300 | + property alias incoming: bubble.incoming |
1301 | property string textColor: incoming ? "#333333" : "white" |
1302 | - property bool selectionMode: false |
1303 | property bool unread: false |
1304 | - property alias confirmRemoval: internalDelegate.confirmRemoval |
1305 | - property alias removable: internalDelegate.removable |
1306 | - property alias selected: internalDelegate.selected |
1307 | property variant activeAttachment |
1308 | property string mmsText: "" |
1309 | + property string mmsTextId: "" |
1310 | property string accountLabel: "" |
1311 | - |
1312 | - anchors.left: parent ? parent.left : undefined |
1313 | - anchors.right: parent ? parent.right: undefined |
1314 | - height: attachments.height + internalDelegate.height |
1315 | + property bool selectionMode: false |
1316 | + property bool selected: false |
1317 | + property bool inProgress: (textMessageStatus === HistoryThreadModel.MessageStatusUnknown || |
1318 | + textMessageStatus === HistoryThreadModel.MessageStatusTemporarilyFailed) |
1319 | + property bool failed: (textMessageStatus === HistoryThreadModel.MessageStatusPermanentlyFailed) |
1320 | + property int visibleAttachments: 0 |
1321 | |
1322 | signal resend() |
1323 | - signal clicked() |
1324 | - signal triggerSelectionMode() |
1325 | + signal itemPressAndHold(QtObject obj) |
1326 | + signal itemClicked(QtObject obj) |
1327 | + |
1328 | + anchors { |
1329 | + left: parent ? parent.left : undefined |
1330 | + right: parent ? parent.right: undefined |
1331 | + } |
1332 | + height: attachments.height + bubbleItem.height |
1333 | |
1334 | Component { |
1335 | - id: popoverSaveAttachmentComponent |
1336 | - Popover { |
1337 | - id: popover |
1338 | - Column { |
1339 | - id: containerLayout |
1340 | - anchors { |
1341 | - left: parent.left |
1342 | - top: parent.top |
1343 | - right: parent.right |
1344 | - } |
1345 | - ListItem.Standard { |
1346 | - text: i18n.tr("Save") |
1347 | - onClicked: { |
1348 | - mainStack.push(picker, {"url": activeAttachment.filePath, "handler": ContentHandler.Destination}); |
1349 | - PopupUtils.close(popover) |
1350 | - } |
1351 | - } |
1352 | - ListItem.Standard { |
1353 | - text: i18n.tr("Share") |
1354 | - onClicked: { |
1355 | - mainStack.push(picker, {"url": activeAttachment.filePath, "handler": ContentHandler.Share}); |
1356 | - PopupUtils.close(popover) |
1357 | - } |
1358 | - } |
1359 | - ListItem.Standard { |
1360 | - text: i18n.tr("Select") |
1361 | - onClicked: { |
1362 | - triggerSelectionMode() |
1363 | - PopupUtils.close(popover) |
1364 | - } |
1365 | + id: statusIcon |
1366 | + Item { |
1367 | + height: units.gu(4) |
1368 | + width: units.gu(4) |
1369 | + visible: !incoming && !messageDelegate.selectionMode |
1370 | + ActivityIndicator { |
1371 | + id: indicator |
1372 | + |
1373 | + anchors.centerIn: parent |
1374 | + height: units.gu(2) |
1375 | + width: units.gu(2) |
1376 | + visible: running && !selectionMode |
1377 | + // if temporarily failed or unknown status, then show the spinner |
1378 | + running: inProgress |
1379 | + } |
1380 | + |
1381 | + Item { |
1382 | + id: retrybutton |
1383 | + |
1384 | + anchors.fill: parent |
1385 | + Icon { |
1386 | + id: icon |
1387 | + |
1388 | + name: "reload" |
1389 | + color: "red" |
1390 | + height: units.gu(2) |
1391 | + width: units.gu(2) |
1392 | + anchors { |
1393 | + centerIn: parent |
1394 | + verticalCenterOffset: units.gu(-1) |
1395 | + } |
1396 | + } |
1397 | + |
1398 | + Label { |
1399 | + text: i18n.tr("Failed!") |
1400 | + fontSize: "small" |
1401 | + color: "red" |
1402 | + anchors { |
1403 | + horizontalCenter: retrybutton.horizontalCenter |
1404 | + top: icon.bottom |
1405 | + } |
1406 | + } |
1407 | + visible: failed |
1408 | + MouseArea { |
1409 | + id: retrybuttonMouseArea |
1410 | + |
1411 | + anchors.fill: parent |
1412 | + onClicked: messageDelegate.resend() |
1413 | } |
1414 | } |
1415 | } |
1416 | @@ -86,18 +109,22 @@ |
1417 | |
1418 | Column { |
1419 | id: attachments |
1420 | - anchors.top: parent.top |
1421 | + anchors { |
1422 | + top: parent.top |
1423 | + left: parent.left |
1424 | + right: parent.right |
1425 | + } |
1426 | height: childrenRect.height |
1427 | - anchors.right: parent.right |
1428 | - anchors.left: parent.left |
1429 | - spacing: units.gu(2) |
1430 | - // TODO: we currently support only images as attachments |
1431 | Repeater { |
1432 | + id: attachmentsRepeater |
1433 | + |
1434 | model: textMessageAttachments |
1435 | Loader { |
1436 | - anchors.left: parent.left |
1437 | - anchors.right: parent.right |
1438 | - height: item ? item.height : undefined |
1439 | + anchors { |
1440 | + left: parent ? parent.left : undefined |
1441 | + right: parent ? parent.right : undefined |
1442 | + } |
1443 | + height: item ? item.height : 0 |
1444 | source: { |
1445 | if (startsWith(modelData.contentType, "image/")) { |
1446 | return "MMS/MMSImage.qml" |
1447 | @@ -105,10 +132,10 @@ |
1448 | return "MMS/MMSVideo.qml" |
1449 | } else if (startsWith(modelData.contentType, "application/smil") || |
1450 | startsWith(modelData.contentType, "application/x-smil")) { |
1451 | - console.log("Ignoring SMIL file") |
1452 | return "" |
1453 | } else if (startsWith(modelData.contentType, "text/plain") ) { |
1454 | mmsText = application.readTextFile(modelData.filePath) |
1455 | + mmsTextId = modelData.attachmentId |
1456 | return "" |
1457 | } else if (startsWith(modelData.contentType, "text/vcard") || |
1458 | startsWith(modelData.contentType, "text/x-vcard")) { |
1459 | @@ -127,20 +154,26 @@ |
1460 | Connections { |
1461 | target: item |
1462 | onItemRemoved: { |
1463 | - console.log("attachment removed: " + modelData.attachmentId) |
1464 | eventModel.removeEventAttachment(accountId, threadId, eventId, type, modelData.attachmentId) |
1465 | - } |
1466 | - } |
1467 | - Connections { |
1468 | - target: item |
1469 | - onPressAndHold: { |
1470 | - activeAttachment = modelData |
1471 | - PopupUtils.open(popoverSaveAttachmentComponent, item) |
1472 | - } |
1473 | - } |
1474 | - Connections { |
1475 | - target: item |
1476 | - onClicked: { |
1477 | + if (visibleAttachments == 1 && mmsText === "") { |
1478 | + // this is the last attachment. remove the whole event |
1479 | + eventModel.removeEvent(accountId, threadId, eventId, type) |
1480 | + return |
1481 | + } |
1482 | + } |
1483 | + } |
1484 | + Connections { |
1485 | + target: item |
1486 | + onItemPressAndHold: itemPressAndHold(bubbleItem) |
1487 | + } |
1488 | + Binding { |
1489 | + target: item |
1490 | + property: "parentSelected" |
1491 | + value: messageDelegate.selected |
1492 | + } |
1493 | + Connections { |
1494 | + target: item |
1495 | + onAttachmentClicked: { |
1496 | if (item.previewer === "") { |
1497 | activeAttachment = modelData |
1498 | PopupUtils.open(popoverSaveAttachmentComponent, item) |
1499 | @@ -156,236 +189,69 @@ |
1500 | } |
1501 | } |
1502 | |
1503 | - ListItem.Empty { |
1504 | - id: internalDelegate |
1505 | - anchors.top: attachments.bottom |
1506 | - anchors.topMargin: textMessageAttachments.length > 0 ? units.gu(1) : undefined |
1507 | - anchors.left: parent ? parent.left : undefined |
1508 | - anchors.right: parent ? parent.right: undefined |
1509 | - clip: true |
1510 | - height: (textMessage === "" && mmsText === "" && textMessageAttachments.length > 0) ? 0 : bubble.height + date.height |
1511 | - showDivider: false |
1512 | - highlightWhenPressed: false |
1513 | - onPressAndHold: PopupUtils.open(popoverMenuComponent, messageDelegate) |
1514 | - |
1515 | - onClicked: messageDelegate.clicked() |
1516 | - |
1517 | - Item { |
1518 | - Component { |
1519 | - id: popoverMenuComponent |
1520 | - Popover { |
1521 | - id: popover |
1522 | - Column { |
1523 | - id: containerLayout |
1524 | - anchors { |
1525 | - left: parent.left |
1526 | - top: parent.top |
1527 | - right: parent.right |
1528 | - } |
1529 | - ListItem.Standard { |
1530 | - text: i18n.tr("Copy") |
1531 | - onClicked: { |
1532 | - Clipboard.push(textMessage); |
1533 | - PopupUtils.close(popover) |
1534 | - } |
1535 | - } |
1536 | - ListItem.Standard { |
1537 | - objectName: "popoverSelectAction" |
1538 | - text: i18n.tr("Select") |
1539 | - onClicked: { |
1540 | - triggerSelectionMode() |
1541 | - PopupUtils.close(popover) |
1542 | - } |
1543 | - } |
1544 | - } |
1545 | - } |
1546 | - } |
1547 | - } |
1548 | - |
1549 | - Item { |
1550 | - Component { |
1551 | - id: popoverComponent |
1552 | - Popover { |
1553 | - id: popover |
1554 | - Column { |
1555 | - id: containerLayout |
1556 | - anchors { |
1557 | - left: parent.left |
1558 | - top: parent.top |
1559 | - right: parent.right |
1560 | - } |
1561 | - ListItem.Standard { |
1562 | - text: i18n.tr("Try again") |
1563 | - enabled: telepathyHelper.connected |
1564 | - onClicked: { |
1565 | - messageDelegate.resend() |
1566 | - PopupUtils.close(popover) |
1567 | - } |
1568 | - } |
1569 | - ListItem.Standard { |
1570 | - text: i18n.tr("Cancel") |
1571 | - onClicked: { |
1572 | - eventModel.removeEvent(accountId, threadId, eventId, type) |
1573 | - PopupUtils.close(popover) |
1574 | - } |
1575 | - } |
1576 | - } |
1577 | - } |
1578 | - } |
1579 | - } |
1580 | - |
1581 | - Icon { |
1582 | - id: selectionIndicator |
1583 | - visible: selectionMode |
1584 | - name: "select" |
1585 | - height: units.gu(3) |
1586 | - width: units.gu(3) |
1587 | - anchors.right: incoming ? undefined : bubble.left |
1588 | - anchors.left: incoming ? bubble.right : undefined |
1589 | - anchors.verticalCenter: bubble.verticalCenter |
1590 | - anchors.leftMargin: incoming ? units.gu(2) : 0 |
1591 | - anchors.rightMargin: incoming ? 0 : units.gu(2) |
1592 | - color: selected ? "white" : "grey" |
1593 | - } |
1594 | - |
1595 | - ActivityIndicator { |
1596 | - id: indicator |
1597 | - height: units.gu(3) |
1598 | - width: units.gu(3) |
1599 | - anchors.right: bubble.left |
1600 | - anchors.left: undefined |
1601 | - anchors.verticalCenter: bubble.verticalCenter |
1602 | - anchors.leftMargin: 0 |
1603 | - anchors.rightMargin: units.gu(1) |
1604 | - |
1605 | - visible: running && !selectionMode |
1606 | - // if temporarily failed or unknown status, then show the spinner |
1607 | - running: (textMessageStatus == HistoryThreadModel.MessageStatusUnknown || |
1608 | - textMessageStatus == HistoryThreadModel.MessageStatusTemporarilyFailed) && !incoming |
1609 | - } |
1610 | - |
1611 | - Label { |
1612 | - id: accountIndicator |
1613 | - anchors { |
1614 | - right: bubble.left |
1615 | - rightMargin: units.gu(0.5) |
1616 | - bottom: bubble.bottom |
1617 | - } |
1618 | - text: accountLabel |
1619 | - visible: !incoming |
1620 | - font.pixelSize: FontUtils.sizeToPixels("small") |
1621 | - color: "green" |
1622 | - } |
1623 | - |
1624 | - // FIXME: this is just a temporary workaround while we dont have the final design |
1625 | - UbuntuShape { |
1626 | - id: warningButton |
1627 | - color: "yellow" |
1628 | - height: units.gu(3) |
1629 | - width: units.gu(3) |
1630 | - anchors.right: accountIndicator.left |
1631 | - anchors.left: undefined |
1632 | - anchors.verticalCenter: bubble.verticalCenter |
1633 | - anchors.leftMargin: 0 |
1634 | - anchors.rightMargin: units.gu(1) |
1635 | - visible: (textMessageStatus == HistoryThreadModel.MessageStatusPermanentlyFailed) && !incoming && !selectionMode |
1636 | - MouseArea { |
1637 | - anchors.fill: parent |
1638 | - onClicked: PopupUtils.open(popoverComponent, warningButton) |
1639 | - } |
1640 | - Label { |
1641 | - text: "!" |
1642 | - color: "black" |
1643 | - anchors.centerIn: parent |
1644 | - } |
1645 | - } |
1646 | - |
1647 | - onItemRemoved: { |
1648 | - eventModel.removeEvent(accountId, threadId, eventId, type) |
1649 | - } |
1650 | - |
1651 | - Label { |
1652 | - id: date |
1653 | - objectName: 'messageDate' |
1654 | - anchors.top: parent.top |
1655 | - anchors{ |
1656 | - right: bubble.right |
1657 | - rightMargin: units.gu(2) |
1658 | - } |
1659 | - |
1660 | - height: paintedHeight + units.gu(0.5) |
1661 | - fontSize: "x-small" |
1662 | - color: "#333333" |
1663 | - text: { |
1664 | - if (indicator.visible) |
1665 | - i18n.tr("Sending...") |
1666 | - else if (warningButton.visible) |
1667 | - i18n.tr("Failed") |
1668 | - else |
1669 | - DateUtils.friendlyDay(timestamp) + " " + Qt.formatDateTime(timestamp, "hh:mm AP") |
1670 | - } |
1671 | - } |
1672 | + ListItemWithActions { |
1673 | + id: bubbleItem |
1674 | + |
1675 | + anchors { |
1676 | + top: attachments.bottom |
1677 | + left: parent.left |
1678 | + right: parent.right |
1679 | + } |
1680 | + internalAnchors { |
1681 | + topMargin: 0 |
1682 | + bottomMargin: 0 |
1683 | + } |
1684 | + |
1685 | + height: bubble.visible ? bubble.height : 0 |
1686 | + leftSideAction: Action { |
1687 | + iconName: "delete" |
1688 | + text: i18n.tr("Delete") |
1689 | + onTriggered: { |
1690 | + // if there are no attachments, remove the whole message |
1691 | + if (visibleAttachments == 0) { |
1692 | + eventModel.removeEvent(accountId, threadId, eventId, type) |
1693 | + return |
1694 | + } |
1695 | + // check if this is an mms text and we have more attachments |
1696 | + if (mmsText !== "" && visibleAttachments > 1) { |
1697 | + // remove only the text attachment if we have more attachments |
1698 | + eventModel.removeEventAttachment(accountId, threadId, eventId, type, mmsTextId) |
1699 | + mmsText = "" |
1700 | + mmsTextId = "" |
1701 | + return |
1702 | + } |
1703 | + } |
1704 | + } |
1705 | + |
1706 | + selected: messageDelegate.selected |
1707 | + selectionMode: messageDelegate.selectionMode |
1708 | + onItemPressAndHold: messageDelegate.itemPressAndHold(bubbleItem) |
1709 | + onItemClicked: messageDelegate.itemClicked(bubbleItem) |
1710 | + onSwippingChanged: messageList.updateSwippedItem(bubbleItem) |
1711 | + onSwipeStateChanged: messageList.updateSwippedItem(bubbleItem) |
1712 | |
1713 | MessageBubble { |
1714 | id: bubble |
1715 | |
1716 | - incoming: messageDelegate.incoming |
1717 | - anchors.left: incoming ? parent.left : undefined |
1718 | - anchors.leftMargin: units.gu(1) |
1719 | - anchors.right: incoming ? undefined : parent.right |
1720 | + anchors { |
1721 | + top: parent.top |
1722 | + left: incoming ? parent.left : undefined |
1723 | + right: incoming ? undefined : parent.right |
1724 | + } |
1725 | + visible: (messageText !== "") |
1726 | + messageText: textMessage !== "" ? textMessage : mmsText |
1727 | + messageTimeStamp: timestamp |
1728 | + messageStatus: textMessageStatus |
1729 | + } |
1730 | + |
1731 | + Loader { |
1732 | + id: statusIconLoader |
1733 | + active: !incoming && !messageDelegate.selectionMode && bubble.visible && (inProgress || failed) |
1734 | + sourceComponent: statusIcon |
1735 | + anchors.right: bubble.left |
1736 | anchors.rightMargin: units.gu(1) |
1737 | - anchors.top: date.bottom |
1738 | - |
1739 | - height: messageContents.height + units.gu(4) |
1740 | - |
1741 | - Item { |
1742 | - id: messageContents |
1743 | - anchors { |
1744 | - top: parent.top |
1745 | - topMargin: units.gu(2) |
1746 | - left: parent.left |
1747 | - leftMargin: incoming ? units.gu(3) : units.gu(2) |
1748 | - right: parent.right |
1749 | - rightMargin: units.gu(3) |
1750 | - } |
1751 | - height: childrenRect.height |
1752 | - |
1753 | - // TODO: to be used only on multiparty chat |
1754 | - Label { |
1755 | - id: senderName |
1756 | - anchors.top: parent.top |
1757 | - height: text == "" ? 0 : paintedHeight |
1758 | - fontSize: "large" |
1759 | - color: textColor |
1760 | - text: "" |
1761 | - } |
1762 | - |
1763 | - Label { |
1764 | - id: messageText |
1765 | - objectName: 'messageText' |
1766 | - anchors.top: parent.top |
1767 | - anchors.left: parent.left |
1768 | - anchors.right: parent.right |
1769 | - height: paintedHeight |
1770 | - wrapMode: Text.WrapAtWordBoundaryOrAnywhere |
1771 | - fontSize: "medium" |
1772 | - color: textColor |
1773 | - //opacity: incoming ? 1 : 0.9 |
1774 | - text: textMessage !== "" ? parseText(textMessage) : parseText(mmsText) |
1775 | - onLinkActivated: Qt.openUrlExternally(link) |
1776 | - function parseText(text) { |
1777 | - var phoneExp = /(\+?([0-9]+[ ]?)?\(?([0-9]+)\)?[-. ]?([0-9]+)[-. ]?([0-9]+)[-. ]?([0-9]+))/img; |
1778 | - // remove html tags |
1779 | - text = text.replace(/</g,'<').replace(/>/g,'<tt>></tt>'); |
1780 | - // replace line breaks |
1781 | - text = text.replace(/(\n)+/g, '<br />'); |
1782 | - // check for links |
1783 | - text = BaLinkify.linkify(text); |
1784 | - // linkify phone numbers |
1785 | - return text.replace(phoneExp, '<a href="tel:///$1">$1</a>'); |
1786 | - } |
1787 | - } |
1788 | - } |
1789 | + anchors.verticalCenter: bubble.verticalCenter |
1790 | } |
1791 | } |
1792 | + |
1793 | } |
1794 | |
1795 | === modified file 'src/qml/Messages.qml' |
1796 | --- src/qml/Messages.qml 2014-07-28 19:45:24 +0000 |
1797 | +++ src/qml/Messages.qml 2014-08-05 11:46:55 +0000 |
1798 | @@ -19,7 +19,7 @@ |
1799 | import QtQuick 2.0 |
1800 | import QtQuick.Window 2.0 |
1801 | import QtContacts 5.0 |
1802 | -import Ubuntu.Components 0.1 |
1803 | +import Ubuntu.Components 1.1 |
1804 | import Ubuntu.Components.ListItems 0.1 as ListItem |
1805 | import Ubuntu.Components.Popups 0.1 |
1806 | import Ubuntu.Content 0.1 |
1807 | @@ -92,8 +92,7 @@ |
1808 | } |
1809 | |
1810 | flickable: null |
1811 | - // we need to use isReady here to know if this is a bottom edge page or not. |
1812 | - __customHeaderContents: participants.length === 0 && isReady ? newMessageHeader : null |
1813 | + |
1814 | property bool isReady: false |
1815 | signal ready |
1816 | onReady: { |
1817 | @@ -125,23 +124,6 @@ |
1818 | } |
1819 | return i18n.tr("New Message") |
1820 | } |
1821 | - tools: { |
1822 | - if (selectionMode) { |
1823 | - return messagesToolbarSelectionMode |
1824 | - } |
1825 | - |
1826 | - if (participants.length == 0) { |
1827 | - return messagesToolbarNewMessage |
1828 | - } else if (participants.length == 1) { |
1829 | - if (contactWatcher.isUnknown) { |
1830 | - return messagesToolbarUnknownContact |
1831 | - } else { |
1832 | - return messagesToolbarKnownContact |
1833 | - } |
1834 | - } else if (groupChat){ |
1835 | - return messagesToolbarGroupChat |
1836 | - } |
1837 | - } |
1838 | |
1839 | Component.onCompleted: { |
1840 | updateFilters() |
1841 | @@ -156,7 +138,7 @@ |
1842 | var componentUnion = "import Ubuntu.History 0.1; HistoryUnionFilter { %1 }" |
1843 | var componentFilters = "" |
1844 | for (var i in telepathyHelper.accountIds) { |
1845 | - var filterValue = eventModel.threadIdForParticipants(telepathyHelper.accountIds[i], |
1846 | + var filterValue = eventModel.threadIdForParticipants(telepathyHelper.accountIds[i], |
1847 | HistoryThreadModel.EventTypeText, |
1848 | participants, |
1849 | HistoryThreadModel.MatchPhoneNumber) |
1850 | @@ -262,89 +244,23 @@ |
1851 | } |
1852 | } |
1853 | |
1854 | - Rectangle { |
1855 | - id: accountList |
1856 | - z: 1 |
1857 | - clip: !multipleAccounts |
1858 | - anchors { |
1859 | - left: parent.left |
1860 | - right: parent.right |
1861 | - top: parent.top |
1862 | - } |
1863 | - height: multipleAccounts ? childrenRect.height : 0 |
1864 | - color: "white" |
1865 | - Row { |
1866 | - anchors { |
1867 | - top: parent.top |
1868 | - horizontalCenter: parent.horizontalCenter |
1869 | - } |
1870 | - height: childrenRect.height |
1871 | - width: childrenRect.width |
1872 | - spacing: units.gu(2) |
1873 | - Repeater { |
1874 | - model: telepathyHelper.accounts |
1875 | - delegate: Label { |
1876 | - width: paintedWidth |
1877 | - height: paintedHeight |
1878 | - text: modelData.displayName |
1879 | - font.pixelSize: FontUtils.sizeToPixels("small") |
1880 | - color: messages.account == modelData ? "red" : "#5d5d5d" |
1881 | - MouseArea { |
1882 | - anchors { |
1883 | - fill: parent |
1884 | - // increase touch area |
1885 | - leftMargin: units.gu(-1) |
1886 | - rightMargin: units.gu(-1) |
1887 | - bottomMargin: units.gu(-1) |
1888 | - } |
1889 | - onClicked: messages.account = modelData |
1890 | - } |
1891 | - } |
1892 | - } |
1893 | - } |
1894 | + head.sections.model: { |
1895 | + // does not show dual sim switch if there is only one sim |
1896 | + if (!multipleAccounts) { |
1897 | + return undefined |
1898 | + } |
1899 | + |
1900 | + var accountNames = [] |
1901 | + for(var i=0; i < telepathyHelper.accounts.length; i++) { |
1902 | + accountNames.push(telepathyHelper.accounts[i].displayName) |
1903 | + } |
1904 | + return accountNames |
1905 | } |
1906 | - |
1907 | - Item { |
1908 | - id: newMessageHeader |
1909 | - anchors { |
1910 | - left: parent.left |
1911 | - rightMargin: units.gu(1) |
1912 | - right: parent.right |
1913 | - bottom: parent.bottom |
1914 | - } |
1915 | - visible: participants.length == 0 && isReady && messages.active |
1916 | - MultiRecipientInput { |
1917 | - id: multiRecipient |
1918 | - objectName: "multiRecipient" |
1919 | - enabled: visible |
1920 | - width: childrenRect.width |
1921 | - anchors { |
1922 | - left: parent.left |
1923 | - right: addIcon.left |
1924 | - rightMargin: units.gu(1) |
1925 | - verticalCenter: parent.verticalCenter |
1926 | - } |
1927 | - } |
1928 | - Icon { |
1929 | - id: addIcon |
1930 | - objectName: "addNewRecipientIcon" |
1931 | - visible: multiRecipient.visible |
1932 | - height: units.gu(3) |
1933 | - width: units.gu(3) |
1934 | - anchors { |
1935 | - right: parent.right |
1936 | - verticalCenter: parent.verticalCenter |
1937 | - } |
1938 | - |
1939 | - name: "contact" |
1940 | - color: "gray" |
1941 | - MouseArea { |
1942 | - anchors.fill: parent |
1943 | - onClicked: { |
1944 | - Qt.inputMethod.hide() |
1945 | - mainStack.push(Qt.resolvedUrl("NewRecipientPage.qml"), {"multiRecipient": multiRecipient, "parentPage": messages}) |
1946 | - } |
1947 | - } |
1948 | + head.sections.selectedIndex: Math.max(0, telepathyHelper.accounts.indexOf(messages.account)) |
1949 | + Connections { |
1950 | + target: messages.head.sections |
1951 | + onSelectedIndexChanged: { |
1952 | + messages.account = telepathyHelper.accounts[head.sections.selectedIndex] |
1953 | } |
1954 | } |
1955 | |
1956 | @@ -360,6 +276,7 @@ |
1957 | autoUpdate: false |
1958 | filterTerm: multiRecipient.searchString |
1959 | showSections: false |
1960 | + autoHideKeyboard: false |
1961 | |
1962 | states: [ |
1963 | State { |
1964 | @@ -373,7 +290,7 @@ |
1965 | ] |
1966 | |
1967 | anchors { |
1968 | - top: accountList.bottom |
1969 | + top: parent.top |
1970 | topMargin: units.gu(1) |
1971 | left: parent.left |
1972 | right: parent.right |
1973 | @@ -489,9 +406,9 @@ |
1974 | Loader { |
1975 | active: multiRecipient.searchString !== "" && multiRecipient.focus |
1976 | sourceComponent: contactSearchComponent |
1977 | + clip: true |
1978 | anchors { |
1979 | - top: accountList.bottom |
1980 | - topMargin: units.gu(1) |
1981 | + top: parent.top |
1982 | left: parent.left |
1983 | right: parent.right |
1984 | bottom: bottomPanel.top |
1985 | @@ -508,129 +425,156 @@ |
1986 | updateFilters() |
1987 | } |
1988 | |
1989 | - ToolbarItems { |
1990 | - id: messagesToolbarSelectionMode |
1991 | - visible: false |
1992 | - back: ToolbarButton { |
1993 | - id: selectionModeCancelButton |
1994 | - objectName: "selectionModeCancelButton" |
1995 | - action: Action { |
1996 | + state: { |
1997 | + if (participants.length === 0 && isReady) { |
1998 | + return "newMessage" |
1999 | + } else if (selectionMode) { |
2000 | + return "selection" |
2001 | + } else if (participants.length == 1) { |
2002 | + if (contactWatcher.isUnknown) { |
2003 | + return "unknownContact" |
2004 | + } else { |
2005 | + return "knownContact" |
2006 | + } |
2007 | + } else if (groupChat){ |
2008 | + return "groupChat" |
2009 | + } else { |
2010 | + return "" |
2011 | + } |
2012 | + } |
2013 | + |
2014 | + Action { |
2015 | + id: backButton |
2016 | + objectName: "backButton" |
2017 | + iconName: "back" |
2018 | + onTriggered: { |
2019 | + if (typeof mainPage !== 'undefined') { |
2020 | + mainPage.temporaryProperties = null |
2021 | + } |
2022 | + mainStack.pop() |
2023 | + } |
2024 | + } |
2025 | + |
2026 | + states: [ |
2027 | + PageHeadState { |
2028 | + name: "selection" |
2029 | + head: messages.head |
2030 | + |
2031 | + backAction: Action { |
2032 | objectName: "selectionModeCancelAction" |
2033 | - iconSource: "image://theme/close" |
2034 | + iconName: "close" |
2035 | onTriggered: messageList.cancelSelection() |
2036 | } |
2037 | - } |
2038 | - ToolbarButton { |
2039 | - id: selectionModeSelectAllButton |
2040 | - objectName: "selectionModeSelectAllButton" |
2041 | - action: Action { |
2042 | - objectName: "selectionModeSelectAllAction" |
2043 | - iconSource: "image://theme/filter" |
2044 | - onTriggered: messageList.selectAll() |
2045 | - } |
2046 | - } |
2047 | - ToolbarButton { |
2048 | - id: selectionModeDeleteButton |
2049 | - objectName: "selectionModeDeleteButton" |
2050 | - action: Action { |
2051 | - objectName: "selectionModeDeleteAction" |
2052 | - enabled: messageList.selectedItems.count > 0 |
2053 | - iconSource: "image://theme/delete" |
2054 | - onTriggered: messageList.endSelection() |
2055 | - } |
2056 | - } |
2057 | - } |
2058 | - |
2059 | - ToolbarItems { |
2060 | - id: messagesToolbarGroupChat |
2061 | - visible: false |
2062 | - ToolbarButton { |
2063 | - id: groupChatButton |
2064 | - objectName: "groupChatButton" |
2065 | - action: Action { |
2066 | - objectName: "groupChatAction" |
2067 | - iconSource: "image://theme/contact-group" |
2068 | - onTriggered: { |
2069 | - PopupUtils.open(participantsPopover, messages.header) |
2070 | - } |
2071 | - } |
2072 | - } |
2073 | - } |
2074 | - |
2075 | - ToolbarItems { |
2076 | - id: messagesToolbarNewMessage |
2077 | - visible: false |
2078 | - back: ToolbarButton { |
2079 | - action: Action { |
2080 | - onTriggered: { |
2081 | - mainPage.temporaryProperties = null |
2082 | - mainStack.pop() |
2083 | - } |
2084 | - iconSource: "image://theme/back" |
2085 | - } |
2086 | - } |
2087 | - } |
2088 | - |
2089 | - ToolbarItems { |
2090 | - id: messagesToolbarUnknownContact |
2091 | - visible: false |
2092 | - ToolbarButton { |
2093 | - objectName: "contactCallButton" |
2094 | - action: Action { |
2095 | - objectName: "contactCallAction" |
2096 | - visible: participants.length == 1 |
2097 | - iconSource: "image://theme/call-start" |
2098 | - text: i18n.tr("Call") |
2099 | - onTriggered: { |
2100 | - Qt.inputMethod.hide() |
2101 | - Qt.openUrlExternally("tel:///" + encodeURIComponent(contactWatcher.phoneNumber)) |
2102 | - } |
2103 | - } |
2104 | - } |
2105 | - ToolbarButton { |
2106 | - objectName: "addContactButton" |
2107 | - action: Action { |
2108 | - objectName: "addContactAction" |
2109 | - visible: contactWatcher.isUnknown && participants.length == 1 |
2110 | - iconSource: "image://theme/new-contact" |
2111 | - text: i18n.tr("Add") |
2112 | - onTriggered: { |
2113 | - Qt.inputMethod.hide() |
2114 | - Qt.openUrlExternally("addressbook:///addnewphone?callback=messaging-app.desktop&phone=" + encodeURIComponent(contactWatcher.phoneNumber)); |
2115 | - } |
2116 | - } |
2117 | - } |
2118 | - } |
2119 | - |
2120 | - ToolbarItems { |
2121 | - id: messagesToolbarKnownContact |
2122 | - visible: false |
2123 | - ToolbarButton { |
2124 | - objectName: "contactCallButton" |
2125 | - action: Action { |
2126 | - objectName: "contactCallKnownAction" |
2127 | - visible: participants.length == 1 |
2128 | - iconSource: "image://theme/call-start" |
2129 | - text: i18n.tr("Call") |
2130 | - onTriggered: { |
2131 | - Qt.inputMethod.hide() |
2132 | - Qt.openUrlExternally("tel:///" + encodeURIComponent(contactWatcher.phoneNumber)) |
2133 | - } |
2134 | - } |
2135 | - } |
2136 | - ToolbarButton { |
2137 | - objectName: "contactProfileButton" |
2138 | - action: Action { |
2139 | - objectName: "contactProfileAction" |
2140 | - visible: !contactWatcher.isUnknown && participants.length == 1 |
2141 | - iconSource: "image://theme/contact" |
2142 | - text: i18n.tr("Contact") |
2143 | - onTriggered: { |
2144 | - Qt.openUrlExternally("addressbook:///contact?callback=messaging-app.desktop&id=" + encodeURIComponent(contactWatcher.contactId)) |
2145 | - } |
2146 | - } |
2147 | - } |
2148 | - } |
2149 | + |
2150 | + actions: [ |
2151 | + Action { |
2152 | + objectName: "selectionModeSelectAllAction" |
2153 | + iconName: "select" |
2154 | + onTriggered: messageList.selectAll() |
2155 | + }, |
2156 | + Action { |
2157 | + objectName: "selectionModeDeleteAction" |
2158 | + enabled: messageList.selectedItems.count > 0 |
2159 | + iconName: "delete" |
2160 | + onTriggered: messageList.endSelection() |
2161 | + } |
2162 | + ] |
2163 | + }, |
2164 | + PageHeadState { |
2165 | + name: "groupChat" |
2166 | + head: messages.head |
2167 | + backAction: backButton |
2168 | + |
2169 | + actions: [ |
2170 | + Action { |
2171 | + objectName: "groupChatAction" |
2172 | + iconName: "contact-group" |
2173 | + onTriggered: PopupUtils.open(participantsPopover, messages.header) |
2174 | + } |
2175 | + ] |
2176 | + }, |
2177 | + PageHeadState { |
2178 | + name: "unknownContact" |
2179 | + head: messages.head |
2180 | + backAction: backButton |
2181 | + |
2182 | + actions: [ |
2183 | + Action { |
2184 | + objectName: "contactCallAction" |
2185 | + visible: participants.length == 1 |
2186 | + iconName: "call-start" |
2187 | + text: i18n.tr("Call") |
2188 | + onTriggered: { |
2189 | + Qt.inputMethod.hide() |
2190 | + Qt.openUrlExternally("tel:///" + encodeURIComponent(contactWatcher.phoneNumber)) |
2191 | + } |
2192 | + }, |
2193 | + Action { |
2194 | + objectName: "addContactAction" |
2195 | + visible: contactWatcher.isUnknown && participants.length == 1 |
2196 | + iconName: "new-contact" |
2197 | + text: i18n.tr("Add") |
2198 | + onTriggered: { |
2199 | + Qt.inputMethod.hide() |
2200 | + Qt.openUrlExternally("addressbook:///addnewphone?callback=messaging-app.desktop&phone=" + encodeURIComponent(contactWatcher.phoneNumber)); |
2201 | + } |
2202 | + } |
2203 | + ] |
2204 | + }, |
2205 | + PageHeadState { |
2206 | + name: "newMessage" |
2207 | + head: messages.head |
2208 | + backAction: backButton |
2209 | + actions: [ |
2210 | + Action { |
2211 | + objectName: "contactList" |
2212 | + iconName: "contact" |
2213 | + onTriggered: { |
2214 | + Qt.inputMethod.hide() |
2215 | + mainStack.push(Qt.resolvedUrl("NewRecipientPage.qml"), {"multiRecipient": multiRecipient, "parentPage": messages}) |
2216 | + } |
2217 | + } |
2218 | + |
2219 | + ] |
2220 | + |
2221 | + contents: MultiRecipientInput { |
2222 | + id: multiRecipient |
2223 | + objectName: "multiRecipient" |
2224 | + enabled: visible |
2225 | + anchors { |
2226 | + left: parent ? parent.left : undefined |
2227 | + right: parent ? parent.right : undefined |
2228 | + rightMargin: units.gu(2) |
2229 | + } |
2230 | + } |
2231 | + }, |
2232 | + PageHeadState { |
2233 | + name: "knownContact" |
2234 | + head: messages.head |
2235 | + backAction: backButton |
2236 | + actions: [ |
2237 | + Action { |
2238 | + objectName: "contactCallKnownAction" |
2239 | + visible: participants.length == 1 |
2240 | + iconName: "call-start" |
2241 | + text: i18n.tr("Call") |
2242 | + onTriggered: { |
2243 | + Qt.inputMethod.hide() |
2244 | + Qt.openUrlExternally("tel:///" + encodeURIComponent(contactWatcher.phoneNumber)) |
2245 | + } |
2246 | + }, |
2247 | + Action { |
2248 | + objectName: "contactProfileAction" |
2249 | + visible: !contactWatcher.isUnknown && participants.length == 1 |
2250 | + iconSource: "image://theme/contact" |
2251 | + text: i18n.tr("Contact") |
2252 | + onTriggered: { |
2253 | + Qt.openUrlExternally("addressbook:///contact?callback=messaging-app.desktop&id=" + encodeURIComponent(contactWatcher.contactId)) |
2254 | + } |
2255 | + } |
2256 | + ] |
2257 | + } |
2258 | + ] |
2259 | |
2260 | HistoryEventModel { |
2261 | id: eventModel |
2262 | @@ -652,44 +596,75 @@ |
2263 | MultipleSelectionListView { |
2264 | id: messageList |
2265 | objectName: "messageList" |
2266 | + |
2267 | + property var _currentSwipedItem: null |
2268 | + |
2269 | + function updateSwippedItem(item) |
2270 | + { |
2271 | + if (item.swipping) { |
2272 | + return |
2273 | + } |
2274 | + |
2275 | + if (item.swipeState !== "Normal") { |
2276 | + if (_currentSwipedItem !== item) { |
2277 | + if (_currentSwipedItem) { |
2278 | + _currentSwipedItem.resetSwipe() |
2279 | + } |
2280 | + _currentSwipedItem = item |
2281 | + } |
2282 | + } else if (item.swipeState !== "Normal" && _currentSwipedItem === item) { |
2283 | + _currentSwipedItem = null |
2284 | + } |
2285 | + } |
2286 | clip: true |
2287 | anchors { |
2288 | - top: accountList.bottom |
2289 | + top: parent.top |
2290 | left: parent.left |
2291 | right: parent.right |
2292 | bottom: bottomPanel.top |
2293 | } |
2294 | - // TODO: workaround to add some extra space at the bottom and top |
2295 | + // fake bottomMargin |
2296 | header: Item { |
2297 | - height: units.gu(2) |
2298 | - } |
2299 | - footer: Item { |
2300 | - height: units.gu(2) |
2301 | - } |
2302 | + height: units.gu(1) |
2303 | + } |
2304 | + |
2305 | + spacing: units.gu(1) |
2306 | listModel: participants.length > 0 ? sortProxy : null |
2307 | verticalLayoutDirection: ListView.BottomToTop |
2308 | - spacing: units.gu(2) |
2309 | highlightFollowsCurrentItem: false |
2310 | + /*add: Transition { |
2311 | + UbuntuNumberAnimation { |
2312 | + properties: "anchors.leftMargin" |
2313 | + from: -width |
2314 | + to: 0 |
2315 | + } |
2316 | + UbuntuNumberAnimation { |
2317 | + properties: "anchors.rightMargin" |
2318 | + from: -width |
2319 | + to: 0 |
2320 | + } |
2321 | + }*/ |
2322 | + |
2323 | listDelegate: MessageDelegate { |
2324 | id: messageDelegate |
2325 | objectName: "message%1".arg(index) |
2326 | incoming: senderId != "self" |
2327 | + // TODO: we have several items inside |
2328 | selected: messageList.isSelected(messageDelegate) |
2329 | unread: newEvent |
2330 | - removable: !messages.selectionMode |
2331 | selectionMode: messages.selectionMode |
2332 | - confirmRemoval: true |
2333 | accountLabel: multipleAccounts ? telepathyHelper.accountForId(accountId).displayName : "" |
2334 | - onClicked: { |
2335 | + // TODO: need select only the item |
2336 | + onItemClicked: { |
2337 | if (messageList.isInSelectionMode) { |
2338 | if (!messageList.selectItem(messageDelegate)) { |
2339 | messageList.deselectItem(messageDelegate) |
2340 | } |
2341 | } |
2342 | } |
2343 | - onTriggerSelectionMode: { |
2344 | + onItemPressAndHold: { |
2345 | messageList.startSelection() |
2346 | - clicked() |
2347 | + messageList.selectItem(messageDelegate) |
2348 | } |
2349 | |
2350 | Component.onCompleted: { |
2351 | @@ -912,7 +887,8 @@ |
2352 | anchors.top: attachments.count == 0 ? textEntry.top : attachmentThumbnails.bottom |
2353 | anchors.left: parent.left |
2354 | anchors.right: parent.right |
2355 | - height: units.gu(4) |
2356 | + // this value is to avoid letter being cut off |
2357 | + height: units.gu(4.3) |
2358 | style: MultiRecipientFieldStyle {} |
2359 | autoSize: true |
2360 | maximumLineCount: 0 |
2361 | @@ -946,7 +922,7 @@ |
2362 | anchors.right: parent.right |
2363 | anchors.rightMargin: units.gu(2) |
2364 | text: "Send" |
2365 | - color: "green" |
2366 | + color: enabled ? "#38b44a" : "#b2b2b2" |
2367 | width: units.gu(7) |
2368 | height: units.gu(4) |
2369 | font.pixelSize: FontUtils.sizeToPixels("small") |
2370 | |
2371 | === modified file 'src/qml/MultiRecipientInput.qml' |
2372 | --- src/qml/MultiRecipientInput.qml 2014-06-11 20:13:37 +0000 |
2373 | +++ src/qml/MultiRecipientInput.qml 2014-08-05 11:46:55 +0000 |
2374 | @@ -17,7 +17,7 @@ |
2375 | */ |
2376 | |
2377 | import QtQuick 2.0 |
2378 | -import Ubuntu.Components 0.1 |
2379 | +import Ubuntu.Components 1.1 |
2380 | import Ubuntu.Contacts 0.1 |
2381 | import Ubuntu.Telephony 0.1 |
2382 | import QtContacts 5.0 |
2383 | @@ -142,7 +142,7 @@ |
2384 | width: units.gu(20) |
2385 | hasClearButton: false |
2386 | clip: false |
2387 | - placeholderText: i18n.tr("Add contacts..") |
2388 | + placeholderText: multiRecipientWidget.recipientCount <= 0 ? i18n.tr("Add contacts...") :"" |
2389 | font.family: "Ubuntu" |
2390 | font.weight: Font.Light |
2391 | color: "#752571" |
2392 | |
2393 | === modified file 'src/qml/NewRecipientPage.qml' |
2394 | --- src/qml/NewRecipientPage.qml 2014-07-17 16:09:02 +0000 |
2395 | +++ src/qml/NewRecipientPage.qml 2014-08-05 11:46:55 +0000 |
2396 | @@ -17,7 +17,7 @@ |
2397 | */ |
2398 | |
2399 | import QtQuick 2.0 |
2400 | -import Ubuntu.Components 0.1 |
2401 | +import Ubuntu.Components 1.1 |
2402 | import Ubuntu.Contacts 0.1 |
2403 | import QtContacts 5.0 |
2404 | |
2405 | @@ -28,21 +28,40 @@ |
2406 | |
2407 | title: i18n.tr("Add recipient") |
2408 | |
2409 | - __customHeaderContents: TextField { |
2410 | - id: searchField |
2411 | - |
2412 | - anchors { |
2413 | - left: parent.left |
2414 | - leftMargin: units.gu(2) |
2415 | - right: parent.right |
2416 | - rightMargin: units.gu(2) |
2417 | - topMargin: units.gu(1.5) |
2418 | - bottomMargin: units.gu(1.5) |
2419 | - verticalCenter: parent.verticalCenter |
2420 | - } |
2421 | - onTextChanged: contactList.currentIndex = -1 |
2422 | - inputMethodHints: Qt.ImhNoPredictiveText |
2423 | - placeholderText: i18n.tr("Type to search by name or number") |
2424 | + head { |
2425 | + contents: TextField { |
2426 | + id: searchField |
2427 | + |
2428 | + anchors { |
2429 | + left: parent.left |
2430 | + leftMargin: units.gu(2) |
2431 | + right: parent.right |
2432 | + rightMargin: units.gu(2) |
2433 | + topMargin: units.gu(1.5) |
2434 | + bottomMargin: units.gu(1.5) |
2435 | + verticalCenter: parent.verticalCenter |
2436 | + } |
2437 | + onTextChanged: contactList.currentIndex = -1 |
2438 | + inputMethodHints: Qt.ImhNoPredictiveText |
2439 | + placeholderText: i18n.tr("Search...") |
2440 | + } |
2441 | + sections.model: ["All", "Favorites"] |
2442 | + } |
2443 | + |
2444 | + Connections { |
2445 | + target: newRecipientPage.head.sections |
2446 | + onSelectedIndexChanged: { |
2447 | + switch (newRecipientPage.head.sections.selectedIndex) { |
2448 | + case 0: |
2449 | + contactList.showAllContacts() |
2450 | + break; |
2451 | + case 1: |
2452 | + contactList.showFavoritesContacts() |
2453 | + break; |
2454 | + default: |
2455 | + break; |
2456 | + } |
2457 | + } |
2458 | } |
2459 | |
2460 | ContactListView { |
2461 | @@ -69,13 +88,18 @@ |
2462 | Qt.openUrlExternally("addressbook:///contact?callback=messaging-app.desktop&id=" + encodeURIComponent(contact.contactId)) |
2463 | mainStack.pop() |
2464 | } |
2465 | - } |
2466 | - |
2467 | - KeyboardRectangle { |
2468 | - id: keyboard |
2469 | + onAddDetailClicked: { |
2470 | + // FIXME: the extra space at the end is needed so contacts-app opens the right view |
2471 | + Qt.openUrlExternally("addressbook:///addphone?callback=messaging-app.desktop&id=" + encodeURIComponent(contact.contactId) + "&phone= ") |
2472 | + mainStack.pop() |
2473 | + } |
2474 | } |
2475 | |
2476 | // WORKAROUND: This is necessary to make the header visible from a bottom edge page |
2477 | Component.onCompleted: parentPage.active = false |
2478 | Component.onDestruction: parentPage.active = true |
2479 | + |
2480 | + KeyboardRectangle { |
2481 | + id: keyboard |
2482 | + } |
2483 | } |
2484 | |
2485 | === removed file 'src/qml/PageWithBottomEdge.qml' |
2486 | --- src/qml/PageWithBottomEdge.qml 2014-06-25 21:14:26 +0000 |
2487 | +++ src/qml/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000 |
2488 | @@ -1,367 +0,0 @@ |
2489 | -/* |
2490 | - * Copyright (C) 2014 Canonical, Ltd. |
2491 | - * |
2492 | - * This program is free software; you can redistribute it and/or modify |
2493 | - * it under the terms of the GNU General Public License as published by |
2494 | - * the Free Software Foundation; version 3. |
2495 | - * |
2496 | - * This program is distributed in the hope that it will be useful, |
2497 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2498 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2499 | - * GNU General Public License for more details. |
2500 | - * |
2501 | - * You should have received a copy of the GNU General Public License |
2502 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2503 | - */ |
2504 | - |
2505 | -/* |
2506 | - Example: |
2507 | - |
2508 | - MainView { |
2509 | - objectName: "mainView" |
2510 | - |
2511 | - applicationName: "com.ubuntu.developer.boiko.bottomedge" |
2512 | - |
2513 | - width: units.gu(100) |
2514 | - height: units.gu(75) |
2515 | - |
2516 | - Component { |
2517 | - id: pageComponent |
2518 | - |
2519 | - PageWithBottomEdge { |
2520 | - id: mainPage |
2521 | - title: i18n.tr("Main Page") |
2522 | - |
2523 | - Rectangle { |
2524 | - anchors.fill: parent |
2525 | - color: "white" |
2526 | - } |
2527 | - |
2528 | - bottomEdgePageComponent: Page { |
2529 | - title: "Contents" |
2530 | - anchors.fill: parent |
2531 | - //anchors.topMargin: contentsPage.flickable.contentY |
2532 | - |
2533 | - ListView { |
2534 | - anchors.fill: parent |
2535 | - model: 50 |
2536 | - delegate: ListItems.Standard { |
2537 | - text: "One Content Item: " + index |
2538 | - } |
2539 | - } |
2540 | - } |
2541 | - bottomEdgeTitle: i18n.tr("Bottom edge action") |
2542 | - } |
2543 | - } |
2544 | - |
2545 | - PageStack { |
2546 | - id: stack |
2547 | - Component.onCompleted: stack.push(pageComponent) |
2548 | - } |
2549 | - } |
2550 | - |
2551 | -*/ |
2552 | - |
2553 | -import QtQuick 2.0 |
2554 | -import Ubuntu.Components 0.1 |
2555 | - |
2556 | -Page { |
2557 | - id: page |
2558 | - |
2559 | - property alias bottomEdgePageComponent: edgeLoader.sourceComponent |
2560 | - property alias bottomEdgePageSource: edgeLoader.source |
2561 | - property alias bottomEdgeTitle: tipLabel.text |
2562 | - property alias bottomEdgeEnabled: bottomEdge.visible |
2563 | - property int bottomEdgeExpandThreshold: page.height * 0.2 |
2564 | - property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded |
2565 | - property bool reloadBottomEdgePage: true |
2566 | - |
2567 | - readonly property alias bottomEdgePage: edgeLoader.item |
2568 | - readonly property bool isReady: (tip.opacity === 0.0) |
2569 | - readonly property bool isCollapsed: (tip.opacity === 1.0) |
2570 | - readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready) |
2571 | - property var temporaryProperties: null |
2572 | - |
2573 | - property bool _showEdgePageWhenReady: false |
2574 | - property int _areaWhenExpanded: 0 |
2575 | - |
2576 | - signal bottomEdgeReleased() |
2577 | - signal bottomEdgeDismissed() |
2578 | - |
2579 | - |
2580 | - function showBottomEdgePage(source, properties) |
2581 | - { |
2582 | - edgeLoader.setSource(source, properties) |
2583 | - temporaryProperties = properties |
2584 | - _showEdgePageWhenReady = true |
2585 | - } |
2586 | - |
2587 | - function setBottomEdgePage(source, properties) |
2588 | - { |
2589 | - edgeLoader.setSource(source, properties) |
2590 | - } |
2591 | - |
2592 | - function _pushPage() |
2593 | - { |
2594 | - if (edgeLoader.status === Loader.Ready) { |
2595 | - edgeLoader.item.active = true |
2596 | - page.pageStack.push(edgeLoader.item) |
2597 | - if (edgeLoader.item.flickable) { |
2598 | - edgeLoader.item.flickable.contentY = -page.header.height |
2599 | - edgeLoader.item.flickable.returnToBounds() |
2600 | - } |
2601 | - if (edgeLoader.item.ready) |
2602 | - edgeLoader.item.ready() |
2603 | - } |
2604 | - } |
2605 | - |
2606 | - |
2607 | - Component.onCompleted: { |
2608 | - // avoid a binding on the expanded height value |
2609 | - var expandedHeight = height; |
2610 | - _areaWhenExpanded = expandedHeight; |
2611 | - } |
2612 | - |
2613 | - onActiveChanged: { |
2614 | - if (active) { |
2615 | - bottomEdge.state = "collapsed" |
2616 | - } |
2617 | - } |
2618 | - |
2619 | - onBottomEdgePageLoadedChanged: { |
2620 | - if (_showEdgePageWhenReady && bottomEdgePageLoaded) { |
2621 | - bottomEdge.state = "expanded" |
2622 | - _showEdgePageWhenReady = false |
2623 | - } |
2624 | - } |
2625 | - |
2626 | - Rectangle { |
2627 | - id: bgVisual |
2628 | - |
2629 | - color: "black" |
2630 | - anchors.fill: page |
2631 | - opacity: 0.7 * ((page.height - bottomEdge.y) / page.height) |
2632 | - z: 1 |
2633 | - } |
2634 | - |
2635 | - Rectangle { |
2636 | - id: bottomEdge |
2637 | - objectName: "bottomEdge" |
2638 | - |
2639 | - readonly property int tipHeight: units.gu(3) |
2640 | - readonly property int pageStartY: 0 |
2641 | - |
2642 | - z: 1 |
2643 | - color: Theme.palette.normal.background |
2644 | - parent: page |
2645 | - anchors { |
2646 | - left: parent.left |
2647 | - right: parent.right |
2648 | - } |
2649 | - height: page.height |
2650 | - y: height |
2651 | - |
2652 | - Rectangle { |
2653 | - id: shadow |
2654 | - |
2655 | - anchors { |
2656 | - left: parent.left |
2657 | - right: parent.right |
2658 | - } |
2659 | - height: units.gu(1) |
2660 | - y: -height |
2661 | - opacity: 0.0 |
2662 | - gradient: Gradient { |
2663 | - GradientStop { position: 0.0; color: "transparent" } |
2664 | - GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) } |
2665 | - } |
2666 | - } |
2667 | - |
2668 | - Item { |
2669 | - id: tipContainer |
2670 | - objectName: "bottomEdgeTip" |
2671 | - |
2672 | - width: childrenRect.width |
2673 | - height: bottomEdge.tipHeight |
2674 | - clip: true |
2675 | - y: -bottomEdge.tipHeight |
2676 | - anchors.horizontalCenter: parent.horizontalCenter |
2677 | - |
2678 | - UbuntuShape { |
2679 | - id: tip |
2680 | - |
2681 | - width: tipLabel.paintedWidth + units.gu(6) |
2682 | - height: bottomEdge.tipHeight + units.gu(1) |
2683 | - color: Theme.palette.normal.overlay |
2684 | - Label { |
2685 | - id: tipLabel |
2686 | - |
2687 | - anchors { |
2688 | - top: parent.top |
2689 | - left: parent.left |
2690 | - right: parent.right |
2691 | - } |
2692 | - height: bottomEdge.tipHeight |
2693 | - verticalAlignment: Text.AlignVCenter |
2694 | - horizontalAlignment: Text.AlignHCenter |
2695 | - } |
2696 | - } |
2697 | - } |
2698 | - |
2699 | - MouseArea { |
2700 | - preventStealing: true |
2701 | - drag.axis: Drag.YAxis |
2702 | - drag.target: bottomEdge |
2703 | - drag.minimumY: bottomEdge.pageStartY |
2704 | - drag.maximumY: page.height |
2705 | - |
2706 | - anchors { |
2707 | - left: parent.left |
2708 | - right: parent.right |
2709 | - } |
2710 | - height: bottomEdge.tipHeight |
2711 | - y: -height |
2712 | - |
2713 | - onReleased: { |
2714 | - page.bottomEdgeReleased() |
2715 | - if (bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) { |
2716 | - bottomEdge.state = "expanded" |
2717 | - } else { |
2718 | - bottomEdge.state = "collapsed" |
2719 | - bottomEdge.y = bottomEdge.height |
2720 | - } |
2721 | - } |
2722 | - |
2723 | - onPressed: { |
2724 | - bottomEdge.state = "floating" |
2725 | - bottomEdge.y -= bottomEdge.tipHeight |
2726 | - } |
2727 | - } |
2728 | - |
2729 | - Behavior on y { |
2730 | - UbuntuNumberAnimation {} |
2731 | - } |
2732 | - |
2733 | - state: "collapsed" |
2734 | - states: [ |
2735 | - State { |
2736 | - name: "collapsed" |
2737 | - PropertyChanges { |
2738 | - target: bottomEdge |
2739 | - y: bottomEdge.height |
2740 | - } |
2741 | - PropertyChanges { |
2742 | - target: tip |
2743 | - opacity: 1.0 |
2744 | - } |
2745 | - }, |
2746 | - State { |
2747 | - name: "expanded" |
2748 | - PropertyChanges { |
2749 | - target: bottomEdge |
2750 | - y: bottomEdge.pageStartY |
2751 | - } |
2752 | - PropertyChanges { |
2753 | - target: tip |
2754 | - opacity: 0.0 |
2755 | - } |
2756 | - }, |
2757 | - State { |
2758 | - name: "floating" |
2759 | - PropertyChanges { |
2760 | - target: shadow |
2761 | - opacity: 1.0 |
2762 | - } |
2763 | - } |
2764 | - ] |
2765 | - |
2766 | - transitions: [ |
2767 | - Transition { |
2768 | - to: "expanded" |
2769 | - SequentialAnimation { |
2770 | - UbuntuNumberAnimation { |
2771 | - targets: [bottomEdge,tip] |
2772 | - properties: "y,opacity" |
2773 | - duration: UbuntuAnimation.SlowDuration |
2774 | - } |
2775 | - ScriptAction { |
2776 | - script: page._pushPage() |
2777 | - } |
2778 | - } |
2779 | - }, |
2780 | - Transition { |
2781 | - from: "expanded" |
2782 | - to: "collapsed" |
2783 | - SequentialAnimation { |
2784 | - ScriptAction { |
2785 | - script: { |
2786 | - edgeLoader.item.parent = edgeLoader |
2787 | - edgeLoader.item.anchors.fill = edgeLoader |
2788 | - edgeLoader.item.active = false |
2789 | - } |
2790 | - } |
2791 | - UbuntuNumberAnimation { |
2792 | - targets: [bottomEdge,tip] |
2793 | - properties: "y,opacity" |
2794 | - duration: UbuntuAnimation.SlowDuration |
2795 | - } |
2796 | - ScriptAction { |
2797 | - script: { |
2798 | - // destroy current bottom page |
2799 | - if (page.reloadBottomEdgePage) { |
2800 | - edgeLoader.active = false |
2801 | - // remove properties from old instance |
2802 | - if (edgeLoader.source !== "") { |
2803 | - var properties = {} |
2804 | - if (temporaryProperties !== null) { |
2805 | - properties = temporaryProperties |
2806 | - temporaryProperties = null |
2807 | - } |
2808 | - |
2809 | - edgeLoader.setSource(edgeLoader.source, properties) |
2810 | - } |
2811 | - } |
2812 | - |
2813 | - // notify |
2814 | - page.bottomEdgeDismissed() |
2815 | - |
2816 | - // load a new bottom page in memory |
2817 | - edgeLoader.active = true |
2818 | - } |
2819 | - } |
2820 | - } |
2821 | - }, |
2822 | - Transition { |
2823 | - from: "floating" |
2824 | - to: "collapsed" |
2825 | - UbuntuNumberAnimation { |
2826 | - targets: [bottomEdge,tip] |
2827 | - properties: "y,opacity" |
2828 | - } |
2829 | - } |
2830 | - ] |
2831 | - |
2832 | - Loader { |
2833 | - id: edgeLoader |
2834 | - |
2835 | - z: 1 |
2836 | - active: true |
2837 | - asynchronous: true |
2838 | - anchors.fill: parent |
2839 | - |
2840 | - //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging |
2841 | - Binding { |
2842 | - target: edgeLoader |
2843 | - property: "anchors.topMargin" |
2844 | - value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0 |
2845 | - when: (edgeLoader.status === Loader.Ready && !page.isReady) |
2846 | - } |
2847 | - |
2848 | - onLoaded: { |
2849 | - if (page.isReady && edgeLoader.item.active != true) { |
2850 | - page._pushPage() |
2851 | - } |
2852 | - } |
2853 | - } |
2854 | - } |
2855 | -} |
2856 | |
2857 | === modified file 'src/qml/ThreadDelegate.qml' |
2858 | --- src/qml/ThreadDelegate.qml 2014-07-25 16:21:47 +0000 |
2859 | +++ src/qml/ThreadDelegate.qml 2014-08-05 11:46:55 +0000 |
2860 | @@ -17,17 +17,20 @@ |
2861 | */ |
2862 | |
2863 | import QtQuick 2.0 |
2864 | -import Ubuntu.Components 0.1 |
2865 | -import Ubuntu.Components.ListItems 0.1 as ListItem |
2866 | +import Ubuntu.Components 1.1 |
2867 | import Ubuntu.Components.Popups 0.1 |
2868 | import Ubuntu.Telephony 0.1 |
2869 | import Ubuntu.Contacts 0.1 |
2870 | import QtContacts 5.0 |
2871 | |
2872 | -ListItem.Empty { |
2873 | +ListItemWithActions { |
2874 | id: delegate |
2875 | + |
2876 | property bool groupChat: participants.length > 1 |
2877 | property string searchTerm |
2878 | + property string phoneNumber: delegateHelper.phoneNumber |
2879 | + property bool unknownContact: delegateHelper.isUnknown |
2880 | + property string threadId: model.threadId |
2881 | property string groupChatLabel: { |
2882 | var firstRecipient |
2883 | if (unknownContact) { |
2884 | @@ -40,10 +43,8 @@ |
2885 | return firstRecipient + " +" + String(participants.length-1) |
2886 | return firstRecipient |
2887 | } |
2888 | - property string phoneNumber: delegateHelper.phoneNumber |
2889 | - property bool unknownContact: delegateHelper.isUnknown |
2890 | + |
2891 | property bool selectionMode: false |
2892 | - property string threadId: model.threadId |
2893 | property string textMessage: { |
2894 | // check if this is an mms, if so, search for the actual text |
2895 | var imageCount = 0 |
2896 | @@ -81,7 +82,6 @@ |
2897 | anchors.left: parent.left |
2898 | anchors.right: parent.right |
2899 | height: units.gu(10) |
2900 | - showDivider: false |
2901 | // WORKAROUND: history-service can't filter by contact names |
2902 | onSearchTermChanged: { |
2903 | var found = false |
2904 | @@ -95,48 +95,15 @@ |
2905 | found = true |
2906 | } |
2907 | |
2908 | - height = found ? units.gu(10) : 0 |
2909 | + height = found ? units.gu(8) : 0 |
2910 | } |
2911 | |
2912 | - // FIXME: the selected state should be handled by the UITK |
2913 | - Item { |
2914 | - id: selection |
2915 | - |
2916 | - anchors { |
2917 | - top: parent.top |
2918 | - bottom: parent.bottom |
2919 | - right: parent.right |
2920 | - } |
2921 | - width: visible ? units.gu(6) : 0 |
2922 | - opacity: selectionMode ? 1.0 : 0.0 |
2923 | - visible: opacity > 0.0 |
2924 | - |
2925 | - Behavior on width { |
2926 | - UbuntuNumberAnimation { } |
2927 | - } |
2928 | - |
2929 | - Behavior on opacity { |
2930 | - UbuntuNumberAnimation { } |
2931 | - } |
2932 | - |
2933 | - Rectangle { |
2934 | - id: selectionIndicator |
2935 | - anchors.fill: parent |
2936 | - color: "black" |
2937 | - opacity: 0.2 |
2938 | - } |
2939 | - |
2940 | - Icon { |
2941 | - anchors.centerIn: selectionIndicator |
2942 | - name: "select" |
2943 | - height: units.gu(3) |
2944 | - width: units.gu(3) |
2945 | - color: selected ? "white" : "grey" |
2946 | - |
2947 | - Behavior on color { |
2948 | - ColorAnimation { |
2949 | - duration: 100 |
2950 | - } |
2951 | + leftSideAction: Action { |
2952 | + iconName: "delete" |
2953 | + text: i18n.tr("Delete") |
2954 | + onTriggered: { |
2955 | + for (var i in threads) { |
2956 | + threadModel.removeThread(threads[i].accountId, threads[i].threadId, threads[i].type) |
2957 | } |
2958 | } |
2959 | } |
2960 | @@ -147,27 +114,24 @@ |
2961 | fallbackAvatarUrl: delegateHelper.avatar !== "" ? delegateHelper.avatar : "image://theme/contact" |
2962 | fallbackDisplayName: delegateHelper.alias |
2963 | showAvatarPicture: (delegateHelper.avatar !== "") || (initials.length === 0) |
2964 | - |
2965 | + anchors { |
2966 | + left: parent.left |
2967 | + top: parent.top |
2968 | + bottom: parent.bottom |
2969 | + } |
2970 | height: units.gu(6) |
2971 | width: units.gu(6) |
2972 | - anchors { |
2973 | - left: parent.left |
2974 | - leftMargin: units.gu(2) |
2975 | - verticalCenter: parent.verticalCenter |
2976 | - } |
2977 | } |
2978 | |
2979 | Label { |
2980 | id: contactName |
2981 | anchors { |
2982 | top: avatar.top |
2983 | - topMargin: units.gu(0.5) |
2984 | left: avatar.right |
2985 | leftMargin: units.gu(1) |
2986 | } |
2987 | - font.weight: Font.Light |
2988 | fontSize: "medium" |
2989 | - color: "#752571" |
2990 | + color: UbuntuColors.lightAubergine |
2991 | text: groupChat ? groupChatLabel : unknownContact ? delegateHelper.phoneNumber : delegateHelper.alias |
2992 | } |
2993 | |
2994 | @@ -175,12 +139,31 @@ |
2995 | id: time |
2996 | anchors { |
2997 | verticalCenter: contactName.verticalCenter |
2998 | - right: selection.left |
2999 | + right: parent.right |
3000 | + } |
3001 | + fontSize: "x-small" |
3002 | + text: Qt.formatDateTime(eventTimestamp,"h:mm ap") |
3003 | + } |
3004 | + |
3005 | + UbuntuShape { |
3006 | + id: unreadCountIndicator |
3007 | + height: units.gu(2) |
3008 | + width: height |
3009 | + anchors { |
3010 | + top: time.bottom |
3011 | + topMargin: units.gu(1) |
3012 | + right: parent.right |
3013 | rightMargin: units.gu(2) |
3014 | } |
3015 | - fontSize: "x-small" |
3016 | - color: "#5d5d5d" |
3017 | - text: Qt.formatDateTime(eventTimestamp,"h:mm ap") |
3018 | + visible: unreadCount > 0 |
3019 | + color: "#38b44a" |
3020 | + Label { |
3021 | + anchors.centerIn: parent |
3022 | + text: unreadCount |
3023 | + color: "white" |
3024 | + fontSize: "x-small" |
3025 | + font.weight: Font.Light |
3026 | + } |
3027 | } |
3028 | |
3029 | // This is currently not being used in the new designs, but let's keep it here for now |
3030 | @@ -213,11 +196,6 @@ |
3031 | text: textMessage |
3032 | font.weight: Font.Light |
3033 | } |
3034 | - onItemRemoved: { |
3035 | - for (var i in threads) { |
3036 | - threadModel.removeThread(threads[i].accountId, threads[i].threadId, threads[i].type) |
3037 | - } |
3038 | - } |
3039 | |
3040 | Item { |
3041 | id: delegateHelper |
3042 | |
3043 | === added file 'src/qml/assets/conversation_error@27.png' |
3044 | Binary files src/qml/assets/conversation_error@27.png 1970-01-01 00:00:00 +0000 and src/qml/assets/conversation_error@27.png 2014-08-05 11:46:55 +0000 differ |
3045 | === added file 'src/qml/assets/conversation_error@27.sci' |
3046 | --- src/qml/assets/conversation_error@27.sci 1970-01-01 00:00:00 +0000 |
3047 | +++ src/qml/assets/conversation_error@27.sci 2014-08-05 11:46:55 +0000 |
3048 | @@ -0,0 +1,5 @@ |
3049 | +border.left: 63 |
3050 | +border.top: 46 |
3051 | +border.bottom: 88 |
3052 | +border.right: 44 |
3053 | +source: conversation_error@27.png |
3054 | |
3055 | === modified file 'src/qml/assets/conversation_outgoing@27.png' |
3056 | Binary files src/qml/assets/conversation_outgoing@27.png 2014-07-07 13:09:42 +0000 and src/qml/assets/conversation_outgoing@27.png 2014-08-05 11:46:55 +0000 differ |
3057 | === added file 'src/qml/assets/conversation_pending@27.png' |
3058 | Binary files src/qml/assets/conversation_pending@27.png 1970-01-01 00:00:00 +0000 and src/qml/assets/conversation_pending@27.png 2014-08-05 11:46:55 +0000 differ |
3059 | === added file 'src/qml/assets/conversation_pending@27.sci' |
3060 | --- src/qml/assets/conversation_pending@27.sci 1970-01-01 00:00:00 +0000 |
3061 | +++ src/qml/assets/conversation_pending@27.sci 2014-08-05 11:46:55 +0000 |
3062 | @@ -0,0 +1,5 @@ |
3063 | +border.left: 36 |
3064 | +border.top: 38 |
3065 | +border.bottom: 80 |
3066 | +border.right: 50 |
3067 | +source: conversation_pending@27.png |
3068 | |
3069 | === modified file 'src/qml/messaging-app.qml' |
3070 | --- src/qml/messaging-app.qml 2014-07-14 22:16:22 +0000 |
3071 | +++ src/qml/messaging-app.qml 2014-08-05 11:46:55 +0000 |
3072 | @@ -17,7 +17,7 @@ |
3073 | */ |
3074 | |
3075 | import QtQuick 2.0 |
3076 | -import Ubuntu.Components 0.1 |
3077 | +import Ubuntu.Components 1.1 |
3078 | import Ubuntu.Components.ListItems 0.1 as ListItem |
3079 | import Ubuntu.Components.Popups 0.1 |
3080 | import Ubuntu.Telephony 0.1 |
3081 | @@ -26,11 +26,13 @@ |
3082 | MainView { |
3083 | id: mainView |
3084 | |
3085 | + property string newPhoneNumber |
3086 | + |
3087 | automaticOrientation: true |
3088 | width: units.gu(40) |
3089 | height: units.gu(71) |
3090 | useDeprecatedToolbar: false |
3091 | - property string newPhoneNumber |
3092 | + anchorToKeyboard: false |
3093 | |
3094 | Component.onCompleted: { |
3095 | i18n.domain = "messaging-app" |
3096 | @@ -144,9 +146,10 @@ |
3097 | } |
3098 | } |
3099 | |
3100 | + |
3101 | PageStack { |
3102 | id: mainStack |
3103 | + |
3104 | objectName: "mainStack" |
3105 | - anchors.fill: parent |
3106 | } |
3107 | } |
3108 | |
3109 | === modified file 'tests/autopilot/messaging_app/emulators.py' |
3110 | --- tests/autopilot/messaging_app/emulators.py 2014-07-24 13:22:09 +0000 |
3111 | +++ tests/autopilot/messaging_app/emulators.py 2014-08-05 11:46:55 +0000 |
3112 | @@ -18,8 +18,8 @@ |
3113 | from autopilot.input import Keyboard |
3114 | from autopilot.platform import model |
3115 | from autopilot.introspection.dbus import StateNotFoundError |
3116 | - |
3117 | from ubuntuuitoolkit import emulators as toolkit_emulators |
3118 | +from ubuntuuitoolkit._custom_proxy_objects import _common |
3119 | |
3120 | |
3121 | logger = logging.getLogger(__name__) |
3122 | @@ -78,6 +78,10 @@ |
3123 | |
3124 | return self.wait_select_single("MainPage", objectName="") |
3125 | |
3126 | + def go_back(self): |
3127 | + """Click back button from toolbar on messages page""" |
3128 | + self.get_header().click_custom_back_button() |
3129 | + |
3130 | def click_header_action(self, action): |
3131 | """Click the action 'action' on the header""" |
3132 | self.get_header().click_action_button(action) |
3133 | @@ -149,8 +153,8 @@ |
3134 | """Return toolbar icon to add contact""" |
3135 | |
3136 | return self.select_single( |
3137 | - 'Icon', |
3138 | - objectName='addNewRecipientIcon', |
3139 | + 'PageHeadButton', |
3140 | + objectName='contactList_header_button', |
3141 | ) |
3142 | |
3143 | def click_add_contact_icon(self): |
3144 | @@ -280,11 +284,6 @@ |
3145 | objectName="message0") |
3146 | self.long_press(message) |
3147 | |
3148 | - # now click the popover action |
3149 | - select = self.wait_select_single("Standard", |
3150 | - objectName="popoverSelectAction") |
3151 | - self.pointing_device.click_object(select) |
3152 | - |
3153 | # FIXME: there should be a better way to detect when the popover is |
3154 | # gone |
3155 | time.sleep(2) |
3156 | @@ -420,7 +419,7 @@ |
3157 | """Bring the bottom edge page to the screen""" |
3158 | self.bottomEdgePageLoaded.wait_for(True) |
3159 | try: |
3160 | - action_item = self.wait_select_single('QQuickItem', |
3161 | + action_item = self.wait_select_single('UbuntuShape', |
3162 | objectName='bottomEdgeTip') |
3163 | start_x = (action_item.globalRect.x + |
3164 | (action_item.globalRect.width * 0.5)) |
3165 | @@ -457,7 +456,7 @@ |
3166 | |
3167 | def get_messages_count(self): |
3168 | """Return the number of meesages.""" |
3169 | - return self.select_single( |
3170 | + return self.wait_select_single( |
3171 | 'MultipleSelectionListView', objectName='messageList').count |
3172 | |
3173 | @autopilot_logging.log_action(logger.info) |
3174 | @@ -508,18 +507,36 @@ |
3175 | return messages |
3176 | |
3177 | |
3178 | -class ThreadDelegate(toolkit_emulators.Empty): |
3179 | +class ListItemWithActions(_common.UbuntuUIToolkitCustomProxyObjectBase): |
3180 | + |
3181 | + def confirm_removal(self): |
3182 | + deleteButton = self.wait_select_single(name='delete') |
3183 | + self.pointing_device.click_object(deleteButton) |
3184 | + |
3185 | + def swipe_to_delete(self): |
3186 | + x, y, width, height = self.globalRect |
3187 | + start_x = x + (width * 0.2) |
3188 | + stop_x = x + (width * 0.8) |
3189 | + start_y = stop_y = y + (height // 2) |
3190 | + |
3191 | + self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
3192 | + |
3193 | + def active_action(self, action_index): |
3194 | + action_margin = ((self.actionWidth / 5) * 2) |
3195 | + x_offset = ((self.actionWidth + action_margin) * action_index) |
3196 | + x_offset += self.actionThreshold |
3197 | + |
3198 | + x, y, width, height = self.globalRect |
3199 | + start_x = x + (width * 0.5) |
3200 | + stop_x = start_x - x_offset |
3201 | + start_y = stop_y = y + (height // 2) |
3202 | + |
3203 | + self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
3204 | + |
3205 | + |
3206 | +class ThreadDelegate(ListItemWithActions): |
3207 | """Autopilot helper for ThreadDelegate.""" |
3208 | |
3209 | |
3210 | -class MessageDelegate(toolkit_emulators.UbuntuUIToolkitEmulatorBase): |
3211 | +class MessageDelegate(ListItemWithActions): |
3212 | """Autopilot helper for the MessageDelegate.""" |
3213 | - |
3214 | - def swipe_to_delete(self): |
3215 | - self._get_internal_list_item().swipe_to_delete() |
3216 | - |
3217 | - def _get_internal_list_item(self): |
3218 | - return self.select_single(toolkit_emulators.Empty) |
3219 | - |
3220 | - def confirm_removal(self): |
3221 | - self._get_internal_list_item().confirm_removal() |
3222 | |
3223 | === modified file 'tests/autopilot/messaging_app/tests/test_messaging.py' |
3224 | --- tests/autopilot/messaging_app/tests/test_messaging.py 2014-07-15 16:32:01 +0000 |
3225 | +++ tests/autopilot/messaging_app/tests/test_messaging.py 2014-08-05 11:46:55 +0000 |
3226 | @@ -333,7 +333,11 @@ |
3227 | |
3228 | self.main_view.enable_messages_selection_mode() |
3229 | messages_page.select_messages(1, 2) |
3230 | - self.main_view.click_header_action('selectionModeDeleteAction') |
3231 | + |
3232 | + # Wait a few seconds before clicking the header |
3233 | + # to make sure the OSD is already gone |
3234 | + time.sleep(5) |
3235 | + self.main_view.click_messages_header_delete() |
3236 | |
3237 | remaining_messages = messages_page.get_messages() |
3238 | self.assertThat(remaining_messages, HasLength(1)) |
3239 | |
3240 | === modified file 'tests/qml/tst_MessageBubble.qml' |
3241 | --- tests/qml/tst_MessageBubble.qml 2014-07-22 16:46:00 +0000 |
3242 | +++ tests/qml/tst_MessageBubble.qml 2014-08-05 11:46:55 +0000 |
3243 | @@ -64,9 +64,6 @@ |
3244 | when: windowShown |
3245 | |
3246 | function init() { |
3247 | - waitForRendering(incomingMessageBubble); |
3248 | - waitForRendering(outgoingMessageBubble); |
3249 | - waitForRendering(changeIncomingMessageBubble); |
3250 | } |
3251 | |
3252 | function cleanup() { |
FAILED: Continuous integration, rev:171 jenkins. qa.ubuntu. com/job/ messaging- app-ci/ 315/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/2591 jenkins. qa.ubuntu. com/job/ generic- mediumtests- utopic/ 2075 jenkins. qa.ubuntu. com/job/ messaging- app-utopic- amd64-ci/ 109 jenkins. qa.ubuntu. com/job/ messaging- app-utopic- armhf-ci/ 109 jenkins. qa.ubuntu. com/job/ messaging- app-utopic- armhf-ci/ 109/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ messaging- app-utopic- i386-ci/ 109 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/2727 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/3834 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/3834/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 10545 jenkins. qa.ubuntu. com/job/ autopilot- testrunner- otto-utopic/ 1733 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/2328 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/2328/ artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/messaging- app-ci/ 315/rebuild
http://