Kirigami2

AboutItem.qml
1/*
2 * SPDX-FileCopyrightText: 2018 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3 * SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8import QtQuick
9import QtQuick.Controls as QQC2
10import QtQuick.Layouts
11import org.kde.kirigami as Kirigami
12
13//TODO: Kf6: move somewhere else which can depend from KAboutData?
14/**
15 * @brief An about item that displays the about data
16 *
17 * Allows to show the copyright notice of the application
18 * together with the contributors and some information of which platform it's
19 * running on.
20 *
21 * @since 5.87
22 * @since org.kde.kirigami 2.19
23 */
24Item {
25 id: aboutItem
26 /**
27 * @brief This property holds an object with the same shape as KAboutData.
28 *
29 * Example usage:
30 * @code{json}
31 * aboutData: {
32 "displayName" : "KirigamiApp",
33 "productName" : "kirigami/app",
34 "componentName" : "kirigamiapp",
35 "shortDescription" : "A Kirigami example",
36 "homepage" : "",
37 "bugAddress" : "submit@bugs.kde.org",
38 "version" : "5.14.80",
39 "otherText" : "",
40 "authors" : [
41 {
42 "name" : "...",
43 "task" : "",
44 "emailAddress" : "somebody@kde.org",
45 "webAddress" : "",
46 "ocsUsername" : ""
47 }
48 ],
49 "credits" : [],
50 "translators" : [],
51 "licenses" : [
52 {
53 "name" : "GPL v2",
54 "text" : "long, boring, license text",
55 "spdx" : "GPL-2.0"
56 }
57 ],
58 "copyrightStatement" : "© 2010-2018 Plasma Development Team",
59 "desktopFileName" : "org.kde.kirigamiapp"
60 }
61 @endcode
62 *
63 * @see KAboutData
64 */
65 property var aboutData
66
67 /**
68 * @brief This property holds a link to a "Get Involved" page.
69 *
70 * default: `"https://community.kde.org/Get_Involved" when application id starts with "org.kde.", otherwise it is empty.`
71 */
72 property url getInvolvedUrl: aboutData.desktopFileName.startsWith("org.kde.") ? "https://community.kde.org/Get_Involved" : ""
73
74 /**
75 * @brief This property holds a link to a "Donate" page.
76 *
77 * default: `"https://kde.org/community/donations" when application id starts with "org.kde.", otherwise it is empty.`
78 */
79 property url donateUrl: aboutData.desktopFileName.startsWith("org.kde.") ? "https://kde.org/community/donations" : ""
81 /** @internal */
82 property bool _usePageStack: false
83
84 /**
85 * @see org::kde::kirigami::FormLayout::wideMode
86 * @property bool wideMode
87 */
88 property alias wideMode: form.wideMode
89
90 /** @internal */
91 default property alias _content: form.data
92
93 // if aboutData is a native KAboutData object, avatarUrl should be a proper url instance,
94 // otherwise if it was defined as a string in pure JavaScript it should work too.
95 readonly property bool __hasAvatars: aboutItem.aboutData.authors.some(__hasAvatar)
96
97 function __hasAvatar(person): bool {
98 return typeof person.avatarUrl !== "undefined"
99 && person.avatarUrl.toString().length > 0;
100 }
101
102 /**
103 * @brief This property controls whether to load avatars by URL.
104 *
105 * If set to false, a fallback "user" icon will be displayed.
106 *
107 * default: ``false``
108 */
109 property bool loadAvatars: false
110
111 implicitHeight: form.implicitHeight
112 implicitWidth: form.implicitWidth
113
114 Component {
115 id: personDelegate
116
117 RowLayout {
118 id: delegate
119
120 // type: KAboutPerson | { name?, task?, emailAddress?, webAddress?, avatarUrl? }
121 required property var modelData
122
123 property bool hasAvatar: aboutItem.__hasAvatar(modelData)
124
125 Layout.fillWidth: true
126
127 spacing: Kirigami.Units.smallSpacing * 2
128
129 Kirigami.Icon {
130 id: avatarIcon
131
132 implicitWidth: Kirigami.Units.iconSizes.medium
133 implicitHeight: implicitWidth
134
135 fallback: "user"
136 source: {
137 if (delegate.hasAvatar && aboutItem.loadAvatars) {
138 // Appending to the params of the url does not work, thus the search is set
139 const url = new URL(modelData.avatarUrl);
140 const params = new URLSearchParams(url.search);
141 params.append("s", width);
142 url.search = params.toString();
143 return url;
144 } else {
145 return "user"
146 }
147 }
148 visible: status !== Kirigami.Icon.Loading
149 }
150
151 // So it's clear that something is happening while avatar images are loaded
152 QQC2.BusyIndicator {
153 implicitWidth: Kirigami.Units.iconSizes.medium
154 implicitHeight: implicitWidth
155
156 visible: avatarIcon.status === Kirigami.Icon.Loading
157 running: visible
158 }
159
160 QQC2.Label {
161 Layout.fillWidth: true
162 readonly property bool withTask: typeof(modelData.task) !== "undefined" && modelData.task.length > 0
163 text: withTask ? qsTr("%1 (%2)").arg(modelData.name).arg(modelData.task) : modelData.name
164 wrapMode: Text.WordWrap
165 }
166
167 QQC2.ToolButton {
168 visible: typeof(modelData.emailAddress) !== "undefined" && modelData.emailAddress.length > 0
169 icon.name: "mail-sent"
170 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
171 QQC2.ToolTip.visible: hovered
172 QQC2.ToolTip.text: qsTr("Send an email to %1").arg(modelData.emailAddress)
173 onClicked: Qt.openUrlExternally("mailto:%1".arg(modelData.emailAddress))
174 }
175
176 QQC2.ToolButton {
177 visible: typeof(modelData.webAddress) !== "undefined" && modelData.webAddress.length > 0
178 icon.name: "globe"
179 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
180 QQC2.ToolTip.visible: hovered
181 QQC2.ToolTip.text: (typeof(modelData.webAddress) === "undefined" && modelData.webAddress.length > 0) ? "" : modelData.webAddress
182 onClicked: Qt.openUrlExternally(modelData.webAddress)
183 }
184 }
185 }
186
187 Kirigami.FormLayout {
188 id: form
189
190 anchors.fill: parent
191
192 GridLayout {
193 columns: 2
194 Layout.fillWidth: true
195
196 Kirigami.Icon {
197 Layout.rowSpan: 3
198 Layout.preferredHeight: Kirigami.Units.iconSizes.huge
199 Layout.preferredWidth: height
200 Layout.maximumWidth: aboutItem.width / 3;
201 Layout.rightMargin: Kirigami.Units.largeSpacing
202 source: Kirigami.Settings.applicationWindowIcon || aboutItem.aboutData.programLogo || aboutItem.aboutData.programIconName || aboutItem.aboutData.componentName
203 }
204
205 Kirigami.Heading {
206 Layout.fillWidth: true
207 text: aboutItem.aboutData.displayName + " " + aboutItem.aboutData.version
208 wrapMode: Text.WordWrap
209 }
210
211 Kirigami.Heading {
212 Layout.fillWidth: true
213 level: 2
214 wrapMode: Text.WordWrap
215 text: aboutItem.aboutData.shortDescription
216 }
217
218 RowLayout {
219 spacing: Kirigami.Units.largeSpacing * 2
220
221 UrlButton {
222 text: qsTr("Get Involved")
223 url: aboutItem.getInvolvedUrl
224 visible: url.toString().length > 0
225 }
226
227 UrlButton {
228 text: qsTr("Donate")
229 url: aboutItem.donateUrl
230 visible: url.toString().length > 0
231 }
232
233 UrlButton {
234 readonly property string theUrl: {
235 if (aboutItem.aboutData.bugAddress !== "submit@bugs.kde.org") {
236 return aboutItem.aboutData.bugAddress
237 }
238 const elements = aboutItem.aboutData.productName.split('/');
239 let url = `https://bugs.kde.org/enter_bug.cgi?format=guided&product=${elements[0]}&version=${aboutItem.aboutData.version}`;
240 if (elements.length === 2) {
241 url += "&component=" + elements[1];
242 }
243 return url;
244 }
245 text: qsTr("Report a Bug")
246 url: theUrl
247 visible: theUrl.toString().length > 0
248 }
249 }
250 }
251
252 Separator {
253 Layout.fillWidth: true
254 }
255
256 Kirigami.Heading {
257 Kirigami.FormData.isSection: true
258 text: qsTr("Copyright")
259 }
260
261 QQC2.Label {
262 Layout.leftMargin: Kirigami.Units.gridUnit
263 text: aboutItem.aboutData.otherText
264 visible: text.length > 0
265 wrapMode: Text.WordWrap
266 Layout.fillWidth: true
267 }
268
269 QQC2.Label {
270 Layout.leftMargin: Kirigami.Units.gridUnit
271 text: aboutItem.aboutData.copyrightStatement
272 visible: text.length > 0
273 wrapMode: Text.WordWrap
274 Layout.fillWidth: true
275 }
276
277 UrlButton {
278 Layout.leftMargin: Kirigami.Units.gridUnit
279 url: aboutItem.aboutData.homepage
280 visible: url.length > 0
281 wrapMode: Text.WordWrap
282 Layout.fillWidth: true
283 }
284
286 id: licenseSheet
287 property alias text: bodyLabel.text
288
289 contentItem: SelectableLabel {
290 id: bodyLabel
291 text: licenseSheet.text
292 wrapMode: Text.Wrap
293 }
294 }
295
296 Component {
297 id: licenseLinkButton
298
299 RowLayout {
300 Layout.leftMargin: Kirigami.Units.smallSpacing
301
302 QQC2.Label { text: qsTr("License:") }
303
304 LinkButton {
305 Layout.fillWidth: true
306 wrapMode: Text.WordWrap
307 text: modelData.name
308 onClicked: mouse => {
309 licenseSheet.text = modelData.text
310 licenseSheet.title = modelData.name
311 licenseSheet.open()
312 }
313 }
314 }
315 }
316
317 Component {
318 id: licenseTextItem
319
320 QQC2.Label {
321 Layout.leftMargin: Kirigami.Units.smallSpacing
322 Layout.fillWidth: true
323 wrapMode: Text.WordWrap
324 text: qsTr("License: %1").arg(modelData.name)
325 }
326 }
327
328 Repeater {
329 model: aboutItem.aboutData.licenses
330 delegate: _usePageStack ? licenseLinkButton : licenseTextItem
331 }
332
333 Kirigami.Heading {
334 Kirigami.FormData.isSection: visible
335 text: qsTr("Libraries in use")
336 Layout.fillWidth: true
337 wrapMode: Text.WordWrap
338 visible: Kirigami.Settings.information
339 }
340
341 Repeater {
342 model: Kirigami.Settings.information
343 delegate: QQC2.Label {
344 Layout.leftMargin: Kirigami.Units.gridUnit
345 Layout.fillWidth: true
346 wrapMode: Text.WordWrap
347 id: libraries
348 text: modelData
349 }
350 }
351
352 Repeater {
353 model: aboutItem.aboutData.components
354 delegate: QQC2.Label {
355 Layout.fillWidth: true
356 wrapMode: Text.WordWrap
357 Layout.leftMargin: Kirigami.Units.gridUnit
358 text: modelData.name + (modelData.version.length === 0 ? "" : " %1".arg(modelData.version))
359 }
360 }
361
362 Kirigami.Heading {
363 Layout.fillWidth: true
364 Kirigami.FormData.isSection: visible
365 text: qsTr("Authors")
366 wrapMode: Text.WordWrap
367 visible: aboutItem.aboutData.authors.length > 0
368 }
369
370 QQC2.CheckBox {
371 id: remoteAvatars
372 visible: aboutItem.__hasAvatars
373 checked: aboutItem.loadAvatars
374 onToggled: aboutItem.loadAvatars = checked
375 text: qsTr("Show author photos")
376 }
377
378 Repeater {
379 id: authorsRepeater
380 model: aboutItem.aboutData.authors
381 delegate: personDelegate
382 }
383
384 Kirigami.Heading {
385 Kirigami.FormData.isSection: visible
386 text: qsTr("Credits")
387 visible: repCredits.count > 0
388 }
389
390 Repeater {
391 id: repCredits
392 model: aboutItem.aboutData.credits
393 delegate: personDelegate
394 }
395
396 Kirigami.Heading {
397 Kirigami.FormData.isSection: visible
398 text: qsTr("Translators")
399 visible: repTranslators.count > 0
400 }
401
402 Repeater {
403 id: repTranslators
404 model: aboutItem.aboutData.translators
405 delegate: personDelegate
406 }
407 }
408}
A button that looks like a link.
An overlay sheet that covers the current Page content.
This is a label which supports text selection.
A visual separator.
Definition Separator.qml:16
A link button that contains a URL.
Definition UrlButton.qml:20
Q_SCRIPTABLE CaptureState status()
QStringView level(QStringView ifopt)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 1 2024 18:46:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.