19import QtQuick.Controls.Suru 2.2
20import Lomiri.Components 1.3
22import Dekko.Mail.API 1.0
23import Dekko.Mail.Stores.Accounts 1.0
24import Dekko.Lomiri.Constants 1.0
35 property var invite: null
37 property int maxHeight: units.gu(40)
39 property var pickerRoot: null
41 readonly property bool active: invite !== null && (invite.valid || invite.loading)
42 property bool showDetails: false
44 property bool responding: false
46 function answer(response) {
51 invite.respond(response)
54 height: active ? Math.min(content.height, maxHeight) : 0
59 function shareIdentities() {
61 invite.identities = AccountStore.identities
68 Component.onCompleted: shareIdentities()
73 card.responding = false
74 ViewActions.orderSimpleToast(ViewKeys.toastMainWindow, qsTr("Your answer will be sent to the organizer."))
77 card.responding =
false
78 ViewActions.orderSimpleToast(ViewKeys.toastMainWindow, reason)
82 function statusText(status) {
85 return qsTr(
"Accepted")
87 return qsTr("Tentative")
89 return qsTr("Declined")
91 return qsTr("Delegated")
93 return qsTr("No answer yet")
98 if (!invite || !invite.valid) {
101 if (invite.cancelled) {
102 return qsTr(
"This event has been cancelled")
104 if (invite.method ===
"REPLY") {
105 switch (invite.replyStatus) {
107 return qsTr(
"%1 has accepted").arg(invite.replyFrom)
109 return qsTr(
"%1 has tentatively accepted").arg(invite.replyFrom)
111 return qsTr(
"%1 has declined").arg(invite.replyFrom)
113 return qsTr(
"Answer to an invitation")
115 switch (invite.response) {
117 return qsTr(
"You have accepted this invitation")
119 return qsTr("You have tentatively accepted this invitation")
121 return qsTr("You have declined this invitation")
123 if (invite.method === "REQUEST") {
124 return qsTr(
"Invitation from %1").arg(invite.organizerName)
131 color: Suru.secondaryBackgroundColor
137 contentHeight: content.height
138 interactive: content.height > card.height
139 boundsBehavior: Flickable.StopAtBounds
143 x:
Style.defaultSpacing
144 width: card.width - (2 *
Style.defaultSpacing)
145 spacing:
Style.smallSpacing
146 topPadding:
Style.smallSpacing
147 bottomPadding:
Style.smallSpacing
151 spacing:
Style.smallSpacing
152 visible: card.invite !== null && card.invite.loading
155 running: parent.visible
160 anchors.verticalCenter: parent.verticalCenter
161 text: qsTr(
"Loading invitation…")
167 height: Math.max(calendarIcon.height, titles.height)
168 visible: card.invite !== null && card.invite.valid
173 height:
Style.largeIconSize
175 color: Suru.foregroundColor
185 left: calendarIcon.right
186 leftMargin:
Style.smallSpacing
187 right: detailsToggle.left
188 rightMargin:
Style.smallSpacing
193 objectName:
"inviteHeadline"
195 text: card.headline()
197 color: card.invite && card.invite.cancelled ? Suru.highlightColor : Suru.secondaryForegroundColor
198 Suru.highlightType: Suru.NegativeHighlight
199 wrapMode: Text.WordWrap
202 objectName:
"inviteSummary"
204 text: card.invite ? card.invite.summary :
""
206 font.weight: Font.DemiBold
207 font.strikeout: card.invite ? card.invite.cancelled : false
208 wrapMode: Text.WordWrap
210 elide: Text.ElideRight
213 objectName:
"inviteWhen"
219 var t = card.invite.when
220 if (card.invite.allDay) {
221 t +=
" " + qsTr(
"(all day)")
223 if (card.invite.recurring) {
224 t +=
" " + qsTr(
"(repeats)")
228 wrapMode: Text.WordWrap
231 objectName:
"inviteLocation"
233 text: card.invite ? card.invite.location :
""
235 color: Suru.secondaryForegroundColor
236 wrapMode: Text.WordWrap
238 elide: Text.ElideRight
242 visible: card.invite !== null && card.invite.valid && !card.invite.timeZoneKnown
244 ? qsTr(
"The time zone \"%1\" is not known, the time shown may be wrong.").arg(card.invite.timeZoneId)
247 color: Suru.highlightColor
248 Suru.highlightType: Suru.NegativeHighlight
249 wrapMode: Text.WordWrap
255 objectName:
"inviteDetailsToggle"
262 onClicked: card.showDetails = !card.showDetails
265 anchors.centerIn: parent
266 name: card.showDetails ?
"up" :
"down"
267 height:
Style.defaultIconSize
269 color: Suru.foregroundColor
277 spacing: units.gu(0.5)
278 visible: card.showDetails && card.invite !== null && card.invite.valid
282 visible: card.invite !== null && card.invite.organizerEmail !==
""
283 text: card.invite ? qsTr(
"Organizer: %1").arg(
284 card.invite.organizerName === card.invite.organizerEmail
285 ? card.invite.organizerEmail
286 : card.invite.organizerName +
" <" + card.invite.organizerEmail +
">")
288 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
293 visible: attendeeList.count > 0
294 text: qsTr(
"Invited:")
295 color: Suru.secondaryForegroundColor
300 model: card.showDetails && card.invite ? card.invite.attendees : []
303 height: Math.max(attendeeName.height, attendeeStatus.height)
309 leftMargin:
Style.smallSpacing
310 right: attendeeStatus.left
311 rightMargin:
Style.smallSpacing
313 text: modelData.isSelf ? qsTr(
"%1 (you)").arg(modelData.name) : modelData.name
314 elide: Text.ElideRight
318 anchors.right: parent.right
319 text: modelData.isOrganizer ? qsTr(
"Organizer") : card.statusText(modelData.status)
321 color: Suru.secondaryForegroundColor
329 text: card.invite ? card.invite.description :
""
330 textFormat: Text.PlainText
331 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
333 elide: Text.ElideRight
339 spacing:
Style.smallSpacing
340 visible: card.invite !== null && card.invite.valid
343 objectName:
"inviteAccept"
344 visible: card.invite !== null && card.invite.canRespond
346 color: card.invite && card.invite.response ===
"ACCEPTED" ? theme.palette.normal.positive
347 : theme.palette.normal.foreground
348 enabled: !card.responding
349 onClicked: card.answer(CalendarInvite.Accepted)
352 objectName:
"inviteTentative"
353 visible: card.invite !== null && card.invite.canRespond
355 color: card.invite && card.invite.response ===
"TENTATIVE" ? theme.palette.normal.activity
356 : theme.palette.normal.foreground
357 enabled: !card.responding
358 onClicked: card.answer(CalendarInvite.Tentative)
361 objectName:
"inviteDecline"
362 visible: card.invite !== null && card.invite.canRespond
363 text: qsTr(
"Decline")
364 color: card.invite && card.invite.response ===
"DECLINED" ? theme.palette.normal.negative
365 : theme.palette.normal.foreground
366 enabled: !card.responding
367 onClicked: card.answer(CalendarInvite.Declined)
370 objectName:
"inviteExport"
371 visible: card.invite !== null && !card.invite.cancelled && card.invite.method !==
"REPLY"
372 text: qsTr(
"Add to calendar")
373 color: theme.palette.normal.foreground
375 const file = card.invite.saveToFile()
377 ViewActions.orderSimpleToast(ViewKeys.toastMainWindow, qsTr(
"The invitation could not be saved."))
380 const url =
"file://" + file
381 if (isRunningOnMir) {
382 ContentActions.exportFile(card.pickerRoot, url)
384 Qt.openUrlExternally(url)
396 bottom: parent.bottom
398 height:
Style.lineSize
399 color:
Style.lineColor