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 }