Skip to content

Commit 9bbd7c0

Browse files
committed
Merge remote-tracking branch 'origin/develop' into develop
2 parents 475137b + f1a99c3 commit 9bbd7c0

File tree

78 files changed

+857
-701
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+857
-701
lines changed

library/ui-strings/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
<string name="notice_widget_modified">%1$s modified %2$s widget</string>
121121
<string name="notice_widget_modified_by_you">You modified %1$s widget</string>
122122

123+
<string name="power_level_owner">Owner</string>
123124
<string name="power_level_admin">Admin</string>
124125
<string name="power_level_moderator">Moderator</string>
125126
<string name="power_level_default">Default</string>
@@ -685,6 +686,7 @@
685686
<string name="room_participants_leave_prompt_title">Leave room</string>
686687
<string name="room_participants_leave_prompt_msg">Are you sure you want to leave the room?</string>
687688
<string name="room_participants_leave_private_warning">This room is not public. You will not be able to rejoin without an invite.</string>
689+
<string name="room_participants_leave_last_admin">You\'re the only admin of this room. Leaving it will mean no one has control over it.</string>
688690

689691
<string name="room_participants_header_direct_chats">Direct Messages</string>
690692

@@ -2383,6 +2385,7 @@
23832385
<string name="room_member_power_level_invites">Invites</string>
23842386
<string name="room_member_power_level_users">Users</string>
23852387

2388+
<string name="room_member_power_level_owner_in">Owner in %1$s</string>
23862389
<string name="room_member_power_level_admin_in">Admin in %1$s</string>
23872390
<string name="room_member_power_level_moderator_in">Moderator in %1$s</string>
23882391
<string name="room_member_power_level_default_in">Default in %1$s</string>

matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.room.model.ReadReceipt
3030
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
3131
import org.matrix.android.sdk.api.session.room.model.RoomSummary
3232
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
33+
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
3334
import org.matrix.android.sdk.api.session.room.send.UserDraft
3435
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
3536
import org.matrix.android.sdk.api.util.Optional
@@ -95,6 +96,10 @@ class FlowRoom(private val room: Room) {
9596
}
9697
}
9798

99+
fun liveRoomPowerLevels(): Flow<RoomPowerLevels> {
100+
return room.stateService().getRoomPowerLevelsLive().asFlow()
101+
}
102+
98103
fun liveReadMarker(): Flow<Optional<String>> {
99104
return room.readService().getReadMarkerLive().asFlow()
100105
}

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
4040
import org.matrix.android.sdk.api.session.room.model.RoomType
4141
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
4242
import org.matrix.android.sdk.api.session.room.model.create.RestrictedRoomPreset
43-
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
4443
import org.matrix.android.sdk.api.session.room.powerlevels.Role
44+
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
4545
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
4646
import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
4747
import org.matrix.android.sdk.common.SessionTestParams
@@ -500,12 +500,12 @@ class SpaceHierarchyTest : InstrumentedTest {
500500
room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent!!)
501501

502502
commonTestHelper.retryPeriodically {
503-
val powerLevelsHelper = aliceSession.getRoom(bobRoomId)!!
503+
val roomPowerLevels = aliceSession.getRoom(bobRoomId)!!
504504
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
505505
?.content
506506
?.toModel<PowerLevelsContent>()
507-
?.let { PowerLevelsHelper(it) }
508-
powerLevelsHelper!!.isUserAllowedToSend(aliceSession.myUserId, true, EventType.STATE_SPACE_PARENT)
507+
?.let { RoomPowerLevels(it) }
508+
roomPowerLevels!!.isUserAllowedToSend(aliceSession.myUserId, true, EventType.STATE_SPACE_PARENT)
509509
}
510510

511511
aliceSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,21 @@ object MatrixPatterns {
3030
// Note: TLD is not mandatory (localhost, IP address...)
3131
private const val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?"
3232

33+
private const val BASE_64_ALPHABET = "[0-9A-Za-z/\\+=]+"
34+
private const val BASE_64_URL_SAFE_ALPHABET = "[0-9A-Za-z/\\-_]+"
35+
3336
// regex pattern to find matrix user ids in a string.
3437
// See https://matrix.org/docs/spec/appendices#historical-user-ids
3538
private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX"
3639
val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
3740

3841
// regex pattern to find room ids in a string.
39-
private const val MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+$DOMAIN_REGEX"
42+
private const val MATRIX_ROOM_IDENTIFIER_REGEX = "^!.+$DOMAIN_REGEX$"
4043
private val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = MATRIX_ROOM_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
4144

45+
private const val MATRIX_ROOM_IDENTIFIER_DOMAINLESS_REGEX = "!$BASE_64_URL_SAFE_ALPHABET"
46+
private val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER_DOMAINLESS = MATRIX_ROOM_IDENTIFIER_DOMAINLESS_REGEX.toRegex()
47+
4248
// regex pattern to find room aliases in a string.
4349
private const val MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+$DOMAIN_REGEX"
4450
private val PATTERN_CONTAIN_MATRIX_ALIAS = MATRIX_ROOM_ALIAS_REGEX.toRegex(RegexOption.IGNORE_CASE)
@@ -48,11 +54,11 @@ object MatrixPatterns {
4854
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = MATRIX_EVENT_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
4955

5056
// regex pattern to find message ids in a string.
51-
private const val MATRIX_EVENT_IDENTIFIER_V3_REGEX = "\\$[A-Z0-9/+]+"
57+
private const val MATRIX_EVENT_IDENTIFIER_V3_REGEX = "\\$$BASE_64_ALPHABET"
5258
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 = MATRIX_EVENT_IDENTIFIER_V3_REGEX.toRegex(RegexOption.IGNORE_CASE)
5359

5460
// Ref: https://matrix.org/docs/spec/rooms/v4#event-ids
55-
private const val MATRIX_EVENT_IDENTIFIER_V4_REGEX = "\\$[A-Z0-9\\-_]+"
61+
private const val MATRIX_EVENT_IDENTIFIER_V4_REGEX = "\\$$BASE_64_URL_SAFE_ALPHABET"
5662
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4 = MATRIX_EVENT_IDENTIFIER_V4_REGEX.toRegex(RegexOption.IGNORE_CASE)
5763

5864
// regex pattern to find group ids in a string.
@@ -76,7 +82,10 @@ object MatrixPatterns {
7682
PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER,
7783
PATTERN_CONTAIN_MATRIX_ALIAS,
7884
PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER,
85+
PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER_DOMAINLESS,
7986
PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER,
87+
PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3,
88+
PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4,
8089
PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER
8190
)
8291

@@ -97,7 +106,9 @@ object MatrixPatterns {
97106
* @return true if the string is a valid room Id
98107
*/
99108
fun isRoomId(str: String?): Boolean {
100-
return str != null && str matches PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER
109+
return str != null &&
110+
(str matches PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER ||
111+
str matches PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER_DOMAINLESS)
101112
}
102113

103114
/**

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/SenderNotificationPermissionCondition.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
package org.matrix.android.sdk.api.session.pushrules
1717

1818
import org.matrix.android.sdk.api.session.events.model.Event
19-
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
20-
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
19+
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
2120

2221
class SenderNotificationPermissionCondition(
2322
/**
@@ -35,8 +34,7 @@ class SenderNotificationPermissionCondition(
3534

3635
override fun technicalDescription() = "User power level <$key>"
3736

38-
fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean {
39-
val powerLevelsHelper = PowerLevelsHelper(powerLevels)
40-
return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevels.notificationLevel(key)
37+
fun isSatisfied(event: Event, roomPowerLevels: RoomPowerLevels): Boolean {
38+
return event.senderId != null && roomPowerLevels.isUserAbleToTriggerNotification(event.senderId, key)
4139
}
4240
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.room
1818

1919
import org.matrix.android.sdk.api.query.QueryStateEventValue
2020
import org.matrix.android.sdk.api.session.events.model.Event
21+
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
2122
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
2223

2324
/**
@@ -34,3 +35,10 @@ fun Room.getTimelineEvent(eventId: String): TimelineEvent? =
3435
*/
3536
fun Room.getStateEvent(eventType: String, stateKey: QueryStateEventValue): Event? =
3637
stateService().getStateEvent(eventType, stateKey)
38+
39+
/**
40+
* Get the current RoomPowerLevels of the room.
41+
*/
42+
fun Room.getRoomPowerLevels(): RoomPowerLevels {
43+
return stateService().getRoomPowerLevels()
44+
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ package org.matrix.android.sdk.api.session.room.model
1818

1919
import com.squareup.moshi.Json
2020
import com.squareup.moshi.JsonClass
21-
import org.matrix.android.sdk.api.session.room.powerlevels.Role
21+
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent.Companion.NOTIFICATIONS_ROOM_KEY
22+
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
2223

2324
/**
2425
* Class representing the EventType.EVENT_TYPE_STATE_ROOM_POWER_LEVELS state event content.
@@ -34,7 +35,7 @@ data class PowerLevelsContent(
3435
*/
3536
@Json(name = "kick") val kick: Int? = null,
3637
/**
37-
* The level required to invite a user. Defaults to 50 if unspecified.
38+
* The level required to invite a user. Defaults to 0 if unspecified.
3839
*/
3940
@Json(name = "invite") val invite: Int? = null,
4041
/**
@@ -88,18 +89,17 @@ data class PowerLevelsContent(
8889
* Get the notification level for a dedicated key.
8990
*
9091
* @param key the notification key
91-
* @return the level, default to Moderator if the key is not found
92+
* @return the level
9293
*/
9394
fun notificationLevel(key: String): Int {
9495
return when (val value = notifications.orEmpty()[key]) {
9596
// the first implementation was a string value
9697
is String -> value.toInt()
9798
is Double -> value.toInt()
9899
is Int -> value
99-
else -> Role.Moderator.value
100+
else -> defaultNotificationLevel(key)
100101
}
101102
}
102-
103103
companion object {
104104
/**
105105
* Key to use for content.notifications and get the level required to trigger an @room notification. Defaults to 50 if unspecified.
@@ -108,11 +108,20 @@ data class PowerLevelsContent(
108108
}
109109
}
110110

111+
private fun defaultNotificationLevel(key: String): Int {
112+
return when (key) {
113+
NOTIFICATIONS_ROOM_KEY -> UserPowerLevel.Moderator.value
114+
else -> UserPowerLevel.User.value
115+
}
116+
}
117+
111118
// Fallback to default value, defined in the Matrix specification
112-
fun PowerLevelsContent.banOrDefault() = ban ?: Role.Moderator.value
113-
fun PowerLevelsContent.kickOrDefault() = kick ?: Role.Moderator.value
114-
fun PowerLevelsContent.inviteOrDefault() = invite ?: Role.Moderator.value
115-
fun PowerLevelsContent.redactOrDefault() = redact ?: Role.Moderator.value
116-
fun PowerLevelsContent.eventsDefaultOrDefault() = eventsDefault ?: Role.Default.value
117-
fun PowerLevelsContent.usersDefaultOrDefault() = usersDefault ?: Role.Default.value
118-
fun PowerLevelsContent.stateDefaultOrDefault() = stateDefault ?: Role.Moderator.value
119+
fun PowerLevelsContent?.banOrDefault() = this?.ban ?: UserPowerLevel.Moderator.value
120+
fun PowerLevelsContent?.kickOrDefault() = this?.kick ?: UserPowerLevel.Moderator.value
121+
fun PowerLevelsContent?.inviteOrDefault() = this?.invite ?: UserPowerLevel.User.value
122+
fun PowerLevelsContent?.redactOrDefault() = this?.redact ?: UserPowerLevel.Moderator.value
123+
fun PowerLevelsContent?.eventsDefaultOrDefault() = this?.eventsDefault ?: UserPowerLevel.User.value
124+
fun PowerLevelsContent?.usersDefaultOrDefault() = this?.usersDefault ?: UserPowerLevel.User.value
125+
fun PowerLevelsContent?.stateDefaultOrDefault() = this?.stateDefault ?: UserPowerLevel.Moderator.value
126+
127+
fun PowerLevelsContent?.notificationLevelOrDefault(key: String) = this?.notificationLevel(key) ?: defaultNotificationLevel(key)

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,39 @@ package org.matrix.android.sdk.api.session.room.model.create
1818

1919
import com.squareup.moshi.Json
2020
import com.squareup.moshi.JsonClass
21+
import org.matrix.android.sdk.api.session.events.model.Event
22+
import org.matrix.android.sdk.api.session.events.model.EventType
23+
import org.matrix.android.sdk.api.session.events.model.toModel
2124

2225
/**
2326
* Content of a m.room.create type event.
2427
*/
2528
@JsonClass(generateAdapter = true)
2629
data class RoomCreateContent(
30+
// Creator should be replaced by the sender of the event
2731
@Json(name = "creator") val creator: String? = null,
2832
@Json(name = "room_version") val roomVersion: String? = null,
2933
@Json(name = "predecessor") val predecessor: Predecessor? = null,
3034
// Defines the room type, see #RoomType (user extensible)
31-
@Json(name = "type") val type: String? = null
35+
@Json(name = "type") val type: String? = null,
36+
@Json(name = "additional_creators") val additionalCreators: List<String>? = null,
3237
)
38+
39+
data class RoomCreateContentWithSender(
40+
val senderId: String,
41+
val inner: RoomCreateContent
42+
) {
43+
val creators = setOf(senderId) + inner.additionalCreators.orEmpty().toSet()
44+
}
45+
46+
fun Event.getRoomCreateContentWithSender(): RoomCreateContentWithSender? {
47+
if (this.type != EventType.STATE_ROOM_CREATE) return null
48+
val innerContent = getClearContent().toModel<RoomCreateContent>() ?: return null
49+
val senderId = senderId ?: return null
50+
return RoomCreateContentWithSender(senderId, innerContent)
51+
}
52+
53+
fun RoomCreateContent.explicitlyPrivilegeRoomCreators(): Boolean {
54+
val supportedRoomVersions = listOf("org.matrix.hydra.11", "12")
55+
return supportedRoomVersions.contains(roomVersion)
56+
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,21 @@
1717

1818
package org.matrix.android.sdk.api.session.room.powerlevels
1919

20-
sealed class Role(open val value: Int) : Comparable<Role> {
21-
object Admin : Role(100)
22-
object Moderator : Role(50)
23-
object Default : Role(0)
24-
data class Custom(override val value: Int) : Role(value)
25-
26-
override fun compareTo(other: Role): Int {
27-
return value.compareTo(other.value)
28-
}
20+
enum class Role {
21+
Creator,
22+
SuperAdmin,
23+
Admin,
24+
Moderator,
25+
User;
2926

3027
companion object {
31-
32-
// Order matters, default value should be checked after defined roles
33-
fun fromValue(value: Int, default: Int): Role {
34-
return when (value) {
35-
Admin.value -> Admin
36-
Moderator.value -> Moderator
37-
Default.value,
38-
default -> Default
39-
else -> Custom(value)
28+
fun getSuggestedRole(userPowerLevel: UserPowerLevel): Role {
29+
return when {
30+
userPowerLevel == UserPowerLevel.Infinite -> Creator
31+
userPowerLevel >= UserPowerLevel.SuperAdmin -> SuperAdmin
32+
userPowerLevel >= UserPowerLevel.Admin -> Admin
33+
userPowerLevel >= UserPowerLevel.Moderator -> Moderator
34+
else -> User
4035
}
4136
}
4237
}

0 commit comments

Comments
 (0)