Add popup to edit push rules
This commit is contained in:
71
src/gui/Base/HSpinBox.qml
Normal file
71
src/gui/Base/HSpinBox.qml
Normal file
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
SpinBox {
|
||||
id: box
|
||||
|
||||
property var defaultValue: null
|
||||
readonly property bool changed: value !== (defaultValue || 0)
|
||||
|
||||
function reset() { value = Qt.binding(() => defaultValue || 0) }
|
||||
|
||||
|
||||
// XXX TODO: default binding break
|
||||
value: defaultValue || 0
|
||||
implicitHeight: theme.baseElementsHeight
|
||||
padding: 0
|
||||
editable: true
|
||||
|
||||
background: null
|
||||
|
||||
contentItem: HTextField {
|
||||
id: textField
|
||||
height: parent.height
|
||||
implicitWidth: 90 * theme.uiScale
|
||||
radius: 0
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
// FIXME
|
||||
text: box.textFromValue(box.value, box.locale)
|
||||
|
||||
readOnly: ! box.editable
|
||||
validator: box.validator
|
||||
inputMethodHints: Qt.ImhFormattedNumbersOnly
|
||||
|
||||
onTextChanged: if (text && text !== "-") box.value = text
|
||||
}
|
||||
|
||||
down.indicator: HButton {
|
||||
x: box.mirrored ? parent.width - width : 0
|
||||
height: parent.height
|
||||
font.pixelSize: theme.fontSize.biggest
|
||||
text: qsTr("-")
|
||||
autoRepeat: true
|
||||
autoRepeatInterval: 50
|
||||
|
||||
onPressed: box.decrease()
|
||||
}
|
||||
|
||||
up.indicator: HButton {
|
||||
x: box.mirrored ? 0 : parent.width - width
|
||||
height: parent.height
|
||||
font.pixelSize: theme.fontSize.biggest
|
||||
text: qsTr("+")
|
||||
autoRepeat: true
|
||||
autoRepeatInterval: 50
|
||||
|
||||
onPressed: box.increase()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: textField.hovered ? Qt.IBeamCursor : Qt.ArrowCursor
|
||||
onWheel: wheel => {
|
||||
wheel.angleDelta.y < 0 ? box.decrease() : box.increase()
|
||||
wheel.accepted()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
@@ -5,19 +6,15 @@ import QtQuick.Layouts 1.12
|
||||
import "../.."
|
||||
import "../../Base"
|
||||
import "../../Base/HTile"
|
||||
import "../../Base/Buttons"
|
||||
import "../../MainPane"
|
||||
import "../../Popups"
|
||||
|
||||
HTile {
|
||||
id: root
|
||||
|
||||
property Item page
|
||||
|
||||
readonly property QtObject matchingRoom:
|
||||
model.kind === "room" ?
|
||||
ModelStore.get(page.userId, "rooms").find(model.rule_id) :
|
||||
null
|
||||
|
||||
|
||||
contentOpacity: model.enabled ? 1 : theme.disabledElementsOpacity
|
||||
hoverEnabled: false
|
||||
leftPadding: theme.spacing / 4
|
||||
@@ -30,71 +27,8 @@ HTile {
|
||||
opacity: model.enabled ? 1 : theme.disabledElementsOpacity
|
||||
elide: Text.ElideNone
|
||||
wrapMode: HLabel.Wrap
|
||||
|
||||
textFormat:
|
||||
model.rule_id === ".m.rule.contains_user_name" ||
|
||||
model.rule_id === ".m.rule.roomnotif" ||
|
||||
model.kind === "sender" ?
|
||||
HLabel.StyledText :
|
||||
HLabel.PlainText
|
||||
|
||||
text:
|
||||
model.rule_id === ".m.rule.master" ?
|
||||
qsTr("Any message") :
|
||||
|
||||
model.rule_id === ".m.rule.suppress_notices" ?
|
||||
qsTr("Messages sent by bots") :
|
||||
|
||||
model.rule_id === ".m.rule.invite_for_me" ?
|
||||
qsTr("Received room invites") :
|
||||
|
||||
model.rule_id === ".m.rule.member_event" ?
|
||||
qsTr("Membership, name & avatar changes") :
|
||||
|
||||
model.rule_id === ".m.rule.contains_display_name" ?
|
||||
qsTr("Messages containing my display name") :
|
||||
|
||||
model.rule_id === ".m.rule.tombstone" ?
|
||||
qsTr("Room migration alerts") :
|
||||
|
||||
model.rule_id === ".m.rule.reaction" ?
|
||||
qsTr("Emoji reactions") :
|
||||
|
||||
model.rule_id === ".m.rule.roomnotif" ?
|
||||
qsTr("Messages containing %1").arg(
|
||||
utils.htmlColorize("@room", theme.colors.accentText),
|
||||
) :
|
||||
|
||||
model.rule_id === ".m.rule.contains_user_name" ?
|
||||
qsTr("Contains %1").arg(utils.coloredNameHtml(
|
||||
"", page.userId, page.userId.split(":")[0].substring(1),
|
||||
)):
|
||||
|
||||
model.rule_id === ".m.rule.call" ?
|
||||
qsTr("Incoming audio calls") :
|
||||
|
||||
model.rule_id === ".m.rule.encrypted_room_one_to_one" ?
|
||||
qsTr("Encrypted 1-to-1 messages") :
|
||||
|
||||
model.rule_id === ".m.rule.room_one_to_one" ?
|
||||
qsTr("Unencrypted 1-to-1 messages") :
|
||||
|
||||
model.rule_id === ".m.rule.message" ?
|
||||
qsTr("Unencrypted group messages") :
|
||||
|
||||
model.rule_id === ".m.rule.encrypted" ?
|
||||
qsTr("Encrypted group messages") :
|
||||
|
||||
model.kind === "content" ?
|
||||
qsTr('Contains "%1"').arg(model.pattern) :
|
||||
|
||||
model.kind === "sender" ?
|
||||
utils.coloredNameHtml("", model.rule_id) :
|
||||
|
||||
matchingRoom && matchingRoom.display_name ?
|
||||
matchingRoom.display_name :
|
||||
|
||||
model.rule_id
|
||||
textFormat: HLabel.StyledText
|
||||
text: utils.formatPushRuleName(page.userId, model)
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: theme.spacing
|
||||
@@ -161,6 +95,10 @@ HTile {
|
||||
|
||||
NotificationRuleButton {
|
||||
icon.name: "pushrule-edit"
|
||||
onClicked: window.makePopup(
|
||||
"Popups/PushRuleSettingsPopup/PushRuleSettingsPopup.qml",
|
||||
{userId: page.userId, rule: model},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -73,11 +73,11 @@ HListView {
|
||||
padding: theme.spacing
|
||||
font.pixelSize: theme.fontSize.big
|
||||
text:
|
||||
section === "override" ? qsTr("High-priority general rules") :
|
||||
section === "content" ? qsTr("Message text rules") :
|
||||
section === "override" ? qsTr("High priority general rules") :
|
||||
section === "content" ? qsTr("Message content rules") :
|
||||
section === "room" ? qsTr("Room rules") :
|
||||
section === "sender" ? qsTr("Sender rules") :
|
||||
qsTr("General rules")
|
||||
qsTr("Low priority general rules")
|
||||
}
|
||||
|
||||
delegate: NotificationRuleDelegate {
|
||||
|
20
src/gui/Popups/PushRuleSettingsPopup/ContentRule.qml
Normal file
20
src/gui/Popups/PushRuleSettingsPopup/ContentRule.qml
Normal file
@@ -0,0 +1,20 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Base/Buttons"
|
||||
|
||||
HColumnLayout {
|
||||
readonly property alias idField: idField
|
||||
|
||||
HLabeledItem {
|
||||
// TODO: globbing explanation & do space works?
|
||||
label.text: qsTr("Word:")
|
||||
Layout.fillWidth: true
|
||||
|
||||
HTextField {
|
||||
id: idField
|
||||
width: parent.width
|
||||
defaultText: rule.kind === "content" ? rule.pattern : ""
|
||||
}
|
||||
}
|
||||
}
|
14
src/gui/Popups/PushRuleSettingsPopup/CustomLabel.qml
Normal file
14
src/gui/Popups/PushRuleSettingsPopup/CustomLabel.qml
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
|
||||
HLabel {
|
||||
opacity: enabled ? 1 : theme.disabledElementsOpacity
|
||||
wrapMode: HLabel.Wrap
|
||||
Layout.fillWidth: true
|
||||
|
||||
Behavior on opacity { HNumberAnimation {} }
|
||||
}
|
119
src/gui/Popups/PushRuleSettingsPopup/GeneralRule.qml
Normal file
119
src/gui/Popups/PushRuleSettingsPopup/GeneralRule.qml
Normal file
@@ -0,0 +1,119 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Base/Buttons"
|
||||
|
||||
HColumnLayout {
|
||||
readonly property alias idField: idField
|
||||
|
||||
readonly property var matrixConditions: {
|
||||
const results = []
|
||||
|
||||
for (let i = 0; i < conditionRepeater.count; i++) {
|
||||
results.push(conditionRepeater.itemAt(i).control.matrixObject)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
spacing: theme.spacing / 2
|
||||
|
||||
HLabeledItem {
|
||||
label.text: rule.default ? qsTr("Rule ID:") : qsTr("Rule name:")
|
||||
Layout.fillWidth: true
|
||||
|
||||
HTextField {
|
||||
id: idField
|
||||
width: parent.width
|
||||
defaultText: rule.rule_id
|
||||
// TODO: minimum length, check no dupe
|
||||
}
|
||||
}
|
||||
|
||||
HRowLayout {
|
||||
Layout.topMargin: theme.spacing / 2
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("Conditions for a message to trigger this rule:")
|
||||
}
|
||||
|
||||
PositiveButton {
|
||||
icon.name: "pushrule-condition-add"
|
||||
iconItem.small: true
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: false
|
||||
onClicked: addConditionMenu.open()
|
||||
|
||||
HMenu {
|
||||
id: addConditionMenu
|
||||
x: -width + parent.width
|
||||
y: parent.height
|
||||
|
||||
HMenuItem {
|
||||
text: qsTr("Room has a certain number of members")
|
||||
}
|
||||
HMenuItem {
|
||||
text: qsTr("Message property matches value")
|
||||
}
|
||||
HMenuItem {
|
||||
text: qsTr("Message contains my display name")
|
||||
}
|
||||
HMenuItem {
|
||||
text: qsTr(
|
||||
"Sender has permission to trigger special notification"
|
||||
)
|
||||
}
|
||||
HMenuItem {
|
||||
text: qsTr("Custom JSON condition")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("No conditions added, all messages will match")
|
||||
color: theme.colors.dimText
|
||||
visible: Layout.preferredHeight > 0
|
||||
Layout.preferredHeight: conditionRepeater.count ? 0 : implicitHeight
|
||||
|
||||
Behavior on Layout.preferredHeight { HNumberAnimation {} }
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: conditionRepeater
|
||||
model: JSON.parse(rule.conditions)
|
||||
|
||||
HRowLayout {
|
||||
readonly property Item control: loader.item
|
||||
|
||||
spacing: theme.spacing
|
||||
|
||||
HLoader {
|
||||
id: loader
|
||||
|
||||
readonly property var condition: modelData
|
||||
readonly property string filename:
|
||||
modelData.kind === "event_match" ?
|
||||
"PushEventMatch" :
|
||||
modelData.kind === "contains_display_name" ?
|
||||
"PushContainsDisplayName" :
|
||||
modelData.kind === "room_member_count" ?
|
||||
"PushRoomMemberCount" :
|
||||
modelData.kind === "sender_notification_permission" ?
|
||||
"PushSenderNotificationPermission" :
|
||||
"PushUnknownCondition"
|
||||
|
||||
asynchronous: false
|
||||
source: "PushConditions/" + filename + ".qml"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NegativeButton {
|
||||
icon.name: "pushrule-condition-remove"
|
||||
iconItem.small: true
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
import QtQuick 2.12
|
||||
import "../../../Base"
|
||||
|
||||
HFlow {
|
||||
spacing: theme.spacing / 2
|
||||
|
||||
// transitions break CustomLabel opacity for some reason
|
||||
populate: null
|
||||
add: null
|
||||
move: null
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
import QtQuick 2.12
|
||||
import ".."
|
||||
import "../../../Base"
|
||||
|
||||
CustomLabel {
|
||||
readonly property var matrixObject: ({kind: "contains_display_name"})
|
||||
|
||||
text: qsTr("Message contains my display name")
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import ".."
|
||||
import "../../../Base"
|
||||
|
||||
CustomFlow {
|
||||
readonly property var matrixObject: ({
|
||||
kind: "event_match",
|
||||
key: keyCombo.editText,
|
||||
pattern: patternField.text,
|
||||
})
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("Message")
|
||||
verticalAlignment: CustomLabel.AlignVCenter
|
||||
height: keyCombo.height
|
||||
}
|
||||
|
||||
HComboBox {
|
||||
id: keyCombo
|
||||
width: Math.min(implicitWidth, parent.width)
|
||||
editText: condition.key
|
||||
editable: true
|
||||
currentIndex: model.indexOf(condition.key)
|
||||
model: [...new Set([
|
||||
"content.body",
|
||||
"content.msgtype",
|
||||
"room_id",
|
||||
"sender",
|
||||
"state_key",
|
||||
"type",
|
||||
condition.key,
|
||||
])].sort()
|
||||
}
|
||||
|
||||
CustomLabel {
|
||||
text: keyCombo.editText === "content.body" ? qsTr("has") : qsTr("is")
|
||||
verticalAlignment: CustomLabel.AlignVCenter
|
||||
height: keyCombo.height
|
||||
}
|
||||
|
||||
HTextField {
|
||||
id: patternField
|
||||
defaultText: condition.pattern
|
||||
width: Math.min(implicitWidth, parent.width)
|
||||
placeholderText: ({
|
||||
"content.body": qsTr("text..."),
|
||||
"content.msgtype": qsTr("e.g. m.image"),
|
||||
"room_id": qsTr("!room:example.org"),
|
||||
"sender": qsTr("@user:example.org"),
|
||||
"state_key": qsTr("@user:example.org"),
|
||||
"type": qsTr("e.g. m.room.message"),
|
||||
}[keyCombo.editText] || qsTr("value"))
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import ".."
|
||||
import "../../../Base"
|
||||
|
||||
CustomFlow {
|
||||
readonly property var matrixObject: ({
|
||||
kind: "room_member_count",
|
||||
is: operatorCombo.operators[operatorCombo.currentIndex]
|
||||
.replace("==", "") + countSpin.value,
|
||||
})
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("Room has")
|
||||
verticalAlignment: CustomLabel.AlignVCenter
|
||||
height: operatorCombo.height
|
||||
}
|
||||
|
||||
HComboBox {
|
||||
readonly property var operators: ["==", ">=", "<=", ">", "<"]
|
||||
|
||||
id: operatorCombo
|
||||
width: Math.min(implicitWidth, parent.width)
|
||||
currentIndex: operators.indexOf(/[=<>]+/.exec(condition.is + "==")[0])
|
||||
model: [
|
||||
qsTr("exactly"),
|
||||
qsTr("at least"),
|
||||
qsTr("at most"),
|
||||
qsTr("more than"),
|
||||
qsTr("less than"),
|
||||
]
|
||||
}
|
||||
|
||||
HSpinBox {
|
||||
id: countSpin
|
||||
width: Math.min(implicitWidth, parent.width)
|
||||
defaultValue: parseInt(condition.is.replace(/[=<>]/, ""), 10)
|
||||
}
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("members")
|
||||
verticalAlignment: CustomLabel.AlignVCenter
|
||||
height: operatorCombo.height
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import ".."
|
||||
import "../../../Base"
|
||||
|
||||
CustomFlow {
|
||||
readonly property var matrixObject: ({
|
||||
kind: "sender_notification_permission",
|
||||
key: keyCombo.editText,
|
||||
})
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("Sender has permission to send")
|
||||
verticalAlignment: CustomLabel.AlignVCenter
|
||||
height: keyCombo.height
|
||||
}
|
||||
|
||||
HComboBox {
|
||||
id: keyCombo
|
||||
width: Math.min(implicitWidth, parent.width)
|
||||
editable: true
|
||||
editText: condition.key
|
||||
currentIndex: model.indexOf(condition.key)
|
||||
model: [...new Set(["room", condition.key])].sort()
|
||||
}
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("notifications")
|
||||
verticalAlignment: CustomLabel.AlignVCenter
|
||||
height: keyCombo.height
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import ".."
|
||||
import "../../../Base"
|
||||
|
||||
AutoDirectionLayout {
|
||||
readonly property var matrixObject: {
|
||||
try {
|
||||
JSON.parse(jsonField.text)
|
||||
} catch (e) {
|
||||
// TODO
|
||||
return condition.condition
|
||||
}
|
||||
}
|
||||
|
||||
rowSpacing: theme.spacing / 2
|
||||
columnSpacing: rowSpacing
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("Custom JSON:")
|
||||
verticalAlignment: CustomLabel.AlignVCenter
|
||||
Layout.fillWidth: false
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
HTextField {
|
||||
// TODO: validate the JSON
|
||||
id: jsonField
|
||||
font.family: theme.fontFamily.mono
|
||||
defaultText: JSON.stringify(condition.condition)
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
243
src/gui/Popups/PushRuleSettingsPopup/PushRuleSettingsPopup.qml
Normal file
243
src/gui/Popups/PushRuleSettingsPopup/PushRuleSettingsPopup.qml
Normal file
@@ -0,0 +1,243 @@
|
||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import ".."
|
||||
import "../.."
|
||||
import "../../Base"
|
||||
import "../../Base/Buttons"
|
||||
|
||||
HFlickableColumnPopup {
|
||||
id: root
|
||||
|
||||
property string userId
|
||||
// A rule item from ModelStore.get(userId, "pushrules")
|
||||
property var rule
|
||||
|
||||
readonly property bool generalChecked:
|
||||
overrideRadio.checked || underrideRadio.checked
|
||||
|
||||
readonly property string checkedKind:
|
||||
overrideRadio.checked ? "override" :
|
||||
contentRadio.checked ? "content" :
|
||||
roomRadio.checked ? "room" :
|
||||
senderRadio.checked ? "sender" :
|
||||
"underride"
|
||||
|
||||
function save() {
|
||||
const details = swipeView.currentItem
|
||||
const isBefore = positionCombo.currentIndex === 0
|
||||
const position =
|
||||
positionCombo.visible && ! positionCombo.isCurrent ?
|
||||
positionCombo.model[positionCombo.currentIndex].rule_id :
|
||||
undefined
|
||||
|
||||
const args = [
|
||||
checkedKind,
|
||||
details.idField.text,
|
||||
rule.kind,
|
||||
rule.rule_id,
|
||||
isBefore && position ? position : undefined,
|
||||
! isBefore && position ? position : undefined,
|
||||
enableCheck.checked,
|
||||
generalChecked ? details.matrixConditions : undefined,
|
||||
contentRadio.checked ? details.idField.text : undefined,
|
||||
]
|
||||
|
||||
py.callClientCoro(userId, "edit_pushrule", args, root.close)
|
||||
}
|
||||
|
||||
page.implicitWidth: Math.min(maximumPreferredWidth, 550 * theme.uiScale)
|
||||
|
||||
page.footer: AutoDirectionLayout {
|
||||
ApplyButton {
|
||||
text: qsTr("Save changes")
|
||||
enabled: true // TODO
|
||||
onClicked: root.save()
|
||||
}
|
||||
|
||||
CancelButton {
|
||||
text: qsTr("Cancel changes")
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
NegativeButton {
|
||||
icon.name: "pushrule-remove"
|
||||
text: qsTr("Remove rule")
|
||||
enabled: ! root.rule.default
|
||||
}
|
||||
}
|
||||
|
||||
CustomLabel {
|
||||
visible: root.rule.default
|
||||
text: qsTr("Some settings cannot be changed for default server rules")
|
||||
color: theme.colors.warningText
|
||||
}
|
||||
|
||||
HColumnLayout {
|
||||
enabled: ! root.rule.default
|
||||
spacing: theme.spacing / 2
|
||||
|
||||
CustomLabel {
|
||||
text: qsTr("Rule type:")
|
||||
}
|
||||
|
||||
HRadioButton {
|
||||
id: overrideRadio
|
||||
text: "High priority general rule"
|
||||
subtitle.text: qsTr(
|
||||
"Control notifications for messages matching certain " +
|
||||
"conditions"
|
||||
)
|
||||
defaultChecked: root.rule.kind === "override"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
HRadioButton {
|
||||
id: contentRadio
|
||||
text: "Message content rule"
|
||||
subtitle.text: qsTr(
|
||||
"Control notifications for text messages containing a " +
|
||||
"certain word"
|
||||
)
|
||||
defaultChecked: root.rule.kind === "content"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
HRadioButton {
|
||||
id: roomRadio
|
||||
text: "Room rule"
|
||||
subtitle.text: qsTr(
|
||||
"Control notifications for all messages received in a " +
|
||||
"certain room"
|
||||
)
|
||||
defaultChecked: root.rule.kind === "room"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
HRadioButton {
|
||||
id: senderRadio
|
||||
text: "Sender rule"
|
||||
subtitle.text: qsTr(
|
||||
"Control notifications for all messages sent by a " +
|
||||
"certain user"
|
||||
)
|
||||
defaultChecked: root.rule.kind === "sender"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
HRadioButton {
|
||||
id: underrideRadio
|
||||
text: "Low priority general rule"
|
||||
subtitle.text: qsTr(
|
||||
"A general rule tested only after every other rule types"
|
||||
)
|
||||
defaultChecked: root.rule.kind === "underride"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
SwipeView {
|
||||
id: swipeView
|
||||
enabled: ! root.rule.default
|
||||
clip: true
|
||||
interactive: false
|
||||
currentIndex:
|
||||
overrideRadio.checked ? 0 :
|
||||
contentRadio.checked ? 1 :
|
||||
roomRadio.checked ? 2 :
|
||||
senderRadio.checked ? 3 :
|
||||
4
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
Behavior on implicitHeight { HNumberAnimation {} }
|
||||
|
||||
GeneralRule { enabled: SwipeView.isCurrentItem }
|
||||
ContentRule { enabled: SwipeView.isCurrentItem }
|
||||
RoomRule { enabled: SwipeView.isCurrentItem }
|
||||
SenderRule { enabled: SwipeView.isCurrentItem }
|
||||
GeneralRule { enabled: SwipeView.isCurrentItem }
|
||||
}
|
||||
|
||||
HLabeledItem {
|
||||
visible: ! rule.default && positionCombo.model.length > 1
|
||||
label.text: qsTr("Position:")
|
||||
Layout.fillWidth: true
|
||||
|
||||
HComboBox {
|
||||
id: positionCombo
|
||||
|
||||
property int currentPosition: 0
|
||||
|
||||
readonly property string name:
|
||||
! model.length ? "" : utils.stripHtmlTags(
|
||||
utils.formatPushRuleName(root.userId, model[currentIndex])
|
||||
)
|
||||
|
||||
readonly property bool isCurrent:
|
||||
model.length &&
|
||||
currentIndex === currentPosition &&
|
||||
root.rule.kind === root.checkedKind
|
||||
|
||||
width: parent.width
|
||||
currentIndex: currentPosition
|
||||
displayText:
|
||||
! model.length ? "" :
|
||||
isCurrent ? qsTr("Current") :
|
||||
currentIndex === 0 ? qsTr('Before "%1"').arg(name) :
|
||||
qsTr('After "%1"').arg(name)
|
||||
|
||||
model: {
|
||||
currentPosition = 0
|
||||
|
||||
const choices = []
|
||||
const rules = ModelStore.get(userId, "pushrules")
|
||||
|
||||
for (let i = 0; i < rules.count; i++) {
|
||||
const item = rules.get(i)
|
||||
const isCurrent =
|
||||
item.kind === root.checkedKind &&
|
||||
item.rule_id === root.rule.rule_id
|
||||
|
||||
if (isCurrent && choices.length)
|
||||
currentPosition = choices.length - 1
|
||||
|
||||
if (item.kind === root.checkedKind && ! item.default) {
|
||||
if (! choices.length) choices.push(item)
|
||||
if (! isCurrent) choices.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
return choices
|
||||
}
|
||||
|
||||
delegate: HMenuItem {
|
||||
readonly property string name:
|
||||
utils.formatPushRuleName(root.userId, modelData)
|
||||
|
||||
label.textFormat: HLabel.StyledText
|
||||
text:
|
||||
model.index === positionCombo.currentPosition &&
|
||||
root.rule.kind === root.checkedKind ?
|
||||
qsTr("Current") :
|
||||
|
||||
model.index === 0 ?
|
||||
qsTr('Before "%1"').arg(name) :
|
||||
|
||||
qsTr('After "%1"').arg(name)
|
||||
|
||||
onTriggered: positionCombo.currentIndex = model.index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HCheckBox {
|
||||
id: enableCheck
|
||||
text: qsTr("Enable this rule")
|
||||
defaultChecked: root.rule.enabled
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
21
src/gui/Popups/PushRuleSettingsPopup/RoomRule.qml
Normal file
21
src/gui/Popups/PushRuleSettingsPopup/RoomRule.qml
Normal file
@@ -0,0 +1,21 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Base/Buttons"
|
||||
|
||||
HColumnLayout {
|
||||
readonly property alias idField: idField
|
||||
|
||||
HLabeledItem {
|
||||
label.text: qsTr("Room ID:")
|
||||
Layout.fillWidth: true
|
||||
|
||||
HTextField {
|
||||
id: idField
|
||||
width: parent.width
|
||||
defaultText: rule.kind === "room" ? rule.rule_id : ""
|
||||
placeholderText: qsTr("!room:example.org")
|
||||
maximumLength: 255
|
||||
}
|
||||
}
|
||||
}
|
21
src/gui/Popups/PushRuleSettingsPopup/SenderRule.qml
Normal file
21
src/gui/Popups/PushRuleSettingsPopup/SenderRule.qml
Normal file
@@ -0,0 +1,21 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Base/Buttons"
|
||||
|
||||
HColumnLayout {
|
||||
readonly property alias idField: idField
|
||||
|
||||
HLabeledItem {
|
||||
label.text: qsTr("User ID:")
|
||||
Layout.fillWidth: true
|
||||
|
||||
HTextField {
|
||||
id: idField
|
||||
width: parent.width
|
||||
defaultText: rule.kind === "sender" ? rule.rule_id : ""
|
||||
placeholderText: qsTr("@alice:example.org")
|
||||
maximumLength: 255
|
||||
}
|
||||
}
|
||||
}
|
@@ -535,6 +535,7 @@ QtObject {
|
||||
return {word, start, end: seen}
|
||||
}
|
||||
|
||||
|
||||
function getClassPathRegex(obj) {
|
||||
const regexParts = []
|
||||
let parent = obj
|
||||
@@ -557,4 +558,79 @@ QtObject {
|
||||
|
||||
return new RegExp("^" + regexParts.reverse().join("") + "$")
|
||||
}
|
||||
|
||||
|
||||
function formatPushRuleName(userId, rule) {
|
||||
// rule: item from ModelStore.get(<userId>, "pushrules")
|
||||
|
||||
const roomColor = theme.colors.accentText
|
||||
const room = ModelStore.get(userId, "rooms").find(rule.rule_id)
|
||||
|
||||
return (
|
||||
rule.rule_id === ".m.rule.master" ?
|
||||
qsTr("Any message") :
|
||||
|
||||
rule.rule_id === ".m.rule.suppress_notices" ?
|
||||
qsTr("Messages sent by bots") :
|
||||
|
||||
rule.rule_id === ".m.rule.invite_for_me" ?
|
||||
qsTr("Received room invites") :
|
||||
|
||||
rule.rule_id === ".m.rule.member_event" ?
|
||||
qsTr("Membership, name & avatar changes") :
|
||||
|
||||
rule.rule_id === ".m.rule.contains_display_name" ?
|
||||
qsTr("Messages containing my display name") :
|
||||
|
||||
rule.rule_id === ".m.rule.tombstone" ?
|
||||
qsTr("Room migration alerts") :
|
||||
|
||||
rule.rule_id === ".m.rule.reaction" ?
|
||||
qsTr("Emoji reactions") :
|
||||
|
||||
rule.rule_id === ".m.rule.roomnotif" ?
|
||||
qsTr("Messages containing %1").arg(
|
||||
htmlColorize("@room", roomColor),
|
||||
) :
|
||||
|
||||
rule.rule_id === ".m.rule.contains_user_name" ?
|
||||
qsTr("Contains %1").arg(coloredNameHtml(
|
||||
"", userId, userId.split(":")[0].substring(1),
|
||||
)):
|
||||
|
||||
rule.rule_id === ".m.rule.call" ?
|
||||
qsTr("Incoming audio calls") :
|
||||
|
||||
rule.rule_id === ".m.rule.encrypted_room_one_to_one" ?
|
||||
qsTr("Encrypted 1-to-1 messages") :
|
||||
|
||||
rule.rule_id === ".m.rule.room_one_to_one" ?
|
||||
qsTr("Unencrypted 1-to-1 messages") :
|
||||
|
||||
rule.rule_id === ".m.rule.message" ?
|
||||
qsTr("Unencrypted group messages") :
|
||||
|
||||
rule.rule_id === ".m.rule.encrypted" ?
|
||||
qsTr("Encrypted group messages") :
|
||||
|
||||
rule.rule_id === ".im.vector.jitsi" ?
|
||||
qsTr("Incoming Jitsi calls") :
|
||||
|
||||
rule.kind === "content" ?
|
||||
qsTr('Contains "%1"').arg(rule.pattern) :
|
||||
|
||||
rule.kind === "sender" ?
|
||||
coloredNameHtml("", rule.rule_id) :
|
||||
|
||||
room && room.display_name && rule.kind !== "room" ?
|
||||
qsTr("Messages in room %1").arg(
|
||||
htmlColorize(escapeHtml(room.display_name), roomColor)
|
||||
) :
|
||||
|
||||
room && room.display_name ?
|
||||
escapeHtml(room.display_name) :
|
||||
|
||||
escapeHtml(rule.rule_id)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user