mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-10 00:50:49 +01:00
Merge pull request #2001 from vector-im/feature/mention_display_name
Fix mention display name
This commit is contained in:
commit
95e80f0263
@ -9,6 +9,7 @@ Improvements 🙌:
|
|||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
- Display name not shown under Settings/General (#1926)
|
- Display name not shown under Settings/General (#1926)
|
||||||
|
- Words containing my name should not trigger notifications (#1781)
|
||||||
- Fix changing language issue
|
- Fix changing language issue
|
||||||
- Fix FontSize issue (#1483, #1787)
|
- Fix FontSize issue (#1483, #1787)
|
||||||
- Fix bad color for settings icon on Android < 24 (#1786)
|
- Fix bad color for settings icon on Android < 24 (#1786)
|
||||||
|
@ -24,21 +24,24 @@ sealed class Action {
|
|||||||
object DoNotNotify : Action()
|
object DoNotNotify : Action()
|
||||||
data class Sound(val sound: String = ACTION_OBJECT_VALUE_VALUE_DEFAULT) : Action()
|
data class Sound(val sound: String = ACTION_OBJECT_VALUE_VALUE_DEFAULT) : Action()
|
||||||
data class Highlight(val highlight: Boolean) : Action()
|
data class Highlight(val highlight: Boolean) : Action()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ACTION_NOTIFY = "notify"
|
||||||
|
const val ACTION_DONT_NOTIFY = "dont_notify"
|
||||||
|
const val ACTION_COALESCE = "coalesce"
|
||||||
|
|
||||||
|
// Ref: https://matrix.org/docs/spec/client_server/latest#tweaks
|
||||||
|
const val ACTION_OBJECT_SET_TWEAK_KEY = "set_tweak"
|
||||||
|
|
||||||
|
const val ACTION_OBJECT_SET_TWEAK_VALUE_SOUND = "sound"
|
||||||
|
const val ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT = "highlight"
|
||||||
|
|
||||||
|
const val ACTION_OBJECT_VALUE_KEY = "value"
|
||||||
|
const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default"
|
||||||
|
const val ACTION_OBJECT_VALUE_VALUE_RING = "ring"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val ACTION_NOTIFY = "notify"
|
|
||||||
private const val ACTION_DONT_NOTIFY = "dont_notify"
|
|
||||||
private const val ACTION_COALESCE = "coalesce"
|
|
||||||
|
|
||||||
// Ref: https://matrix.org/docs/spec/client_server/latest#tweaks
|
|
||||||
private const val ACTION_OBJECT_SET_TWEAK_KEY = "set_tweak"
|
|
||||||
|
|
||||||
private const val ACTION_OBJECT_SET_TWEAK_VALUE_SOUND = "sound"
|
|
||||||
private const val ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT = "highlight"
|
|
||||||
|
|
||||||
private const val ACTION_OBJECT_VALUE_KEY = "value"
|
|
||||||
private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/latest#actions
|
* Ref: https://matrix.org/docs/spec/client_server/latest#actions
|
||||||
*
|
*
|
||||||
@ -69,18 +72,18 @@ private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default"
|
|||||||
fun List<Action>.toJson(): List<Any> {
|
fun List<Action>.toJson(): List<Any> {
|
||||||
return map { action ->
|
return map { action ->
|
||||||
when (action) {
|
when (action) {
|
||||||
is Action.Notify -> ACTION_NOTIFY
|
is Action.Notify -> Action.ACTION_NOTIFY
|
||||||
is Action.DoNotNotify -> ACTION_DONT_NOTIFY
|
is Action.DoNotNotify -> Action.ACTION_DONT_NOTIFY
|
||||||
is Action.Sound -> {
|
is Action.Sound -> {
|
||||||
mapOf(
|
mapOf(
|
||||||
ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_SOUND,
|
Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND,
|
||||||
ACTION_OBJECT_VALUE_KEY to action.sound
|
Action.ACTION_OBJECT_VALUE_KEY to action.sound
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is Action.Highlight -> {
|
is Action.Highlight -> {
|
||||||
mapOf(
|
mapOf(
|
||||||
ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT,
|
Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT,
|
||||||
ACTION_OBJECT_VALUE_KEY to action.highlight
|
Action.ACTION_OBJECT_VALUE_KEY to action.highlight
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,26 +95,26 @@ fun PushRule.getActions(): List<Action> {
|
|||||||
|
|
||||||
actions.forEach { actionStrOrObj ->
|
actions.forEach { actionStrOrObj ->
|
||||||
when (actionStrOrObj) {
|
when (actionStrOrObj) {
|
||||||
ACTION_NOTIFY -> Action.Notify
|
Action.ACTION_NOTIFY -> Action.Notify
|
||||||
ACTION_DONT_NOTIFY -> Action.DoNotNotify
|
Action.ACTION_DONT_NOTIFY -> Action.DoNotNotify
|
||||||
is Map<*, *> -> {
|
is Map<*, *> -> {
|
||||||
when (actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]) {
|
when (actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]) {
|
||||||
ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> {
|
Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> {
|
||||||
(actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue ->
|
(actionStrOrObj[Action.ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue ->
|
||||||
Action.Sound(stringValue)
|
Action.Sound(stringValue)
|
||||||
}
|
}
|
||||||
// When the value is not there, default sound (not specified by the spec)
|
// When the value is not there, default sound (not specified by the spec)
|
||||||
?: Action.Sound(ACTION_OBJECT_VALUE_VALUE_DEFAULT)
|
?: Action.Sound(Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT)
|
||||||
}
|
}
|
||||||
ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> {
|
Action.ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> {
|
||||||
(actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue ->
|
(actionStrOrObj[Action.ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue ->
|
||||||
Action.Highlight(boolValue)
|
Action.Highlight(boolValue)
|
||||||
}
|
}
|
||||||
// When the value is not there, default is true, says the spec
|
// When the value is not there, default is true, says the spec
|
||||||
?: Action.Highlight(true)
|
?: Action.Highlight(true)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
Timber.w("Unsupported set_tweak value ${actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]}")
|
Timber.w("Unsupported set_tweak value ${actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]}")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,32 +18,8 @@ package org.matrix.android.sdk.api.pushrules
|
|||||||
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
|
|
||||||
abstract class Condition(val kind: Kind) {
|
interface Condition {
|
||||||
|
fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean
|
||||||
|
|
||||||
enum class Kind(val value: String) {
|
fun technicalDescription(): String
|
||||||
EventMatch("event_match"),
|
|
||||||
ContainsDisplayName("contains_display_name"),
|
|
||||||
RoomMemberCount("room_member_count"),
|
|
||||||
SenderNotificationPermission("sender_notification_permission"),
|
|
||||||
Unrecognised("");
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
fun fromString(value: String): Kind {
|
|
||||||
return when (value) {
|
|
||||||
"event_match" -> EventMatch
|
|
||||||
"contains_display_name" -> ContainsDisplayName
|
|
||||||
"room_member_count" -> RoomMemberCount
|
|
||||||
"sender_notification_permission" -> SenderNotificationPermission
|
|
||||||
else -> Unrecognised
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean
|
|
||||||
|
|
||||||
open fun technicalDescription(): String {
|
|
||||||
return "Kind: $kind"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -20,17 +20,15 @@ import org.matrix.android.sdk.api.session.events.model.Event
|
|||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||||
import timber.log.Timber
|
import org.matrix.android.sdk.internal.util.caseInsensitiveFind
|
||||||
|
|
||||||
class ContainsDisplayNameCondition : Condition(Kind.ContainsDisplayName) {
|
class ContainsDisplayNameCondition : Condition {
|
||||||
|
|
||||||
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
||||||
return conditionResolver.resolveContainsDisplayNameCondition(event, this)
|
return conditionResolver.resolveContainsDisplayNameCondition(event, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun technicalDescription(): String {
|
override fun technicalDescription() = "User is mentioned"
|
||||||
return "User is mentioned"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSatisfied(event: Event, displayName: String): Boolean {
|
fun isSatisfied(event: Event, displayName: String): Boolean {
|
||||||
val message = when (event.type) {
|
val message = when (event.type) {
|
||||||
@ -45,31 +43,6 @@ class ContainsDisplayNameCondition : Condition(Kind.ContainsDisplayName) {
|
|||||||
else -> null
|
else -> null
|
||||||
} ?: return false
|
} ?: return false
|
||||||
|
|
||||||
return caseInsensitiveFind(displayName, message.body)
|
return message.body.caseInsensitiveFind(displayName)
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Returns whether a string contains an occurrence of another, as a standalone word, regardless of case.
|
|
||||||
*
|
|
||||||
* @param subString the string to search for
|
|
||||||
* @param longString the string to search in
|
|
||||||
* @return whether a match was found
|
|
||||||
*/
|
|
||||||
fun caseInsensitiveFind(subString: String, longString: String): Boolean {
|
|
||||||
// add sanity checks
|
|
||||||
if (subString.isEmpty() || longString.isEmpty()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
val regex = Regex("(\\W|^)" + Regex.escape(subString) + "(\\W|$)", RegexOption.IGNORE_CASE)
|
|
||||||
return regex.containsMatchIn(longString)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "## caseInsensitiveFind() : failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@ package org.matrix.android.sdk.api.pushrules
|
|||||||
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.util.caseInsensitiveFind
|
||||||
|
import org.matrix.android.sdk.internal.util.hasSpecialGlobChar
|
||||||
|
import org.matrix.android.sdk.internal.util.simpleGlobToRegExp
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class EventMatchCondition(
|
class EventMatchCondition(
|
||||||
@ -29,16 +32,18 @@ class EventMatchCondition(
|
|||||||
* The glob-style pattern to match against. Patterns with no special glob characters should
|
* The glob-style pattern to match against. Patterns with no special glob characters should
|
||||||
* be treated as having asterisks prepended and appended when testing the condition.
|
* be treated as having asterisks prepended and appended when testing the condition.
|
||||||
*/
|
*/
|
||||||
val pattern: String
|
val pattern: String,
|
||||||
) : Condition(Kind.EventMatch) {
|
/**
|
||||||
|
* true to match only words. In this case pattern will not be considered as a glob
|
||||||
|
*/
|
||||||
|
val wordsOnly: Boolean
|
||||||
|
) : Condition {
|
||||||
|
|
||||||
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
||||||
return conditionResolver.resolveEventMatchCondition(event, this)
|
return conditionResolver.resolveEventMatchCondition(event, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun technicalDescription(): String {
|
override fun technicalDescription() = "'$key' matches '$pattern', words only '$wordsOnly'"
|
||||||
return "'$key' Matches '$pattern'"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSatisfied(event: Event): Boolean {
|
fun isSatisfied(event: Event): Boolean {
|
||||||
// TODO encrypted events?
|
// TODO encrypted events?
|
||||||
@ -48,14 +53,18 @@ class EventMatchCondition(
|
|||||||
|
|
||||||
// Patterns with no special glob characters should be treated as having asterisks prepended
|
// Patterns with no special glob characters should be treated as having asterisks prepended
|
||||||
// and appended when testing the condition.
|
// and appended when testing the condition.
|
||||||
try {
|
return try {
|
||||||
val modPattern = if (hasSpecialGlobChar(pattern)) simpleGlobToRegExp(pattern) else simpleGlobToRegExp("*$pattern*")
|
if (wordsOnly) {
|
||||||
val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL)
|
value.caseInsensitiveFind(pattern)
|
||||||
return regex.containsMatchIn(value)
|
} else {
|
||||||
|
val modPattern = if (pattern.hasSpecialGlobChar()) pattern.simpleGlobToRegExp() else "*$pattern*".simpleGlobToRegExp()
|
||||||
|
val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL)
|
||||||
|
regex.containsMatchIn(value)
|
||||||
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
// e.g PatternSyntaxException
|
// e.g PatternSyntaxException
|
||||||
Timber.e(e, "Failed to evaluate push condition")
|
Timber.e(e, "Failed to evaluate push condition")
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,27 +87,4 @@ class EventMatchCondition(
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private fun hasSpecialGlobChar(glob: String): Boolean {
|
|
||||||
return glob.contains("*") || glob.contains("?")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Very simple glob to regexp converter
|
|
||||||
private fun simpleGlobToRegExp(glob: String): String {
|
|
||||||
var out = "" // "^"
|
|
||||||
for (element in glob) {
|
|
||||||
when (element) {
|
|
||||||
'*' -> out += ".*"
|
|
||||||
'?' -> out += '.'.toString()
|
|
||||||
'.' -> out += "\\."
|
|
||||||
'\\' -> out += "\\\\"
|
|
||||||
else -> out += element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out += "" // '$'.toString()
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.pushrules
|
||||||
|
|
||||||
|
enum class Kind(val value: String) {
|
||||||
|
EventMatch("event_match"),
|
||||||
|
ContainsDisplayName("contains_display_name"),
|
||||||
|
RoomMemberCount("room_member_count"),
|
||||||
|
SenderNotificationPermission("sender_notification_permission"),
|
||||||
|
Unrecognised("");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun fromString(value: String): Kind {
|
||||||
|
return when (value) {
|
||||||
|
"event_match" -> EventMatch
|
||||||
|
"contains_display_name" -> ContainsDisplayName
|
||||||
|
"room_member_count" -> RoomMemberCount
|
||||||
|
"sender_notification_permission" -> SenderNotificationPermission
|
||||||
|
else -> Unrecognised
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -29,15 +29,13 @@ class RoomMemberCountCondition(
|
|||||||
* If no prefix is present, this parameter defaults to ==.
|
* If no prefix is present, this parameter defaults to ==.
|
||||||
*/
|
*/
|
||||||
val iz: String
|
val iz: String
|
||||||
) : Condition(Kind.RoomMemberCount) {
|
) : Condition {
|
||||||
|
|
||||||
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
||||||
return conditionResolver.resolveRoomMemberCountCondition(event, this)
|
return conditionResolver.resolveRoomMemberCountCondition(event, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun technicalDescription(): String {
|
override fun technicalDescription() = "Room member count is $iz"
|
||||||
return "Room member count is $iz"
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun isSatisfied(event: Event, roomGetter: RoomGetter): Boolean {
|
internal fun isSatisfied(event: Event, roomGetter: RoomGetter): Boolean {
|
||||||
// sanity checks
|
// sanity checks
|
||||||
|
@ -45,4 +45,6 @@ object RuleIds {
|
|||||||
|
|
||||||
// Not documented
|
// Not documented
|
||||||
const val RULE_ID_FALLBACK = ".m.rule.fallback"
|
const val RULE_ID_FALLBACK = ".m.rule.fallback"
|
||||||
|
|
||||||
|
const val RULE_ID_REACTION = ".m.rule.reaction"
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,13 @@ class SenderNotificationPermissionCondition(
|
|||||||
* type from the notifications object in the power level event content.
|
* type from the notifications object in the power level event content.
|
||||||
*/
|
*/
|
||||||
val key: String
|
val key: String
|
||||||
) : Condition(Kind.SenderNotificationPermission) {
|
) : Condition {
|
||||||
|
|
||||||
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
||||||
return conditionResolver.resolveSenderNotificationPermissionCondition(event, this)
|
return conditionResolver.resolveSenderNotificationPermissionCondition(event, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun technicalDescription(): String {
|
override fun technicalDescription() = "User power level <$key>"
|
||||||
return "User power level <$key>"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean {
|
fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean {
|
||||||
val powerLevelsHelper = PowerLevelsHelper(powerLevels)
|
val powerLevelsHelper = PowerLevelsHelper(powerLevels)
|
||||||
|
@ -21,7 +21,9 @@ import com.squareup.moshi.JsonClass
|
|||||||
import org.matrix.android.sdk.api.pushrules.Condition
|
import org.matrix.android.sdk.api.pushrules.Condition
|
||||||
import org.matrix.android.sdk.api.pushrules.ContainsDisplayNameCondition
|
import org.matrix.android.sdk.api.pushrules.ContainsDisplayNameCondition
|
||||||
import org.matrix.android.sdk.api.pushrules.EventMatchCondition
|
import org.matrix.android.sdk.api.pushrules.EventMatchCondition
|
||||||
|
import org.matrix.android.sdk.api.pushrules.Kind
|
||||||
import org.matrix.android.sdk.api.pushrules.RoomMemberCountCondition
|
import org.matrix.android.sdk.api.pushrules.RoomMemberCountCondition
|
||||||
|
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||||
import org.matrix.android.sdk.api.pushrules.SenderNotificationPermissionCondition
|
import org.matrix.android.sdk.api.pushrules.SenderNotificationPermissionCondition
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -58,20 +60,20 @@ data class PushCondition(
|
|||||||
val iz: String? = null
|
val iz: String? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun asExecutableCondition(): Condition? {
|
fun asExecutableCondition(rule: PushRule): Condition? {
|
||||||
return when (Condition.Kind.fromString(kind)) {
|
return when (Kind.fromString(kind)) {
|
||||||
Condition.Kind.EventMatch -> {
|
Kind.EventMatch -> {
|
||||||
if (key != null && pattern != null) {
|
if (key != null && pattern != null) {
|
||||||
EventMatchCondition(key, pattern)
|
EventMatchCondition(key, pattern, rule.ruleId == RuleIds.RULE_ID_CONTAIN_USER_NAME)
|
||||||
} else {
|
} else {
|
||||||
Timber.e("Malformed Event match condition")
|
Timber.e("Malformed Event match condition")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Condition.Kind.ContainsDisplayName -> {
|
Kind.ContainsDisplayName -> {
|
||||||
ContainsDisplayNameCondition()
|
ContainsDisplayNameCondition()
|
||||||
}
|
}
|
||||||
Condition.Kind.RoomMemberCount -> {
|
Kind.RoomMemberCount -> {
|
||||||
if (iz.isNullOrEmpty()) {
|
if (iz.isNullOrEmpty()) {
|
||||||
Timber.e("Malformed ROOM_MEMBER_COUNT condition")
|
Timber.e("Malformed ROOM_MEMBER_COUNT condition")
|
||||||
null
|
null
|
||||||
@ -79,7 +81,7 @@ data class PushCondition(
|
|||||||
RoomMemberCountCondition(iz)
|
RoomMemberCountCondition(iz)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Condition.Kind.SenderNotificationPermission -> {
|
Kind.SenderNotificationPermission -> {
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
Timber.e("Malformed Sender Notification Permission condition")
|
Timber.e("Malformed Sender Notification Permission condition")
|
||||||
null
|
null
|
||||||
@ -87,7 +89,7 @@ data class PushCondition(
|
|||||||
SenderNotificationPermissionCondition(key)
|
SenderNotificationPermissionCondition(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Condition.Kind.Unrecognised -> {
|
Kind.Unrecognised -> {
|
||||||
Timber.e("Unknown kind $kind")
|
Timber.e("Unknown kind $kind")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ data class PushRule(
|
|||||||
* Add the default notification sound.
|
* Add the default notification sound.
|
||||||
*/
|
*/
|
||||||
fun setNotificationSound(): PushRule {
|
fun setNotificationSound(): PushRule {
|
||||||
return setNotificationSound(ACTION_VALUE_DEFAULT)
|
return setNotificationSound(Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNotificationSound(): String? {
|
fun getNotificationSound(): String? {
|
||||||
@ -109,13 +109,13 @@ data class PushRule(
|
|||||||
fun setNotify(notify: Boolean): PushRule {
|
fun setNotify(notify: Boolean): PushRule {
|
||||||
val mutableActions = actions.toMutableList()
|
val mutableActions = actions.toMutableList()
|
||||||
|
|
||||||
mutableActions.remove(ACTION_DONT_NOTIFY)
|
mutableActions.remove(Action.ACTION_DONT_NOTIFY)
|
||||||
mutableActions.remove(ACTION_NOTIFY)
|
mutableActions.remove(Action.ACTION_NOTIFY)
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
mutableActions.add(ACTION_NOTIFY)
|
mutableActions.add(Action.ACTION_NOTIFY)
|
||||||
} else {
|
} else {
|
||||||
mutableActions.add(ACTION_DONT_NOTIFY)
|
mutableActions.add(Action.ACTION_DONT_NOTIFY)
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy(actions = mutableActions)
|
return copy(actions = mutableActions)
|
||||||
@ -126,51 +126,12 @@ data class PushRule(
|
|||||||
*
|
*
|
||||||
* @return true if the rule should play sound
|
* @return true if the rule should play sound
|
||||||
*/
|
*/
|
||||||
fun shouldNotify() = actions.contains(ACTION_NOTIFY)
|
fun shouldNotify() = actions.contains(Action.ACTION_NOTIFY)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the rule should not highlight the event.
|
* Return true if the rule should not highlight the event.
|
||||||
*
|
*
|
||||||
* @return true if the rule should not play sound
|
* @return true if the rule should not play sound
|
||||||
*/
|
*/
|
||||||
fun shouldNotNotify() = actions.contains(ACTION_DONT_NOTIFY)
|
fun shouldNotNotify() = actions.contains(Action.ACTION_DONT_NOTIFY)
|
||||||
|
|
||||||
companion object {
|
|
||||||
/* ==========================================================================================
|
|
||||||
* Rule id
|
|
||||||
* ========================================================================================== */
|
|
||||||
|
|
||||||
const val RULE_ID_DISABLE_ALL = ".m.rule.master"
|
|
||||||
const val RULE_ID_CONTAIN_USER_NAME = ".m.rule.contains_user_name"
|
|
||||||
const val RULE_ID_CONTAIN_DISPLAY_NAME = ".m.rule.contains_display_name"
|
|
||||||
const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one"
|
|
||||||
const val RULE_ID_INVITE_ME = ".m.rule.invite_for_me"
|
|
||||||
const val RULE_ID_PEOPLE_JOIN_LEAVE = ".m.rule.member_event"
|
|
||||||
const val RULE_ID_CALL = ".m.rule.call"
|
|
||||||
const val RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS = ".m.rule.suppress_notices"
|
|
||||||
const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message"
|
|
||||||
const val RULE_ID_AT_ROOMS = ".m.rule.roomnotif"
|
|
||||||
const val RULE_ID_TOMBSTONE = ".m.rule.tombstone"
|
|
||||||
const val RULE_ID_E2E_ONE_TO_ONE_ROOM = ".m.rule.encrypted_room_one_to_one"
|
|
||||||
const val RULE_ID_E2E_GROUP = ".m.rule.encrypted"
|
|
||||||
const val RULE_ID_REACTION = ".m.rule.reaction"
|
|
||||||
const val RULE_ID_FALLBACK = ".m.rule.fallback"
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
|
||||||
* Actions
|
|
||||||
* ========================================================================================== */
|
|
||||||
|
|
||||||
const val ACTION_NOTIFY = "notify"
|
|
||||||
const val ACTION_DONT_NOTIFY = "dont_notify"
|
|
||||||
const val ACTION_COALESCE = "coalesce"
|
|
||||||
|
|
||||||
const val ACTION_SET_TWEAK_SOUND_VALUE = "sound"
|
|
||||||
const val ACTION_SET_TWEAK_HIGHLIGHT_VALUE = "highlight"
|
|
||||||
|
|
||||||
const val ACTION_PARAMETER_SET_TWEAK = "set_tweak"
|
|
||||||
const val ACTION_PARAMETER_VALUE = "value"
|
|
||||||
|
|
||||||
const val ACTION_VALUE_DEFAULT = "default"
|
|
||||||
const val ACTION_VALUE_RING = "ring"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.pushrules.rest
|
|||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +52,7 @@ data class RuleSet(
|
|||||||
var result: PushRuleAndKind? = null
|
var result: PushRuleAndKind? = null
|
||||||
// sanity check
|
// sanity check
|
||||||
if (null != ruleId) {
|
if (null != ruleId) {
|
||||||
if (PushRule.RULE_ID_CONTAIN_USER_NAME == ruleId) {
|
if (RuleIds.RULE_ID_CONTAIN_USER_NAME == ruleId) {
|
||||||
result = findRule(content, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.CONTENT) }
|
result = findRule(content, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.CONTENT) }
|
||||||
} else {
|
} else {
|
||||||
// assume that the ruleId is unique.
|
// assume that the ruleId is unique.
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
package org.matrix.android.sdk.internal.database.mapper
|
package org.matrix.android.sdk.internal.database.mapper
|
||||||
|
|
||||||
import com.squareup.moshi.Types
|
import com.squareup.moshi.Types
|
||||||
import org.matrix.android.sdk.api.pushrules.Condition
|
import io.realm.RealmList
|
||||||
|
import org.matrix.android.sdk.api.pushrules.Kind
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushCondition
|
import org.matrix.android.sdk.api.pushrules.rest.PushCondition
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
||||||
import org.matrix.android.sdk.internal.database.model.PushRuleEntity
|
import org.matrix.android.sdk.internal.database.model.PushRuleEntity
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
import io.realm.RealmList
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal object PushRulesMapper {
|
internal object PushRulesMapper {
|
||||||
@ -39,7 +39,7 @@ internal object PushRulesMapper {
|
|||||||
enabled = pushrule.enabled,
|
enabled = pushrule.enabled,
|
||||||
ruleId = pushrule.ruleId,
|
ruleId = pushrule.ruleId,
|
||||||
conditions = listOf(
|
conditions = listOf(
|
||||||
PushCondition(Condition.Kind.EventMatch.value, "content.body", pushrule.pattern)
|
PushCondition(Kind.EventMatch.value, "content.body", pushrule.pattern)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ internal object PushRulesMapper {
|
|||||||
enabled = pushrule.enabled,
|
enabled = pushrule.enabled,
|
||||||
ruleId = pushrule.ruleId,
|
ruleId = pushrule.ruleId,
|
||||||
conditions = listOf(
|
conditions = listOf(
|
||||||
PushCondition(Condition.Kind.EventMatch.value, "room_id", pushrule.ruleId)
|
PushCondition(Kind.EventMatch.value, "room_id", pushrule.ruleId)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ internal object PushRulesMapper {
|
|||||||
enabled = pushrule.enabled,
|
enabled = pushrule.enabled,
|
||||||
ruleId = pushrule.ruleId,
|
ruleId = pushrule.ruleId,
|
||||||
conditions = listOf(
|
conditions = listOf(
|
||||||
PushCondition(Condition.Kind.EventMatch.value, "user_id", pushrule.ruleId)
|
PushCondition(Kind.EventMatch.value, "user_id", pushrule.ruleId)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
|
|||||||
return rules.firstOrNull { rule ->
|
return rules.firstOrNull { rule ->
|
||||||
// All conditions must hold true for an event in order to apply the action for the event.
|
// All conditions must hold true for an event in order to apply the action for the event.
|
||||||
rule.enabled && rule.conditions?.all {
|
rule.enabled && rule.conditions?.all {
|
||||||
it.asExecutableCondition()?.isSatisfied(event, conditionResolver) ?: false
|
it.asExecutableCondition(rule)?.isSatisfied(event, conditionResolver) ?: false
|
||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
package org.matrix.android.sdk.internal.session.room.notification
|
package org.matrix.android.sdk.internal.session.room.notification
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.pushrules.Action
|
import org.matrix.android.sdk.api.pushrules.Action
|
||||||
import org.matrix.android.sdk.api.pushrules.Condition
|
import org.matrix.android.sdk.api.pushrules.Kind
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
||||||
import org.matrix.android.sdk.api.pushrules.getActions
|
import org.matrix.android.sdk.api.pushrules.getActions
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushCondition
|
import org.matrix.android.sdk.api.pushrules.rest.PushCondition
|
||||||
@ -59,7 +59,7 @@ internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule?
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val condition = PushCondition(
|
val condition = PushCondition(
|
||||||
kind = Condition.Kind.EventMatch.value,
|
kind = Kind.EventMatch.value,
|
||||||
key = "room_id",
|
key = "room_id",
|
||||||
pattern = roomId
|
pattern = roomId
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.internal.util
|
||||||
|
|
||||||
|
internal fun String.hasSpecialGlobChar(): Boolean {
|
||||||
|
return contains("*") || contains("?")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Very simple glob to regexp converter
|
||||||
|
internal fun String.simpleGlobToRegExp(): String {
|
||||||
|
val string = this
|
||||||
|
return buildString {
|
||||||
|
// append("^")
|
||||||
|
string.forEach { char ->
|
||||||
|
when (char) {
|
||||||
|
'*' -> append(".*")
|
||||||
|
'?' -> append(".")
|
||||||
|
'.' -> append("\\.")
|
||||||
|
'\\' -> append("\\\\")
|
||||||
|
else -> append(char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// append("$")
|
||||||
|
}
|
||||||
|
}
|
@ -52,3 +52,25 @@ fun convertFromUTF8(s: String): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun String.withoutPrefix(prefix: String) = if (startsWith(prefix)) substringAfter(prefix) else this
|
fun String.withoutPrefix(prefix: String) = if (startsWith(prefix)) substringAfter(prefix) else this
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a string contains an occurrence of another, as a standalone word, regardless of case.
|
||||||
|
*
|
||||||
|
* @param subString the string to search for
|
||||||
|
* @return whether a match was found
|
||||||
|
*/
|
||||||
|
fun String.caseInsensitiveFind(subString: String): Boolean {
|
||||||
|
// add sanity checks
|
||||||
|
if (subString.isEmpty() || isEmpty()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val regex = Regex("(\\W|^)" + Regex.escape(subString) + "(\\W|$)", RegexOption.IGNORE_CASE)
|
||||||
|
return regex.containsMatchIn(this)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "## caseInsensitiveFind() : failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -16,6 +16,12 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.pushrules
|
package org.matrix.android.sdk.api.pushrules
|
||||||
|
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import org.amshove.kluent.shouldBe
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
import org.matrix.android.sdk.MatrixTest
|
import org.matrix.android.sdk.MatrixTest
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
@ -24,28 +30,26 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
|
||||||
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.mockk
|
|
||||||
import org.amshove.kluent.shouldBe
|
|
||||||
import org.junit.Assert.assertFalse
|
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class PushrulesConditionTest: MatrixTest {
|
class PushRulesConditionTest : MatrixTest {
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* Test EventMatchCondition
|
* Test EventMatchCondition
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
@Test
|
private fun createSimpleTextEvent(text: String): Event {
|
||||||
fun test_eventmatch_type_condition() {
|
return Event(
|
||||||
val condition = EventMatchCondition("type", "m.room.message")
|
|
||||||
|
|
||||||
val simpleTextEvent = Event(
|
|
||||||
type = "m.room.message",
|
type = "m.room.message",
|
||||||
eventId = "mx0",
|
eventId = "mx0",
|
||||||
content = MessageTextContent("m.text", "Yo wtf?").toContent(),
|
content = MessageTextContent("m.text", text).toContent(),
|
||||||
originServerTs = 0)
|
originServerTs = 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_eventmatch_type_condition() {
|
||||||
|
val condition = EventMatchCondition("type", "m.room.message", false)
|
||||||
|
|
||||||
|
val simpleTextEvent = createSimpleTextEvent("Yo wtf?")
|
||||||
|
|
||||||
val rm = RoomMemberContent(
|
val rm = RoomMemberContent(
|
||||||
Membership.INVITE,
|
Membership.INVITE,
|
||||||
@ -65,13 +69,9 @@ class PushrulesConditionTest: MatrixTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_path_condition() {
|
fun test_eventmatch_path_condition() {
|
||||||
val condition = EventMatchCondition("content.msgtype", "m.text")
|
val condition = EventMatchCondition("content.msgtype", "m.text", false)
|
||||||
|
|
||||||
val simpleTextEvent = Event(
|
val simpleTextEvent = createSimpleTextEvent("Yo wtf?")
|
||||||
type = "m.room.message",
|
|
||||||
eventId = "mx0",
|
|
||||||
content = MessageTextContent("m.text", "Yo wtf?").toContent(),
|
|
||||||
originServerTs = 0)
|
|
||||||
|
|
||||||
assert(condition.isSatisfied(simpleTextEvent))
|
assert(condition.isSatisfied(simpleTextEvent))
|
||||||
|
|
||||||
@ -86,49 +86,44 @@ class PushrulesConditionTest: MatrixTest {
|
|||||||
).toContent(),
|
).toContent(),
|
||||||
originServerTs = 0
|
originServerTs = 0
|
||||||
).apply {
|
).apply {
|
||||||
assert(EventMatchCondition("content.membership", "invite").isSatisfied(this))
|
assert(EventMatchCondition("content.membership", "invite", false).isSatisfied(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_cake_condition() {
|
fun test_eventmatch_cake_condition() {
|
||||||
val condition = EventMatchCondition("content.body", "cake")
|
val condition = EventMatchCondition("content.body", "cake", false)
|
||||||
|
|
||||||
Event(
|
assert(condition.isSatisfied(createSimpleTextEvent("How was the cake?")))
|
||||||
type = "m.room.message",
|
assert(condition.isSatisfied(createSimpleTextEvent("Howwasthecake?")))
|
||||||
eventId = "mx0",
|
|
||||||
content = MessageTextContent("m.text", "How was the cake?").toContent(),
|
|
||||||
originServerTs = 0
|
|
||||||
).apply {
|
|
||||||
assert(condition.isSatisfied(this))
|
|
||||||
}
|
|
||||||
|
|
||||||
Event(
|
|
||||||
type = "m.room.message",
|
|
||||||
eventId = "mx0",
|
|
||||||
content = MessageTextContent("m.text", "Howwasthecake?").toContent(),
|
|
||||||
originServerTs = 0
|
|
||||||
).apply {
|
|
||||||
assert(condition.isSatisfied(this))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_cakelie_condition() {
|
fun test_eventmatch_cakelie_condition() {
|
||||||
val condition = EventMatchCondition("content.body", "cake*lie")
|
val condition = EventMatchCondition("content.body", "cake*lie", false)
|
||||||
|
|
||||||
val simpleTextEvent = Event(
|
assert(condition.isSatisfied(createSimpleTextEvent("How was the cakeisalie?")))
|
||||||
type = "m.room.message",
|
}
|
||||||
eventId = "mx0",
|
|
||||||
content = MessageTextContent("m.text", "How was the cakeisalie?").toContent(),
|
|
||||||
originServerTs = 0)
|
|
||||||
|
|
||||||
assert(condition.isSatisfied(simpleTextEvent))
|
@Test
|
||||||
|
fun test_eventmatch_words_only_condition() {
|
||||||
|
val condition = EventMatchCondition("content.body", "ben", true)
|
||||||
|
|
||||||
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("benoit")))
|
||||||
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("Hello benoit")))
|
||||||
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("superben")))
|
||||||
|
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("ben")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("hello ben")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("ben is there")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("hello ben!")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("hello Ben!")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("BEN")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_notice_condition() {
|
fun test_notice_condition() {
|
||||||
val conditionEqual = EventMatchCondition("content.msgtype", "m.notice")
|
val conditionEqual = EventMatchCondition("content.msgtype", "m.notice", false)
|
||||||
|
|
||||||
Event(
|
Event(
|
||||||
type = "m.room.message",
|
type = "m.room.message",
|
@ -25,9 +25,6 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService
|
import com.google.firebase.messaging.FirebaseMessagingService
|
||||||
import com.google.firebase.messaging.RemoteMessage
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
|
||||||
import org.matrix.android.sdk.api.session.Session
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
|
||||||
import im.vector.app.BuildConfig
|
import im.vector.app.BuildConfig
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
@ -40,6 +37,9 @@ import im.vector.app.features.notifications.NotificationDrawerManager
|
|||||||
import im.vector.app.features.notifications.SimpleNotifiableEvent
|
import im.vector.app.features.notifications.SimpleNotifiableEvent
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
import im.vector.app.push.fcm.FcmHelper
|
||||||
|
import org.matrix.android.sdk.api.pushrules.Action
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,7 +196,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
description = "",
|
description = "",
|
||||||
type = null,
|
type = null,
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
soundName = PushRule.ACTION_VALUE_DEFAULT,
|
soundName = Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT,
|
||||||
isPushGatewayEvent = true
|
isPushGatewayEvent = true
|
||||||
)
|
)
|
||||||
notificationDrawerManager.onNotifiableEventReceived(simpleNotifiableEvent)
|
notificationDrawerManager.onNotifiableEventReceived(simpleNotifiableEvent)
|
||||||
|
@ -22,6 +22,8 @@ import android.view.View
|
|||||||
import android.widget.RadioGroup
|
import android.widget.RadioGroup
|
||||||
import androidx.preference.PreferenceViewHolder
|
import androidx.preference.PreferenceViewHolder
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import org.matrix.android.sdk.api.pushrules.Action
|
||||||
|
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushRuleAndKind
|
import org.matrix.android.sdk.api.pushrules.rest.PushRuleAndKind
|
||||||
@ -51,7 +53,7 @@ class PushRulePreference : VectorPreference {
|
|||||||
get() {
|
get() {
|
||||||
val safeRule = ruleAndKind?.pushRule ?: return NOTIFICATION_OFF_INDEX
|
val safeRule = ruleAndKind?.pushRule ?: return NOTIFICATION_OFF_INDEX
|
||||||
|
|
||||||
if (safeRule.ruleId == PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
if (safeRule.ruleId == RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
||||||
if (safeRule.shouldNotNotify()) {
|
if (safeRule.shouldNotNotify()) {
|
||||||
return if (safeRule.enabled) {
|
return if (safeRule.enabled) {
|
||||||
NOTIFICATION_OFF_INDEX
|
NOTIFICATION_OFF_INDEX
|
||||||
@ -108,7 +110,7 @@ class PushRulePreference : VectorPreference {
|
|||||||
val safeKind = ruleAndKind?.kind ?: return null
|
val safeKind = ruleAndKind?.kind ?: return null
|
||||||
|
|
||||||
return if (index != ruleStatusIndex) {
|
return if (index != ruleStatusIndex) {
|
||||||
if (safeRule.ruleId == PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
if (safeRule.ruleId == RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
||||||
when (index) {
|
when (index) {
|
||||||
NOTIFICATION_OFF_INDEX -> {
|
NOTIFICATION_OFF_INDEX -> {
|
||||||
safeRule.copy(enabled = true)
|
safeRule.copy(enabled = true)
|
||||||
@ -128,7 +130,7 @@ class PushRulePreference : VectorPreference {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (NOTIFICATION_OFF_INDEX == index) {
|
if (NOTIFICATION_OFF_INDEX == index) {
|
||||||
if (safeKind == RuleSetKey.UNDERRIDE || safeRule.ruleId == PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
if (safeKind == RuleSetKey.UNDERRIDE || safeRule.ruleId == RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) {
|
||||||
safeRule.setNotify(false)
|
safeRule.setNotify(false)
|
||||||
} else {
|
} else {
|
||||||
safeRule.copy(enabled = false)
|
safeRule.copy(enabled = false)
|
||||||
@ -137,15 +139,15 @@ class PushRulePreference : VectorPreference {
|
|||||||
val newRule = safeRule.copy(enabled = true)
|
val newRule = safeRule.copy(enabled = true)
|
||||||
.setNotify(true)
|
.setNotify(true)
|
||||||
.setHighlight(safeKind != RuleSetKey.UNDERRIDE
|
.setHighlight(safeKind != RuleSetKey.UNDERRIDE
|
||||||
&& safeRule.ruleId != PushRule.RULE_ID_INVITE_ME
|
&& safeRule.ruleId != RuleIds.RULE_ID_INVITE_ME
|
||||||
&& NOTIFICATION_NOISY_INDEX == index)
|
&& NOTIFICATION_NOISY_INDEX == index)
|
||||||
|
|
||||||
if (NOTIFICATION_NOISY_INDEX == index) {
|
if (NOTIFICATION_NOISY_INDEX == index) {
|
||||||
newRule.setNotificationSound(
|
newRule.setNotificationSound(
|
||||||
if (safeRule.ruleId == PushRule.RULE_ID_CALL) {
|
if (safeRule.ruleId == RuleIds.RULE_ID_CALL) {
|
||||||
PushRule.ACTION_VALUE_RING
|
Action.ACTION_OBJECT_VALUE_VALUE_RING
|
||||||
} else {
|
} else {
|
||||||
PushRule.ACTION_VALUE_DEFAULT
|
Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
package im.vector.app.features.settings
|
package im.vector.app.features.settings
|
||||||
|
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import org.matrix.android.sdk.api.MatrixCallback
|
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushRuleAndKind
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.preference.PushRulePreference
|
import im.vector.app.core.preference.PushRulePreference
|
||||||
import im.vector.app.core.preference.VectorPreference
|
import im.vector.app.core.preference.VectorPreference
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
|
import org.matrix.android.sdk.api.MatrixCallback
|
||||||
|
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||||
|
import org.matrix.android.sdk.api.pushrules.rest.PushRuleAndKind
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VectorSettingsAdvancedNotificationPreferenceFragment @Inject constructor()
|
class VectorSettingsAdvancedNotificationPreferenceFragment @Inject constructor()
|
||||||
@ -92,17 +92,17 @@ class VectorSettingsAdvancedNotificationPreferenceFragment @Inject constructor()
|
|||||||
companion object {
|
companion object {
|
||||||
// preference name <-> rule Id
|
// preference name <-> rule Id
|
||||||
private val prefKeyToPushRuleId = mapOf(
|
private val prefKeyToPushRuleId = mapOf(
|
||||||
"SETTINGS_PUSH_RULE_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY" to PushRule.RULE_ID_CONTAIN_DISPLAY_NAME,
|
"SETTINGS_PUSH_RULE_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_DISPLAY_NAME,
|
||||||
"SETTINGS_PUSH_RULE_CONTAINING_MY_USER_NAME_PREFERENCE_KEY" to PushRule.RULE_ID_CONTAIN_USER_NAME,
|
"SETTINGS_PUSH_RULE_CONTAINING_MY_USER_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_USER_NAME,
|
||||||
"SETTINGS_PUSH_RULE_MESSAGES_IN_ONE_TO_ONE_PREFERENCE_KEY" to PushRule.RULE_ID_ONE_TO_ONE_ROOM,
|
"SETTINGS_PUSH_RULE_MESSAGES_IN_ONE_TO_ONE_PREFERENCE_KEY" to RuleIds.RULE_ID_ONE_TO_ONE_ROOM,
|
||||||
"SETTINGS_PUSH_RULE_MESSAGES_IN_GROUP_CHAT_PREFERENCE_KEY" to PushRule.RULE_ID_ALL_OTHER_MESSAGES_ROOMS,
|
"SETTINGS_PUSH_RULE_MESSAGES_IN_GROUP_CHAT_PREFERENCE_KEY" to RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS,
|
||||||
"SETTINGS_PUSH_RULE_INVITED_TO_ROOM_PREFERENCE_KEY" to PushRule.RULE_ID_INVITE_ME,
|
"SETTINGS_PUSH_RULE_INVITED_TO_ROOM_PREFERENCE_KEY" to RuleIds.RULE_ID_INVITE_ME,
|
||||||
"SETTINGS_PUSH_RULE_CALL_INVITATIONS_PREFERENCE_KEY" to PushRule.RULE_ID_CALL,
|
"SETTINGS_PUSH_RULE_CALL_INVITATIONS_PREFERENCE_KEY" to RuleIds.RULE_ID_CALL,
|
||||||
"SETTINGS_PUSH_RULE_MESSAGES_SENT_BY_BOT_PREFERENCE_KEY" to PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS,
|
"SETTINGS_PUSH_RULE_MESSAGES_SENT_BY_BOT_PREFERENCE_KEY" to RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS,
|
||||||
"SETTINGS_PUSH_RULE_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to PushRule.RULE_ID_AT_ROOMS,
|
"SETTINGS_PUSH_RULE_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to RuleIds.RULE_ID_ROOM_NOTIF,
|
||||||
"SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_ONE_ONE_CHAT_PREFERENCE_KEY" to PushRule.RULE_ID_E2E_ONE_TO_ONE_ROOM,
|
"SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_ONE_ONE_CHAT_PREFERENCE_KEY" to RuleIds.RULE_ID_ONE_TO_ONE_ENCRYPTED_ROOM,
|
||||||
"SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_GROUP_CHAT_PREFERENCE_KEY" to PushRule.RULE_ID_E2E_GROUP,
|
"SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_GROUP_CHAT_PREFERENCE_KEY" to RuleIds.RULE_ID_ENCRYPTED,
|
||||||
"SETTINGS_PUSH_RULE_ROOMS_UPGRADED_KEY" to PushRule.RULE_ID_TOMBSTONE
|
"SETTINGS_PUSH_RULE_ROOMS_UPGRADED_KEY" to RuleIds.RULE_ID_TOMBSTONE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,11 @@ import androidx.core.view.isVisible
|
|||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
import com.airbnb.epoxy.EpoxyModelClass
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import com.airbnb.epoxy.EpoxyModelWithHolder
|
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||||
import org.matrix.android.sdk.api.pushrules.getActions
|
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.app.features.notifications.toNotificationAction
|
import im.vector.app.features.notifications.toNotificationAction
|
||||||
|
import org.matrix.android.sdk.api.pushrules.getActions
|
||||||
|
import org.matrix.android.sdk.api.pushrules.rest.PushRule
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_pushrule_raw)
|
@EpoxyModelClass(layout = R.layout.item_pushrule_raw)
|
||||||
abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
|
abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
|
||||||
@ -68,7 +68,7 @@ abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
|
|||||||
val description = StringBuffer()
|
val description = StringBuffer()
|
||||||
pushRule.conditions?.forEachIndexed { i, condition ->
|
pushRule.conditions?.forEachIndexed { i, condition ->
|
||||||
if (i > 0) description.append("\n")
|
if (i > 0) description.append("\n")
|
||||||
description.append(condition.asExecutableCondition()?.technicalDescription()
|
description.append(condition.asExecutableCondition(pushRule)?.technicalDescription()
|
||||||
?: "UNSUPPORTED")
|
?: "UNSUPPORTED")
|
||||||
}
|
}
|
||||||
if (description.isBlank()) {
|
if (description.isBlank()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user