~barry/messaging-app/py3autopilot

« back to all changes in this revision

Viewing changes to src/qml/Messages.qml

  • Committer: Barry Warsaw
  • Date: 2014-06-19 13:57:17 UTC
  • mfrom: (111.1.8 messaging-app)
  • Revision ID: barry@python.org-20140619135717-k18ohowjg3xqeali
trunk merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import Ubuntu.Contacts 0.1
28
28
import QtContacts 5.0
29
29
 
30
 
 
31
30
Page {
32
31
    id: messages
33
32
    objectName: "messagesPage"
34
33
    property string threadId: ""
 
34
    property bool newMessage: threadId === ""
35
35
    // FIXME: we should get the account ID properly when dealing with multiple accounts
36
36
    property string accountId: telepathyHelper.accountIds[0]
37
37
    property variant participants: []
43
43
    property bool landscape: orientationAngle == 90 || orientationAngle == 270
44
44
    property bool pendingMessage: false
45
45
    flickable: null
 
46
    // we need to use isReady here to know if this is a bottom edge page or not.
 
47
    __customHeaderContents: newMessage && isReady ? newMessageHeader : null
 
48
    property bool isReady: false
 
49
    signal ready
 
50
    onReady: {
 
51
        isReady = true
 
52
        if (participants.length === 0 && keyboardFocus)
 
53
            multiRecipient.forceFocus()
 
54
    }
 
55
 
46
56
    title: {
 
57
        if (selectionMode) {
 
58
            return i18n.tr("Edit")
 
59
        }
 
60
 
47
61
        if (landscape) {
48
62
            return ""
49
63
        }
57
71
            if (participants.length == 1) {
58
72
                return firstRecipient
59
73
            } else {
60
 
                var numOther = participants.length-1
61
 
                return firstRecipient + " +" + i18n.tr("%1 other", "%1 others", numOther).arg(numOther)
 
74
                return i18n.tr("Group")
62
75
            }
63
76
        }
64
77
        return i18n.tr("New Message")
65
78
    }
66
 
    tools: messagesToolbar
67
 
    onSelectionModeChanged: messagesToolbar.opened = false
 
79
    tools: {
 
80
        if (selectionMode) {
 
81
            return messagesToolbarSelectionMode
 
82
        }
 
83
 
 
84
        if (participants.length == 0) {
 
85
            return null
 
86
        } else if (participants.length == 1) {
 
87
            if (contactWatcher.isUnknown) {
 
88
                return messagesToolbarUnknownContact
 
89
            } else {
 
90
                return messagesToolbarKnownContact
 
91
            }
 
92
        } else if (groupChat){
 
93
            return messagesToolbarGroupChat
 
94
        }
 
95
    }
 
96
 
68
97
    Component.onCompleted: {
69
98
        threadId = getCurrentThreadId()
70
99
    }
113
142
        }
114
143
    }
115
144
 
116
 
    Item {
117
 
        id: headerContent
118
 
        visible: groupChat
119
 
        anchors.fill: parent
120
 
 
121
 
        Label {
122
 
            text: messages.title
123
 
            fontSize: "x-large"
124
 
            font.weight: Font.Light
125
 
            verticalAlignment: Text.AlignVCenter
126
 
            elide: Text.ElideRight
127
 
            anchors {
128
 
                left: parent.left
129
 
                leftMargin: units.gu(1)
130
 
                top: parent.top
131
 
                bottom: parent.bottom
132
 
                right: participantsButton.left
133
 
            }
134
 
        }
135
 
 
136
 
        Icon {
137
 
            id: participantsButton
138
 
            name: "navigation-menu"
139
 
            width: visible ? units.gu(6) : 0
140
 
            height: units.gu(6)
141
 
            visible: groupChat
142
 
            anchors {
143
 
                verticalCenter: parent.verticalCenter
144
 
                right: parent.right
145
 
            }
146
 
 
147
 
            MouseArea {
148
 
                anchors.fill: parent
149
 
                onClicked: PopupUtils.open(participantsPopover, participantsButton)
150
 
            }
151
 
        }
152
 
    }
153
 
 
154
 
    Binding {
155
 
        target: messages.header
156
 
        property: "contents"
157
 
        value: groupChat ? headerContent : null
158
 
        when: messages.header && !landscape && messages.active
159
 
    }
160
 
 
161
 
 
162
145
    Component {
163
146
         id: newContactDialog
164
147
         Dialog {
169
152
                 text: i18n.tr("Add to existing contact")
170
153
                 color: UbuntuColors.orange
171
154
                 onClicked: {
172
 
                     PopupUtils.open(addPhoneNumberToContactSheet)
173
155
                     PopupUtils.close(dialogue)
 
156
                     Qt.inputMethod.hide()
 
157
                     mainStack.push(Qt.resolvedUrl("AddPhoneNumberToContactPage.qml"), {"phoneNumber": contactWatcher.phoneNumber})
174
158
                 }
175
159
             }
176
160
             Button {
191
175
         }
192
176
    }
193
177
 
 
178
    Item {
 
179
        id: newMessageHeader
 
180
        anchors {
 
181
            left: parent.left
 
182
            rightMargin: units.gu(1)
 
183
            right: parent.right
 
184
            bottom: parent.bottom
 
185
            top: parent.top
 
186
        }
 
187
        visible: participants.length == 0 && isReady && messages.active
 
188
        MultiRecipientInput {
 
189
            id: multiRecipient
 
190
            objectName: "multiRecipient"
 
191
            enabled: visible
 
192
            width: childrenRect.width
 
193
            anchors {
 
194
                left: parent.left
 
195
                right: addIcon.left
 
196
                rightMargin: units.gu(1)
 
197
                verticalCenter: parent.verticalCenter
 
198
            }
 
199
        }
 
200
        Icon {
 
201
            id: addIcon
 
202
            visible: multiRecipient.visible
 
203
            height: units.gu(3)
 
204
            width: units.gu(3)
 
205
            anchors {
 
206
                right: parent.right
 
207
                verticalCenter: parent.verticalCenter
 
208
            }
 
209
 
 
210
            name: "new-contact"
 
211
            color: "gray"
 
212
            MouseArea {
 
213
                anchors.fill: parent
 
214
                onClicked: {
 
215
                    Qt.inputMethod.hide()
 
216
                    mainStack.push(Qt.resolvedUrl("NewRecipientPage.qml"), {"multiRecipient": multiRecipient})
 
217
                }
 
218
            }
 
219
        }
 
220
    }
 
221
 
 
222
    ContactListView {
 
223
        id: contactSearch
 
224
        property bool searchEnabled: multiRecipient.searchString !== "" && multiRecipient.focus
 
225
        visible: searchEnabled
 
226
        detailToPick: ContactDetail.PhoneNumber
 
227
        clip: true
 
228
        z: 1
 
229
        autoUpdate: false
 
230
 
 
231
        property string searchTerm: {
 
232
            if(multiRecipient.searchString !== "" && multiRecipient.focus) {
 
233
                return multiRecipient.searchString
 
234
            }
 
235
            return ""
 
236
        }
 
237
        states: [
 
238
            State {
 
239
                name: "empty"
 
240
                when: contactSearch.count === 0
 
241
                PropertyChanges {
 
242
                    target: contactSearch
 
243
                    height: 0
 
244
                }
 
245
            }
 
246
        ]
 
247
 
 
248
        anchors {
 
249
            top: parent.top
 
250
            left: parent.left
 
251
            right: parent.right
 
252
            bottom: bottomPanel.top
 
253
        }
 
254
 
 
255
        Behavior on height {
 
256
            UbuntuNumberAnimation { }
 
257
        }
 
258
 
 
259
        onSearchTermChanged: {
 
260
            if ((searchTerm.length > 0) && (filter != contactSearchFilter)) {
 
261
                changeFilter(contactSearchFilter)
 
262
            } else if ((searchTerm.length == 0) && (filter != null)) {
 
263
                changeFilter(null)
 
264
            }
 
265
            contactSearchTimeout.restart()
 
266
        }
 
267
 
 
268
        InvalidFilter {
 
269
            id: invalidFilter
 
270
        }
 
271
 
 
272
        // clear list if it is invisible to save some memory
 
273
        onVisibleChanged: {
 
274
            if (visible && (filter != null)) {
 
275
                changeFilter(null)
 
276
            } else if (!visible && filter != invalidFilter) {
 
277
                changeFilter(invalidFilter)
 
278
            }
 
279
            contactSearch.update()
 
280
        }
 
281
 
 
282
        onDetailClicked: {
 
283
            if (action === "message" || action === "") {
 
284
                multiRecipient.addRecipient(detail.number)
 
285
                multiRecipient.clearSearch()
 
286
                multiRecipient.forceActiveFocus()
 
287
            } else if (action === "call") {
 
288
                Qt.inputMethod.hide()
 
289
                Qt.openUrlExternally("tel:///" + encodeURIComponent(detail.number))
 
290
            }
 
291
        }
 
292
 
 
293
        onInfoRequested: {
 
294
            Qt.inputMethod.hide()
 
295
            Qt.openUrlExternally("addressbook:///contact?id=" + encodeURIComponent(contact.contactId))
 
296
        }
 
297
 
 
298
        UnionFilter {
 
299
            id: contactSearchFilter
 
300
 
 
301
            DetailFilter {
 
302
                detail: ContactDetail.DisplayLabel
 
303
                field: DisplayLabel.Label
 
304
                value: contactSearch.searchTerm
 
305
                matchFlags: DetailFilter.MatchContains
 
306
            }
 
307
            DetailFilter {
 
308
                detail: ContactDetail.PhoneNumber
 
309
                field: PhoneNumber.Number
 
310
                value: contactSearch.searchTerm
 
311
                matchFlags: DetailFilter.MatchPhoneNumber
 
312
            }
 
313
 
 
314
            DetailFilter {
 
315
                detail: ContactDetail.PhoneNumber
 
316
                field: PhoneNumber.Number
 
317
                value: contactSearch.searchTerm
 
318
                matchFlags: DetailFilter.MatchContains
 
319
            }
 
320
        }
 
321
 
 
322
        Timer {
 
323
            id: contactSearchTimeout
 
324
 
 
325
            running: false
 
326
            repeat: false
 
327
            interval: 300
 
328
            onTriggered: contactSearch.update()
 
329
        }
 
330
    }
 
331
 
194
332
    ContactWatcher {
195
333
        id: contactWatcher
196
334
        phoneNumber: participants.length > 0 ? participants[0] : ""
200
338
        threadId = getCurrentThreadId()
201
339
    }
202
340
 
203
 
    Component {
204
 
        id: addPhoneNumberToContactSheet
205
 
        DefaultSheet {
206
 
            // FIXME: workaround to set the contact list
207
 
            // background to black
208
 
            Rectangle {
209
 
                anchors.fill: parent
210
 
                anchors.margins: -units.gu(1)
211
 
                color: "#221e1c"
212
 
            }
213
 
            id: sheet
214
 
            title: i18n.tr("Add to contact")
215
 
            doneButton: false
216
 
            modal: true
217
 
            contentsHeight: parent.height
218
 
            contentsWidth: parent.width
219
 
            ContactListView {
220
 
                anchors.fill: parent
221
 
                onContactClicked: {
222
 
                    Qt.openUrlExternally("addressbook:///addphone?id=" + encodeURIComponent(contact.contactId) +
223
 
                                                                "&phone=" + encodeURIComponent(contactWatcher.phoneNumber))
224
 
                    PopupUtils.close(sheet)
225
 
                }
226
 
            }
227
 
            onDoneClicked: PopupUtils.close(sheet)
228
 
        }
229
 
    }
230
 
 
231
 
    Component {
232
 
        id: addContactToConversationSheet
233
 
        DefaultSheet {
234
 
            // FIXME: workaround to set the contact list
235
 
            // background to black
236
 
            Rectangle {
237
 
                anchors.fill: parent
238
 
                anchors.margins: -units.gu(1)
239
 
                color: "#221e1c"
240
 
            }
241
 
            id: sheet
242
 
            title: i18n.tr("Add Contact")
243
 
            doneButton: false
244
 
            modal: true
245
 
            contentsHeight: parent.height
246
 
            contentsWidth: parent.width
247
 
            ContactListView {
248
 
                anchors.fill: parent
249
 
                detailToPick: ContactDetail.PhoneNumber
250
 
                onContactClicked: {
251
 
                    // FIXME: search for favorite number
252
 
                    multiRecipient.addRecipient(contact.phoneNumber.number)
253
 
                    multiRecipient.forceActiveFocus()
254
 
                    PopupUtils.close(sheet)
255
 
                }
256
 
                onDetailClicked: {
257
 
                    multiRecipient.addRecipient(detail.number)
258
 
                    PopupUtils.close(sheet)
259
 
                    multiRecipient.forceActiveFocus()
260
 
                }
261
 
            }
262
 
            onDoneClicked: PopupUtils.close(sheet)
263
 
        }
264
 
    }
265
 
 
266
 
    ToolbarItems {
267
 
        id: messagesToolbar
268
 
        ToolbarButton {
269
 
            objectName: "selectMessagesButton"
270
 
            visible: messageList.count !== 0
271
 
            action: Action {
272
 
                iconSource: "image://theme/select"
273
 
                text: i18n.tr("Select")
274
 
                onTriggered: messageList.startSelection()
275
 
            }
276
 
        }
277
 
        ToolbarButton {
278
 
            visible: contactWatcher.isUnknown && participants.length == 1
 
341
    ToolbarItems {
 
342
        id: messagesToolbarSelectionMode
 
343
        visible: false
 
344
        back: ToolbarButton {
 
345
            id: selectionModeCancelButton
 
346
            objectName: "selectionModeCancelButton"
 
347
            action: Action {
 
348
                objectName: "selectionModeCancelAction"
 
349
                iconSource: "image://theme/close"
 
350
                onTriggered: messageList.cancelSelection()
 
351
            }
 
352
        }
 
353
        ToolbarButton {
 
354
            id: selectionModeSelectAllButton
 
355
            objectName: "selectionModeSelectAllButton"
 
356
            action: Action {
 
357
                objectName: "selectionModeSelectAllAction"
 
358
                iconSource: "image://theme/filter"
 
359
                onTriggered: messageList.selectAll()
 
360
            }
 
361
        }
 
362
        ToolbarButton {
 
363
            id: selectionModeDeleteButton
 
364
            objectName: "selectionModeDeleteButton"
 
365
            action: Action {
 
366
                objectName: "selectionModeDeleteAction"
 
367
                enabled: messageList.selectedItems.count > 0
 
368
                iconSource: "image://theme/delete"
 
369
                onTriggered: messageList.endSelection()
 
370
            }
 
371
        }
 
372
    }
 
373
 
 
374
    ToolbarItems {
 
375
        id: messagesToolbarGroupChat
 
376
        visible: false
 
377
        ToolbarButton {
 
378
            id: groupChatButton
 
379
            objectName: "groupChatButton"
 
380
            action: Action {
 
381
                iconSource: "image://theme/navigation-menu"
 
382
                onTriggered: {
 
383
                    PopupUtils.open(participantsPopover, messages.header)
 
384
                }
 
385
            }
 
386
        }
 
387
    }
 
388
 
 
389
    ToolbarItems {
 
390
        id: messagesToolbarUnknownContact
 
391
        visible: false
 
392
        ToolbarButton {
 
393
            objectName: "contactCallButton"
 
394
            action: Action {
 
395
                visible: participants.length == 1
 
396
                iconSource: "image://theme/call-start"
 
397
                text: i18n.tr("Call")
 
398
                onTriggered: {
 
399
                    Qt.inputMethod.hide()
 
400
                    Qt.openUrlExternally("tel:///" + encodeURIComponent(contactWatcher.phoneNumber))
 
401
                }
 
402
            }
 
403
        }
 
404
        ToolbarButton {
279
405
            objectName: "addContactButton"
280
406
            action: Action {
 
407
                visible: contactWatcher.isUnknown && participants.length == 1
281
408
                iconSource: "image://theme/new-contact"
282
409
                text: i18n.tr("Add")
283
410
                onTriggered: {
 
411
                    Qt.inputMethod.hide()
284
412
                    PopupUtils.open(newContactDialog)
285
 
                    messagesToolbar.opened = false
286
 
                }
287
 
            }
288
 
        }
289
 
        ToolbarButton {
290
 
            visible: !contactWatcher.isUnknown && participants.length == 1
 
413
                }
 
414
            }
 
415
        }
 
416
    }
 
417
 
 
418
    ToolbarItems {
 
419
        id: messagesToolbarKnownContact
 
420
        visible: false
 
421
        ToolbarButton {
 
422
            objectName: "contactCallButton"
 
423
            action: Action {
 
424
                visible: participants.length == 1
 
425
                iconSource: "image://theme/call-start"
 
426
                text: i18n.tr("Call")
 
427
                onTriggered: {
 
428
                    Qt.inputMethod.hide()
 
429
                    Qt.openUrlExternally("tel:///" + encodeURIComponent(contactWatcher.phoneNumber))
 
430
                }
 
431
            }
 
432
        }
 
433
        ToolbarButton {
291
434
            objectName: "contactProfileButton"
292
435
            action: Action {
 
436
                visible: !contactWatcher.isUnknown && participants.length == 1
293
437
                iconSource: "image://theme/contact"
294
438
                text: i18n.tr("Contact")
295
439
                onTriggered: {
296
440
                    Qt.openUrlExternally("addressbook:///contact?id=" + encodeURIComponent(contactWatcher.contactId))
297
 
                    messagesToolbar.opened = false
298
 
                }
299
 
            }
300
 
        }
301
 
        ToolbarButton {
302
 
            visible: participants.length == 1
303
 
            objectName: "contactCallButton"
304
 
            action: Action {
305
 
                iconSource: "image://theme/call-start"
306
 
                text: i18n.tr("Call")
307
 
                onTriggered: {
308
 
                    Qt.openUrlExternally("tel:///" + encodeURIComponent(contactWatcher.phoneNumber))
309
 
                    messagesToolbar.opened = false
310
 
                }
311
 
            }
312
 
        }
313
 
        locked: selectionMode
 
441
                }
 
442
            }
 
443
        }
314
444
    }
315
445
 
316
446
    HistoryEventModel {
339
469
        ascending: false
340
470
    }
341
471
 
342
 
    Icon {
343
 
        id: addIcon
344
 
        visible: multiRecipient.visible
345
 
        height: units.gu(3)
346
 
        width: units.gu(3)
347
 
        anchors {
348
 
            right: parent.right
349
 
            rightMargin: units.gu(2)
350
 
            top: parent.top
351
 
            topMargin: units.gu(1)
352
 
        }
353
 
 
354
 
        name: "new-contact"
355
 
        color: "white"
356
 
        MouseArea {
357
 
            anchors.fill: parent
358
 
            onClicked: {
359
 
                var item = keyboard.recursiveFindFocusedItem(messages)
360
 
                if (item) {
361
 
                    item.focus = false
362
 
                }
363
 
 
364
 
                PopupUtils.open(addContactToConversationSheet)
365
 
            }
366
 
        }
367
 
    }
368
 
 
369
 
    MultiRecipientInput {
370
 
        id: multiRecipient
371
 
        objectName: "multiRecipient"
372
 
        visible: participants.length == 0
373
 
        enabled: visible
374
 
        anchors {
375
 
            top: parent.top
376
 
            topMargin: units.gu(1)
377
 
            left: parent.left
378
 
            right: addIcon.left
379
 
        }
380
 
    }
381
 
 
382
472
    MultipleSelectionListView {
383
473
        id: messageList
384
474
        objectName: "messageList"
385
475
        clip: true
386
 
        acceptAction.text: i18n.tr("Delete")
387
 
        acceptAction.enabled: selectedItems.count > 0
388
476
        anchors {
389
 
            top: multiRecipient.bottom
 
477
            top: parent.top
390
478
            left: parent.left
391
479
            right: parent.right
392
480
            bottom: bottomPanel.top
398
486
        footer: Item {
399
487
            height: units.gu(2)
400
488
        }
401
 
        listModel: threadId !== "" ? sortProxy : null
 
489
        listModel: !newMessage ? sortProxy : null
402
490
        verticalLayoutDirection: ListView.BottomToTop
403
491
        spacing: units.gu(2)
404
492
        highlightFollowsCurrentItem: false
418
506
                    }
419
507
                }
420
508
            }
 
509
            onTriggerSelectionMode: {
 
510
                messageList.startSelection()
 
511
                clicked()
 
512
            }
421
513
 
422
514
            Component.onCompleted: {
423
515
                if (newEvent) {
447
539
    Item {
448
540
        id: bottomPanel
449
541
        anchors.bottom: keyboard.top
450
 
        anchors.bottomMargin: selectionMode ? 0 : units.gu(2)
451
542
        anchors.left: parent.left
452
543
        anchors.right: parent.right
453
 
        height: selectionMode ? 0 : textEntry.height + attachButton.height + units.gu(4)
 
544
        height: selectionMode ? 0 : textEntry.height + units.gu(2)
454
545
        visible: !selectionMode
455
546
        clip: true
456
547
 
461
552
        ListItem.ThinDivider {
462
553
            anchors.top: parent.top
463
554
        }
 
555
 
 
556
        Icon {
 
557
            id: attachButton
 
558
            anchors.left: parent.left
 
559
            anchors.leftMargin: units.gu(2)
 
560
            anchors.verticalCenter: sendButton.verticalCenter
 
561
            height: units.gu(3)
 
562
            width: units.gu(3)
 
563
            color: "gray"
 
564
            name: "camera"
 
565
        }
 
566
 
464
567
        TextArea {
465
568
            id: textEntry
466
 
            anchors.bottomMargin: units.gu(2)
467
 
            anchors.bottom: attachButton.top
468
 
            anchors.left: parent.left
469
 
            anchors.leftMargin: units.gu(2)
470
 
            anchors.right: parent.right
471
 
            anchors.rightMargin: units.gu(2)
472
 
            height: units.gu(5)
 
569
            anchors.bottomMargin: units.gu(1)
 
570
            anchors.bottom: parent.bottom
 
571
            anchors.left: attachButton.right
 
572
            anchors.leftMargin: units.gu(1)
 
573
            anchors.right: sendButton.left
 
574
            anchors.rightMargin: units.gu(1)
 
575
            height: units.gu(4)
473
576
            autoSize: true
 
577
            maximumLineCount: 0
474
578
            placeholderText: i18n.tr("Write a message...")
475
579
            focus: false
476
580
            font.family: "Ubuntu"
483
587
                }
484
588
            }
485
589
            Component.onCompleted: {
486
 
                if (messages.keyboardFocus && participants.length != 0) {
 
590
                // if page is active, it means this is not a bottom edge page
 
591
                if (messages.active && messages.keyboardFocus && participants.length != 0) {
487
592
                    textEntry.forceActiveFocus()
488
593
                }
489
594
            }
490
595
        }
491
596
 
492
597
        Button {
493
 
            id: attachButton
494
 
            anchors.left: parent.left
495
 
            anchors.leftMargin: units.gu(2)
 
598
            id: sendButton
 
599
            anchors.bottomMargin: units.gu(1)
496
600
            anchors.bottom: parent.bottom
497
 
            text: "Attach"
498
 
            width: units.gu(17)
499
 
            color: "gray"
500
 
            visible: false
501
 
        }
502
 
 
503
 
        Button {
504
601
            anchors.right: parent.right
505
602
            anchors.rightMargin: units.gu(2)
506
 
            anchors.bottom: parent.bottom
507
603
            text: "Send"
508
 
            width: units.gu(17)
 
604
            color: "green"
 
605
            width: units.gu(7)
509
606
            enabled: (textEntry.text != "" || textEntry.inputMethodComposing) && telepathyHelper.connected && (participants.length > 0 || multiRecipient.recipientCount > 0 )
510
607
            onClicked: {
511
608
                // make sure we flush everything we have prepared in the OSK preedit
513
610
                if (textEntry.text == "") {
514
611
                    return
515
612
                }
516
 
 
517
613
                if (participants.length == 0 && multiRecipient.recipientCount > 0) {
518
614
                    participants = multiRecipient.recipients
519
615
                }
520
 
 
521
616
                if (messages.accountId == "") {
522
617
                    // FIXME: handle dual sim
523
618
                    messages.accountId = telepathyHelper.accountIds[0]
524
619
                }
525
 
 
526
 
                if (messages.threadId == "") {
 
620
                if (messages.newMessage) {
527
621
                    // create the new thread and get the threadId
528
622
                    messages.threadId = eventModel.threadIdForParticipants(messages.accountId,
529
623
                                                                            HistoryThreadModel.EventTypeText,