Dekko
Loading...
Searching...
No Matches
RecipientField.qml
1/* Copyright (C) 2016 - 2017 Dan Chapman <dpniel@ubuntu.com>
2
3 This file is part of Dekko email client for Ubuntu devices
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of
8 the License or (at your option) version 3
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18import QtQuick 2.4
19import QuickFlux 1.0
20import Lomiri.Components 1.3
21import Lomiri.Components.Popups 1.3
22import Dekko.Components 1.0
23import Dekko.Mail 1.0
24import Dekko.Mail.API 1.0
25import Dekko.Mail.Stores.Composer 1.0
26import Dekko.Lomiri.Constants 1.0
27import Dekko.Lomiri.Components 1.0
28import "../delegates"
29
30FocusScope {
31 id: field
32
33 property int recipientType: RecipientType.To
34 property alias text: input.text
35 property alias textDocument: input.textDocument
36 property alias recipientModel: repeater.model
37 property bool isInvalidated: false
38
39 height: main.height
40
41 StretchRow {
42 anchors {
43 leftMargin: Style.smallSpacing
44 fill: parent
45 rightMargin: Style.smallSpacing
46 }
47 spacing: Style.smallSpacing
48 // Label to display our To, Cc, Bcc types
49 Label {
50 id: type
51 anchors {
52 left: parent.left
53 top: parent.top
54 leftMargin: Style.smallSpacing
55 topMargin: Style.smallSpacing
56 }
57 text: MailUtils.recipientTypeToString(recipientType) + ":"
58 }
59 // We want the recipient flow to take up all available space so use a stretcher
60 Stretcher {
61 id: main
62 height: flow.height
63 implicitHeight: height
64 // Use a flow here to show the RecipientInfo for already added contacts
65 // We use the flow to position the RecipientInput by placing it as the last item
66 // in the flow and taking up all width. This gives consistent spacing as contacts
67 // are added as well as we only have to resize the parent to flows height and not
68 // flow height + input height. 1 binding less... yay! heh
69 Flow {
70 id: flow
71 anchors {
72 left: parent.left
73 leftMargin: Style.smallSpacing
74 top: parent.top
75 topMargin: recipientModel.count ? (Style.smallSpacing / 2) : Style.smallSpacing
76 right: parent.right
77 }
78 spacing: Style.smallSpacing / 2
79 // Display the already added recipients
80 Repeater {
81 id: repeater
82 delegate: RecipientDelegate {
83 composeMode: true
84 type: recipientType
85 }
86 }
87 Item {
88 width: parent.width
89 height: units.gu(4)
90 clip: true
92 id: input
93 anchors {
94 left: parent.left
95 top: parent.top
96 right: parent.right
97 }
98 placeholderText: qsTr("Enter an address")
99 height: parent.height
100 onActiveFocusChanged: {
101 if (!activeFocus && input.text && !isInvalidated) {
102 Log.logInfo("RecipientFIeld::focusChanged", "Lost focus adding recipient")
103 ComposerActions.addRecipientIfValid(recipientType, input.text)
104 }
105
106 if (activeFocus && isInvalidated) {
107 isInvalidated = false
108 }
109 }
110
111 // We don't want to let the return/enter key events
112 // propogate to the textarea as it just moves to a new line
113 // whereas we want it to validate & commit the address to the
114 // recipients model. So we catch and accept the event here.
115 Keys.onReturnPressed: {
116 event.accepted = true
117 Log.logInfo("RecipientField::returnPressed", "Adding recipient");
118 ComposerActions.addRecipientIfValid(recipientType, input.text)
119 }
120 Keys.onEnterPressed: {
121 event.accepted = true
122 Log.logInfo("RecipientField::enterPressed", "Adding recipient");
123 ComposerActions.addRecipientIfValid(recipientType, input.text)
124 }
125 // We also support completion tokens. and is triggered
126 // when an address ends with ';' or ','
127 onCompletionTokenSeen: {
128 Log.logInfo("RecipientField::CompletionTokenSeen", "Adding recipient");
129 ComposerActions.addRecipientIfValid(recipientType, input.text)
130 }
131 }
132 }
133 }
134 }
135 // Finally the input field context actions button
137 id: ctxt
138 anchors {
139 right: parent.right
140 top: parent.top
141 topMargin: -units.gu(0.5)
142 }
143 visible: !ComposerStore.showCC || !ComposerStore.showBCC
144 height: units.gu(5)
145 width: units.gu(4)
146 implicitWidth: width
147 implicitHeight: height
148 iconSize: units.gu(2.25)
149 iconColor: LomiriColors.ash
150 action: Action {
151 iconSource: Paths.actionIconUrl(Icons.ContextMenuIcon)
152 onTriggered: PopupUtils.open(Qt.resolvedUrl("./RecipientInputContextMenu.qml"),
153 ctxt,
154 {
155 recipientType: field.recipientType
156 })
157 }
158 }
159 }
160 // Divider
161 Line {
162 anchors {
163 left: parent.left
164 bottom: parent.bottom
165 right: parent.right
166 }
167 }
168
169 AppScript {
170 runWhen: ComposerKeys.addRecipientIfValid
171 script: {
172 if (message.type === recipientType) {
173 ComposerActions.validateAddress(message.type, message.address)
174 } else {
175 exit.bind(this, 0)
176 return;
177 }
178 once(ComposerKeys.validAddress, function(message) {
179 Log.logInfo("RecipientField::validAddress", "Address is valid, adding to recipients")
180 isInvalidated = false
181 ComposerActions.addRecipientFromAddress(message.type, message.address)
182 input.text = ""
183 })
184 // Somethings not right. Show the invalid fields.
185 once(ComposerKeys.invalidAddress, function(message) {
186 Log.logInfo("RecipientField::invalidAddress", "Address invalid: %1".arg(message.address))
187 input.cursorPosition = input.length
188 isInvalidated = true
189 PopupActions.showError(PopupKeys.popupComposer, "Invalid email address: %1".arg(message.address))
190 })
191 }
192 }
193}
Definition main.qml:18