Warning, /network/tokodon/src/content/ui/ModerationTools/MainReportToolPage.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2023 Rishi Kumar <rsi.dev17@gmail.com> 0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0003 0004 import QtQuick 0005 import QtQuick.Controls 2 as QQC2 0006 import QtQuick.Layouts 0007 import org.kde.kirigami 2 as Kirigami 0008 import org.kde.tokodon 0009 import org.kde.tokodon.private 0010 import org.kde.kirigamiaddons.formcard 1 as FormCard 0011 import org.kde.kirigamiaddons.components 1 as KirigamiComponents 0012 import Qt5Compat.GraphicalEffects 0013 import "../StatusDelegate" 0014 0015 Kirigami.ScrollablePage { 0016 id: root 0017 0018 property var reportInfo 0019 property int index 0020 property var model 0021 property var arr: [] 0022 property bool isInitial: true 0023 property bool trigger: false 0024 readonly property bool isAssignedModeratorSelectedAccount: root.reportInfo.assignedModerator ? root.reportInfo.assignedAccount.userLevelIdentity.id === AccountManager.selectedAccountId : false 0025 readonly property bool assignedModerator: root.reportInfo.assignedAccount 0026 property bool displayAttachmentPanel: root.reportInfo.statusCount || root.reportInfo.mediaAttachmentCount 0027 0028 function isChecked(ruleId) { 0029 for (var i = 0; i < root.reportInfo.rules.length; i++) { 0030 if (ruleId === root.reportInfo.rules[i].id) { 0031 arr.push(ruleId) 0032 return true; 0033 } 0034 } 0035 return false; 0036 } 0037 0038 function ammendOrDelete(inp) { 0039 var index = arr.indexOf(inp); 0040 if (index !== -1) { 0041 arr.splice(index, 1); 0042 } else { 0043 arr.push(inp); 0044 } 0045 } 0046 0047 title: i18n("Report #%1", root.reportInfo.reportId) 0048 0049 actions: Kirigami.Action { 0050 icon.name: root.reportInfo.actionTaken ? "edit-delete-remove" : "checkmark" 0051 text: root.reportInfo.actionTaken ? i18n("Mark as unresolved") : i18n("Mark as resolved") 0052 onTriggered: { 0053 if (root.reportInfo.actionTaken) { 0054 root.model.unresolveReport(root.index) 0055 showPassiveNotification(i18n("Report Unresolved")) 0056 } else { 0057 root.model.resolveReport(root.index) 0058 showPassiveNotification(i18n("Report Resolved")) 0059 } 0060 } 0061 } 0062 0063 data: RulesModel { 0064 id: rulesModel 0065 account: AccountManager.selectedAccount 0066 } 0067 0068 ColumnLayout { 0069 id: profileInfo 0070 0071 FormCard.FormCard { 0072 Layout.topMargin: Kirigami.Units.largeSpacing 0073 Layout.fillWidth: true 0074 0075 Rectangle { 0076 Layout.preferredHeight: Kirigami.Units.gridUnit * 9 0077 Layout.fillWidth: true 0078 clip: true 0079 color: Kirigami.Theme.backgroundColor 0080 Kirigami.Theme.colorSet: Kirigami.Theme.View 0081 0082 Image { 0083 id: bg 0084 anchors.centerIn: parent 0085 source: root.reportInfo.targetAccount.userLevelIdentity.backgroundUrl 0086 fillMode: Image.PreserveAspectFit 0087 visible: true 0088 } 0089 0090 QQC2.Pane { 0091 id: pane 0092 visible: true 0093 background: Item { 0094 FastBlur { 0095 id: blur 0096 source: bg 0097 radius: 48 0098 width: pane.width 0099 height: pane.height 0100 } 0101 ColorOverlay { 0102 width: pane.width 0103 height: pane.height 0104 source: blur 0105 color: "#66808080" 0106 } 0107 Rectangle { 0108 id: strip 0109 color: "#66F0F0F0" 0110 anchors.bottom: parent.bottom; 0111 height: 2 * Kirigami.Units.gridUnit 0112 width: parent.width 0113 visible: children.length > 0 0114 } 0115 } 0116 anchors.left: parent.left 0117 anchors.bottom: parent.bottom; 0118 anchors.right: parent.right 0119 contentItem: 0120 ColumnLayout { 0121 spacing: 0 0122 0123 RowLayout { 0124 implicitHeight: Kirigami.Units.gridUnit * 5 0125 KirigamiComponents.Avatar { 0126 source: root.reportInfo.targetAccount.userLevelIdentity.avatarUrl 0127 } 0128 0129 Column { 0130 Layout.fillWidth: true 0131 Kirigami.Heading { 0132 level: 5 0133 text: root.reportInfo.targetAccount.userLevelIdentity.username 0134 type: Kirigami.Heading.Primary 0135 } 0136 QQC2.Label { 0137 text: "@" + root.reportInfo.targetAccount.userLevelIdentity.account 0138 } 0139 } 0140 } 0141 } 0142 } 0143 } 0144 0145 Kirigami.Separator { 0146 Layout.fillWidth: true 0147 } 0148 0149 RowLayout { 0150 visible: root.reportInfo.targetAccount.userLevelIdentity.bio 0151 spacing: 0 0152 QQC2.Pane { 0153 contentItem: QQC2.Label { 0154 text: i18nc("@info Bio label of account.", "Bio") 0155 wrapMode: Text.Wrap 0156 } 0157 Layout.minimumWidth: Kirigami.Units.gridUnit * 10 0158 Layout.maximumWidth: Kirigami.Units.gridUnit * 10 0159 Kirigami.Theme.colorSet: Kirigami.Theme.View 0160 leftPadding: Kirigami.Units.largeSpacing 0161 rightPadding: Kirigami.Units.largeSpacing 0162 bottomPadding: 0 0163 topPadding: 0 0164 } 0165 0166 QQC2.TextArea { 0167 text: root.reportInfo.targetAccount.userLevelIdentity.bio 0168 textFormat: TextEdit.RichText 0169 readOnly: true 0170 Layout.fillWidth: true 0171 Layout.leftMargin: Kirigami.Units.largeSpacing 0172 Layout.rightMargin: Kirigami.Units.largeSpacing 0173 Layout.topMargin: Kirigami.Units.smallSpacing 0174 Layout.bottomMargin: Kirigami.Units.smallSpacing 0175 leftPadding: 0 0176 rightPadding: 0 0177 bottomPadding: 0 0178 topPadding: 0 0179 background: null 0180 wrapMode: TextEdit.Wrap 0181 onLinkActivated: Qt.openUrlExternally(link) 0182 MouseArea { 0183 anchors.fill: parent 0184 acceptedButtons: Qt.NoButton // don't eat clicks on the Text 0185 cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor 0186 } 0187 } 0188 } 0189 0190 Kirigami.Separator { 0191 Layout.fillWidth: true 0192 } 0193 } 0194 0195 FormCard.FormGridContainer { 0196 id: container 0197 0198 Layout.topMargin: Kirigami.Units.largeSpacing 0199 Layout.fillWidth: true 0200 0201 infoCards: [ 0202 FormCard.FormGridContainer.InfoCard { 0203 title: root.reportInfo.targetAccount.userLevelIdentity.statusesCount 0204 subtitle: i18nc("@info Number of Posts", "Posts") 0205 }, 0206 FormCard.FormGridContainer.InfoCard { 0207 title: root.reportInfo.targetAccount.userLevelIdentity.followersCount 0208 subtitle: i18nc("@info Number of followers.", "Followers") 0209 }, 0210 FormCard.FormGridContainer.InfoCard { 0211 title: root.reportInfo.targetAccount.userLevelIdentity.followingCount 0212 subtitle: i18nc("@info Row Number of accounts followed by the account", "Following") 0213 }, 0214 FormCard.FormGridContainer.InfoCard { 0215 title: root.reportInfo.targetAccount.joined.toLocaleString() 0216 subtitle: i18nc("@info Time at which the reported account joined.", "Joined") 0217 }, 0218 FormCard.FormGridContainer.InfoCard { 0219 title: root.reportInfo.targetAccount.lastActive.toLocaleString() 0220 subtitle: i18nc("@info The last time the reported account was active.", "Last Active") 0221 }, 0222 FormCard.FormGridContainer.InfoCard { 0223 title: root.reportInfo.createdAt.toLocaleString() 0224 subtitle: i18nc("@info The current login status of the account.", "Reported") 0225 } 0226 ] 0227 } 0228 0229 FormCard.FormCard { 0230 Layout.topMargin: Kirigami.Units.largeSpacing 0231 Layout.fillWidth: true 0232 visible: true 0233 0234 FormCard.FormTextDelegate { 0235 visible: true 0236 text: i18nc("@info Time at which the report was made", "Reported") 0237 description: root.reportInfo.createdAt.toLocaleString() 0238 } 0239 0240 FormCard.FormDelegateSeparator {} 0241 0242 FormCard.FormTextDelegate { 0243 visible: root.reportInfo.filedAccount 0244 text: i18n("Reported By") 0245 description: root.reportInfo.filedAccount.userLevelIdentity.account 0246 0247 leadingPadding: Kirigami.Units.largeSpacing 0248 leading: KirigamiComponents.Avatar { 0249 source: root.reportInfo.filedAccount.userLevelIdentity.avatarUrl 0250 implicitHeight: Kirigami.Units.gridUnit * 2 0251 implicitWidth: Kirigami.Units.gridUnit * 2 0252 } 0253 } 0254 0255 FormCard.FormDelegateSeparator {} 0256 0257 FormCard.FormTextDelegate { 0258 visible: true 0259 text: i18n("Report Status") 0260 description: root.reportInfo.actionTaken ? i18n("Resolved") : i18n("Unresolved") 0261 } 0262 0263 FormCard.FormDelegateSeparator {} 0264 0265 FormCard.FormTextDelegate { 0266 visible: root.reportInfo.actionTakenByAccount.userLevelIdentity.account 0267 text: i18n("Action taken by") 0268 description: root.reportInfo.actionTakenByAccount.userLevelIdentity.account 0269 leadingPadding: Kirigami.Units.largeSpacing 0270 leading: KirigamiComponents.Avatar { 0271 source: root.reportInfo.actionTakenByAccount.userLevelIdentity.avatarUrl 0272 implicitHeight: Kirigami.Units.gridUnit * 2 0273 implicitWidth: Kirigami.Units.gridUnit * 2 0274 } 0275 } 0276 0277 FormCard.FormDelegateSeparator {} 0278 0279 FormCard.FormTextDelegate { 0280 text: i18n("Assigned moderator") 0281 description: root.reportInfo.assignedModerator ? root.reportInfo.assignedAccount.userLevelIdentity.account : i18n("No one") 0282 leadingPadding: Kirigami.Units.largeSpacing 0283 leading: KirigamiComponents.Avatar { 0284 source: root.reportInfo.assignedModerator ? root.reportInfo.assignedAccount.userLevelIdentity.avatarUrl : "" 0285 implicitHeight: Kirigami.Units.gridUnit * 2 0286 implicitWidth: Kirigami.Units.gridUnit * 2 0287 } 0288 trailing: QQC2.Button { 0289 text: assignedModerator ? (isAssignedModeratorSelectedAccount ? i18n("Unassign") : i18n("Assign to me")) : i18n("Assign to me") 0290 icon.name: "im-user" 0291 onClicked: assignedModerator ? (isAssignedModeratorSelectedAccount ? root.model.unassignReport(root.index) : root.model.assignReport(root.index)) : root.model.assignReport(root.index) 0292 } 0293 } 0294 0295 FormCard.FormDelegateSeparator {} 0296 0297 FormCard.FormTextDelegate { 0298 visible: !root.reportInfo.targetAccount.isLocal 0299 text: i18n("Forwarded") 0300 description: root.reportInfo.forwarded ? i18nc("@info:The report is forwarded", "Yes") : i18nc("@info:The report is not forwarded", "No") 0301 } 0302 } 0303 0304 FormCard.FormCard { 0305 Layout.topMargin: Kirigami.Units.largeSpacing 0306 Layout.fillWidth: true 0307 0308 FormCard.FormHeader { 0309 title: i18n("Category") 0310 } 0311 0312 QQC2.Label { 0313 text: i18n("The reason this account and/or content was reported will be cited in communication with the reported account") 0314 Layout.fillWidth: true 0315 wrapMode: Text.Wrap 0316 Layout.leftMargin: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0317 Layout.rightMargin: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0318 Layout.bottomMargin: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0319 } 0320 0321 FormCard.FormDelegateSeparator {} 0322 0323 FormCard.FormRadioDelegate { 0324 id: other 0325 text: i18n("Other") 0326 checked: root.reportInfo.category === "other" 0327 onCheckedChanged: if (checked && !isInitial) { 0328 arr = [] 0329 root.model.updateReport(index, "other", arr) 0330 showPassiveNotification(i18n("Category changed to other")) 0331 } else { 0332 isInitial = false 0333 } 0334 } 0335 0336 FormCard.FormDelegateSeparator { below: other ; above: spam } 0337 0338 FormCard.FormRadioDelegate { 0339 id: spam 0340 checked: root.reportInfo.category === "spam" 0341 text: i18n("Spam") 0342 onCheckedChanged: if (checked && !isInitial) { 0343 arr = [] 0344 root.model.updateReport(index, "spam", arr) 0345 showPassiveNotification(i18n("Category changed to spam")) 0346 } else { 0347 isInitial = false 0348 } 0349 } 0350 0351 FormCard.FormDelegateSeparator { below: spam } 0352 0353 FormCard.FormRadioDelegate { 0354 id: serverRules 0355 checked: root.reportInfo.category === "violation" 0356 text: i18n("Content violates one or more server rules") 0357 onCheckedChanged: if (checked && !isInitial) { 0358 arr = [] 0359 root.model.updateReport(index, "violation", arr) 0360 showPassiveNotification(i18n("Category changed to rule violation")) 0361 } else { 0362 isInitial = false 0363 } 0364 } 0365 0366 Repeater { 0367 id: rulesList 0368 0369 model: serverRules.checked ? rulesModel : [] 0370 0371 delegate: ColumnLayout { 0372 id: ruleLayout 0373 0374 required property int index 0375 required property string text 0376 required property string id 0377 0378 spacing: 0 0379 FormCard.FormCheckDelegate { 0380 id: ruleLabel 0381 focusPolicy: Qt.NoFocus 0382 hoverEnabled: false 0383 Layout.leftMargin: Kirigami.Units.largeSpacing * 4 0384 text: ruleLayout.text 0385 checked: isChecked(ruleLayout.id) 0386 Component.onCompleted: if (ruleLayout.index === rulesList.model.length -1) { 0387 root.trigger = true 0388 } 0389 onCheckedChanged: if (root.trigger) { 0390 ammendOrDelete(ruleLayout.id) 0391 root.model.updateReport(ruleLayout.index, "violation", arr) 0392 } 0393 } 0394 } 0395 } 0396 } 0397 0398 FormCard.FormCard { 0399 Layout.topMargin: Kirigami.Units.largeSpacing 0400 Layout.fillWidth: true 0401 0402 FormCard.FormHeader { 0403 title: i18n("To provide more information, %1 wrote:", root.reportInfo.filedAccount.userLevelIdentity.account) 0404 } 0405 0406 FormCard.FormTextDelegate { 0407 visible: true 0408 text: root.reportInfo.filedAccount.userLevelIdentity.account 0409 trailing: QQC2.Label { 0410 text: root.reportInfo.createdAt.toLocaleDateString() 0411 } 0412 description: root.reportInfo.comment ? root.reportInfo.comment : i18nc("@info:Account didn't provide any comment on the report ","N/A") 0413 leadingPadding: Kirigami.Units.largeSpacing 0414 leading: KirigamiComponents.Avatar { 0415 source: root.reportInfo.filedAccount.userLevelIdentity.avatarUrl 0416 implicitHeight: Kirigami.Units.gridUnit * 2 0417 implicitWidth: Kirigami.Units.gridUnit * 2 0418 } 0419 } 0420 } 0421 0422 FormCard.FormCard { 0423 Layout.topMargin: Kirigami.Units.largeSpacing 0424 Layout.fillWidth: true 0425 visible: root.displayAttachmentPanel 0426 0427 FormCard.FormHeader { 0428 title: i18n("Reported Content") 0429 } 0430 0431 QQC2.Label { 0432 text: i18n("Offending content will be cited in communication with the reported account") 0433 Layout.leftMargin: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0434 Layout.rightMargin: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0435 Layout.bottomMargin: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0436 } 0437 0438 FormCard.FormDelegateSeparator {} 0439 0440 Repeater { 0441 id: statusList 0442 model: root.reportInfo.reportStatus 0443 0444 delegate: ColumnLayout { 0445 required property var modelData 0446 spacing: 0 0447 Layout.fillWidth: true 0448 Layout.bottomMargin: Kirigami.Units.largeSpacing 0449 Layout.topMargin: Kirigami.Units.largeSpacing 0450 Layout.leftMargin: Kirigami.Units.gridUnit 0451 Layout.rightMargin: Kirigami.Units.gridUnit 0452 0453 RowLayout { 0454 Layout.preferredHeight: spoilerTextLabel.contentHeight + Kirigami.Units.gridUnit * 2 0455 visible: modelData.spoilerText.length !== 0 0456 Kirigami.Icon { 0457 Layout.alignment: Qt.AlignVCenter 0458 source: "data-warning" 0459 } 0460 QQC2.Label { 0461 id: spoilerTextLabel 0462 Layout.fillWidth: true 0463 text: i18n("<b>Content Warning</b><br /> %1", modelData.spoilerText) 0464 wrapMode: Text.Wrap 0465 font: Config.defaultFont 0466 0467 } 0468 QQC2.Button { 0469 text: postContent.visible ? i18n("Show Less") : i18n("Show More") 0470 onClicked: postContent.visible = !postContent.visible 0471 } 0472 } 0473 0474 PostContent { 0475 id: postContent 0476 content: modelData.content 0477 expandedPost: false 0478 secondary: false 0479 visible: modelData.spoilerText.length === 0 || AccountManager.selectedAccount.preferences.extendSpoiler 0480 shouldOpenInternalLinks: false 0481 } 0482 0483 AttachmentGrid { 0484 expandedPost: false 0485 attachments: modelData.attachments 0486 identity: modelData.authorIdentity 0487 sensitive: true 0488 secondary: false 0489 inViewPort: true 0490 visible: postContent.visible && modelData.attachments.length > 0 0491 } 0492 0493 Item { 0494 height: modelData.selected || Kirigami.Settings.tabletMode ? Kirigami.Units.mediumSpacing : Kirigami.Units.smallSpacing 0495 } 0496 0497 RowLayout { 0498 visible: true 0499 QQC2.Label { 0500 text: modelData.absoluteTime 0501 elide: Text.ElideRight 0502 color: Kirigami.Theme.disabledTextColor 0503 } 0504 } 0505 } 0506 } 0507 } 0508 } 0509 }