room version cap support + room upgrade
This commit is contained in:
parent
0c88d11429
commit
171793d190
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.session.homeserver
|
package org.matrix.android.sdk.api.session.homeserver
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities.Companion.MAX_UPLOAD_FILE_SIZE_UNKNOWN
|
||||||
|
|
||||||
data class HomeServerCapabilities(
|
data class HomeServerCapabilities(
|
||||||
/**
|
/**
|
||||||
* True if it is possible to change the password of the account.
|
* True if it is possible to change the password of the account.
|
||||||
@ -32,7 +34,9 @@ data class HomeServerCapabilities(
|
|||||||
/**
|
/**
|
||||||
* Default identity server url, provided in Wellknown
|
* Default identity server url, provided in Wellknown
|
||||||
*/
|
*/
|
||||||
val defaultIdentityServerUrl: String? = null
|
val defaultIdentityServerUrl: String? = null,
|
||||||
|
|
||||||
|
val roomVersions: RoomVersionCapabilities? = null
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L
|
const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.session.homeserver
|
||||||
|
|
||||||
|
data class RoomVersionCapabilities(
|
||||||
|
val defaultRoomVersion: String,
|
||||||
|
val supportedVersion: List<RoomVersionInfo>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class RoomVersionInfo(
|
||||||
|
val version: String,
|
||||||
|
val status: RoomVersionStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class RoomVersionStatus {
|
||||||
|
STABLE,
|
||||||
|
UNSTABLE
|
||||||
|
}
|
@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService
|
|||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineService
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineService
|
||||||
import org.matrix.android.sdk.api.session.room.typing.TypingService
|
import org.matrix.android.sdk.api.session.room.typing.TypingService
|
||||||
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
|
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
|
||||||
|
import org.matrix.android.sdk.api.session.room.version.RoomVersionService
|
||||||
import org.matrix.android.sdk.api.session.search.SearchResult
|
import org.matrix.android.sdk.api.session.search.SearchResult
|
||||||
import org.matrix.android.sdk.api.session.space.Space
|
import org.matrix.android.sdk.api.session.space.Space
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
@ -57,7 +58,8 @@ interface Room :
|
|||||||
RelationService,
|
RelationService,
|
||||||
RoomCryptoService,
|
RoomCryptoService,
|
||||||
RoomPushRuleService,
|
RoomPushRuleService,
|
||||||
RoomAccountDataService {
|
RoomAccountDataService,
|
||||||
|
RoomVersionService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The roomId of this room
|
* The roomId of this room
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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.session.room.version
|
||||||
|
|
||||||
|
interface RoomVersionService {
|
||||||
|
|
||||||
|
fun getRoomVersion(): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upgrade to the given room version
|
||||||
|
* @return the replacement room id
|
||||||
|
*/
|
||||||
|
suspend fun upgradeToVersion(version: String): String
|
||||||
|
|
||||||
|
suspend fun getRecommendedVersion() : String
|
||||||
|
|
||||||
|
fun userMayUpgradeRoom(userId: String): Boolean
|
||||||
|
}
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.space
|
|||||||
|
|
||||||
import org.matrix.android.sdk.api.session.room.Room
|
import org.matrix.android.sdk.api.session.room.Room
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
||||||
|
|
||||||
interface Space {
|
interface Space {
|
||||||
|
|
||||||
@ -38,6 +39,8 @@ interface Space {
|
|||||||
autoJoin: Boolean = false,
|
autoJoin: Boolean = false,
|
||||||
suggested: Boolean? = false)
|
suggested: Boolean? = false)
|
||||||
|
|
||||||
|
fun getChildInfo(roomId: String): SpaceChildContent?
|
||||||
|
|
||||||
suspend fun removeChildren(roomId: String)
|
suspend fun removeChildren(roomId: String)
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
|
@ -46,7 +46,7 @@ import javax.inject.Inject
|
|||||||
class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
|
class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val SESSION_STORE_SCHEMA_VERSION = 14L
|
const val SESSION_STORE_SCHEMA_VERSION = 15L
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
@ -66,6 +66,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
|
|||||||
if (oldVersion <= 11) migrateTo12(realm)
|
if (oldVersion <= 11) migrateTo12(realm)
|
||||||
if (oldVersion <= 12) migrateTo13(realm)
|
if (oldVersion <= 12) migrateTo13(realm)
|
||||||
if (oldVersion <= 13) migrateTo14(realm)
|
if (oldVersion <= 13) migrateTo14(realm)
|
||||||
|
if (oldVersion <= 14) migrateTo15(realm)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
private fun migrateTo1(realm: DynamicRealm) {
|
||||||
@ -306,4 +307,10 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
|
|||||||
|
|
||||||
roomAccountDataSchema.isEmbedded = true
|
roomAccountDataSchema.isEmbedded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun migrateTo15(realm: DynamicRealm) {
|
||||||
|
Timber.d("Step 14 -> 15")
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.addField(HomeServerCapabilitiesEntityFields.ROOM_VERSION_JSON, String::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,15 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.database.mapper
|
package org.matrix.android.sdk.internal.database.mapper
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.RoomVersionCapabilities
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.RoomVersionInfo
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.session.homeserver.RoomVersions
|
||||||
|
import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HomeServerCapabilitiesEntity -> HomeSeverCapabilities
|
* HomeServerCapabilitiesEntity -> HomeSeverCapabilities
|
||||||
@ -29,7 +36,21 @@ internal object HomeServerCapabilitiesMapper {
|
|||||||
canChangePassword = entity.canChangePassword,
|
canChangePassword = entity.canChangePassword,
|
||||||
maxUploadFileSize = entity.maxUploadFileSize,
|
maxUploadFileSize = entity.maxUploadFileSize,
|
||||||
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
|
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
|
||||||
defaultIdentityServerUrl = entity.defaultIdentityServerUrl
|
defaultIdentityServerUrl = entity.defaultIdentityServerUrl,
|
||||||
|
roomVersions = entity.roomVersionJson?.let {
|
||||||
|
tryOrNull {
|
||||||
|
MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).fromJson(it)?.let {
|
||||||
|
RoomVersionCapabilities(
|
||||||
|
defaultRoomVersion = it.default ?: DefaultRoomVersionService.DEFAULT_ROOM_VERSION,
|
||||||
|
supportedVersion = it.available.entries.map { entry ->
|
||||||
|
RoomVersionInfo(entry.key, RoomVersionStatus.STABLE
|
||||||
|
.takeIf { entry.value == "stable" }
|
||||||
|
?: RoomVersionStatus.UNSTABLE)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ internal open class HomeServerCapabilitiesEntity(
|
|||||||
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
|
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
|
||||||
var lastVersionIdentityServerSupported: Boolean = false,
|
var lastVersionIdentityServerSupported: Boolean = false,
|
||||||
var defaultIdentityServerUrl: String? = null,
|
var defaultIdentityServerUrl: String? = null,
|
||||||
var lastUpdatedTimestamp: Long = 0L
|
var lastUpdatedTimestamp: Long = 0L,
|
||||||
|
var roomVersionJson: String? = null
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.homeserver
|
|||||||
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.extensions.orTrue
|
import org.matrix.android.sdk.api.extensions.orTrue
|
||||||
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities
|
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities
|
||||||
@ -38,9 +39,14 @@ internal data class Capabilities(
|
|||||||
* Capability to indicate if the user can change their password.
|
* Capability to indicate if the user can change their password.
|
||||||
*/
|
*/
|
||||||
@Json(name = "m.change_password")
|
@Json(name = "m.change_password")
|
||||||
val changePassword: ChangePassword? = null
|
val changePassword: ChangePassword? = null,
|
||||||
|
|
||||||
// No need for m.room_versions for the moment
|
/**
|
||||||
|
* This capability describes the default and available room versions a server supports, and at what level of stability.
|
||||||
|
* Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms.
|
||||||
|
*/
|
||||||
|
@Json(name = "m.room_versions")
|
||||||
|
val roomVersions: RoomVersions? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
@ -52,6 +58,18 @@ internal data class ChangePassword(
|
|||||||
val enabled: Boolean?
|
val enabled: Boolean?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class RoomVersions(
|
||||||
|
/**
|
||||||
|
* Required. True if the user can change their password, false otherwise.
|
||||||
|
*/
|
||||||
|
@Json(name = "default")
|
||||||
|
val default: String?,
|
||||||
|
|
||||||
|
@Json(name = "available")
|
||||||
|
val available: JsonDict
|
||||||
|
)
|
||||||
|
|
||||||
// The spec says: If not present, the client should assume that password changes are possible via the API
|
// The spec says: If not present, the client should assume that password changes are possible via the API
|
||||||
internal fun GetCapabilitiesResult.canChangePassword(): Boolean {
|
internal fun GetCapabilitiesResult.canChangePassword(): Boolean {
|
||||||
return capabilities?.changePassword?.enabled.orTrue()
|
return capabilities?.changePassword?.enabled.orTrue()
|
||||||
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.internal.auth.version.Versions
|
|||||||
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
|
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
@ -104,6 +105,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
|||||||
|
|
||||||
if (getCapabilitiesResult != null) {
|
if (getCapabilitiesResult != null) {
|
||||||
homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword()
|
homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword()
|
||||||
|
|
||||||
|
homeServerCapabilitiesEntity.roomVersionJson = getCapabilitiesResult.capabilities?.roomVersions?.let {
|
||||||
|
MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getMediaConfigResult != null) {
|
if (getMediaConfigResult != null) {
|
||||||
|
@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService
|
|||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineService
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineService
|
||||||
import org.matrix.android.sdk.api.session.room.typing.TypingService
|
import org.matrix.android.sdk.api.session.room.typing.TypingService
|
||||||
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
|
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
|
||||||
|
import org.matrix.android.sdk.api.session.room.version.RoomVersionService
|
||||||
import org.matrix.android.sdk.api.session.search.SearchResult
|
import org.matrix.android.sdk.api.session.search.SearchResult
|
||||||
import org.matrix.android.sdk.api.session.space.Space
|
import org.matrix.android.sdk.api.session.space.Space
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
@ -69,7 +70,8 @@ internal class DefaultRoom(override val roomId: String,
|
|||||||
private val roomAccountDataService: RoomAccountDataService,
|
private val roomAccountDataService: RoomAccountDataService,
|
||||||
private val sendStateTask: SendStateTask,
|
private val sendStateTask: SendStateTask,
|
||||||
private val viaParameterFinder: ViaParameterFinder,
|
private val viaParameterFinder: ViaParameterFinder,
|
||||||
private val searchTask: SearchTask) :
|
private val searchTask: SearchTask,
|
||||||
|
private val roomVersionService: RoomVersionService) :
|
||||||
Room,
|
Room,
|
||||||
TimelineService by timelineService,
|
TimelineService by timelineService,
|
||||||
SendService by sendService,
|
SendService by sendService,
|
||||||
@ -85,7 +87,8 @@ internal class DefaultRoom(override val roomId: String,
|
|||||||
RelationService by relationService,
|
RelationService by relationService,
|
||||||
MembershipService by roomMembersService,
|
MembershipService by roomMembersService,
|
||||||
RoomPushRuleService by roomPushRuleService,
|
RoomPushRuleService by roomPushRuleService,
|
||||||
RoomAccountDataService by roomAccountDataService {
|
RoomAccountDataService by roomAccountDataService,
|
||||||
|
RoomVersionService by roomVersionService {
|
||||||
|
|
||||||
override fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>> {
|
override fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>> {
|
||||||
return roomSummaryDataSource.getRoomSummaryLive(roomId)
|
return roomSummaryDataSource.getRoomSummaryLive(roomId)
|
||||||
|
@ -369,4 +369,15 @@ internal interface RoomAPI {
|
|||||||
@Path("roomId") roomId: String,
|
@Path("roomId") roomId: String,
|
||||||
@Path("type") type: String,
|
@Path("type") type: String,
|
||||||
@Body content: JsonDict)
|
@Body content: JsonDict)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upgrades the given room to a particular room version.
|
||||||
|
* Errors:
|
||||||
|
* 400, The request was invalid. One way this can happen is if the room version requested is not supported by the homeserver
|
||||||
|
* (M_UNSUPPORTED_ROOM_VERSION)
|
||||||
|
* 403: The user is not permitted to upgrade the room.(M_FORBIDDEN)
|
||||||
|
*/
|
||||||
|
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/upgrade")
|
||||||
|
suspend fun upgradeRoom(@Path("roomId") roomId: String,
|
||||||
|
@Body body: RoomUpgradeBody): RoomUpgradeResponse
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import org.matrix.android.sdk.internal.session.room.tags.DefaultTagsService
|
|||||||
import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimelineService
|
import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimelineService
|
||||||
import org.matrix.android.sdk.internal.session.room.typing.DefaultTypingService
|
import org.matrix.android.sdk.internal.session.room.typing.DefaultTypingService
|
||||||
import org.matrix.android.sdk.internal.session.room.uploads.DefaultUploadsService
|
import org.matrix.android.sdk.internal.session.room.uploads.DefaultUploadsService
|
||||||
|
import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService
|
||||||
import org.matrix.android.sdk.internal.session.search.SearchTask
|
import org.matrix.android.sdk.internal.session.search.SearchTask
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
|
|||||||
private val relationServiceFactory: DefaultRelationService.Factory,
|
private val relationServiceFactory: DefaultRelationService.Factory,
|
||||||
private val membershipServiceFactory: DefaultMembershipService.Factory,
|
private val membershipServiceFactory: DefaultMembershipService.Factory,
|
||||||
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory,
|
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory,
|
||||||
|
private val roomVersionServiceFactory: DefaultRoomVersionService.Factory,
|
||||||
private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory,
|
private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory,
|
||||||
private val sendStateTask: SendStateTask,
|
private val sendStateTask: SendStateTask,
|
||||||
private val viaParameterFinder: ViaParameterFinder,
|
private val viaParameterFinder: ViaParameterFinder,
|
||||||
@ -89,7 +91,8 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
|
|||||||
roomAccountDataService = roomAccountDataServiceFactory.create(roomId),
|
roomAccountDataService = roomAccountDataServiceFactory.create(roomId),
|
||||||
sendStateTask = sendStateTask,
|
sendStateTask = sendStateTask,
|
||||||
searchTask = searchTask,
|
searchTask = searchTask,
|
||||||
viaParameterFinder = viaParameterFinder
|
viaParameterFinder = viaParameterFinder,
|
||||||
|
roomVersionService = roomVersionServiceFactory.create(roomId)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,8 @@ import org.matrix.android.sdk.internal.session.room.typing.DefaultSendTypingTask
|
|||||||
import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask
|
import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask
|
||||||
import org.matrix.android.sdk.internal.session.room.uploads.DefaultGetUploadsTask
|
import org.matrix.android.sdk.internal.session.room.uploads.DefaultGetUploadsTask
|
||||||
import org.matrix.android.sdk.internal.session.room.uploads.GetUploadsTask
|
import org.matrix.android.sdk.internal.session.room.uploads.GetUploadsTask
|
||||||
|
import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionUpgradeTask
|
||||||
|
import org.matrix.android.sdk.internal.session.room.version.RoomVersionUpgradeTask
|
||||||
import org.matrix.android.sdk.internal.session.space.DefaultSpaceService
|
import org.matrix.android.sdk.internal.session.space.DefaultSpaceService
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
|
|
||||||
@ -243,4 +245,7 @@ internal abstract class RoomModule {
|
|||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindGetEventTask(task: DefaultGetEventTask): GetEventTask
|
abstract fun bindGetEventTask(task: DefaultGetEventTask): GetEventTask
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindRoomVersionUpgradeTask(task: DefaultRoomVersionUpgradeTask): RoomVersionUpgradeTask
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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.session.room
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class RoomUpgradeBody(
|
||||||
|
@Json(name = "new_version")
|
||||||
|
val newVersion: String
|
||||||
|
)
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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.session.room
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class RoomUpgradeResponse(
|
||||||
|
@Json(name = "replacement_room")
|
||||||
|
val replacementRoomId: String
|
||||||
|
)
|
@ -354,7 +354,7 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||||||
// we keep real m.child/m.parent relations and add the one for common memberships
|
// we keep real m.child/m.parent relations and add the one for common memberships
|
||||||
dmRoom.flattenParentIds += "|${flattenRelated.joinToString("|")}|"
|
dmRoom.flattenParentIds += "|${flattenRelated.joinToString("|")}|"
|
||||||
}
|
}
|
||||||
// Timber.v("## SPACES: flatten of ${dmRoom.otherMemberIds.joinToString(",")} is ${dmRoom.flattenParentIds}")
|
Timber.v("## SPACES: flatten of ${dmRoom.otherMemberIds.joinToString(",")} is ${dmRoom.flattenParentIds}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maybe a good place to count the number of notifications for spaces?
|
// Maybe a good place to count the number of notifications for spaces?
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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.session.room.version
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.realm.Realm
|
||||||
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
|
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.room.model.PowerLevelsContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||||
|
import org.matrix.android.sdk.api.session.room.version.RoomVersionService
|
||||||
|
import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper
|
||||||
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.query.get
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
|
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||||
|
|
||||||
|
internal class DefaultRoomVersionService @AssistedInject constructor(
|
||||||
|
@Assisted private val roomId: String,
|
||||||
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
|
private val stateEventDataSource: StateEventDataSource,
|
||||||
|
private val roomVersionUpgradeTask: RoomVersionUpgradeTask
|
||||||
|
) : RoomVersionService {
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(roomId: String): DefaultRoomVersionService
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRoomVersion(): String {
|
||||||
|
return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty)
|
||||||
|
?.content
|
||||||
|
?.toModel<RoomCreateContent>()
|
||||||
|
?.roomVersion
|
||||||
|
// as per spec -> Defaults to "1" if the key does not exist.
|
||||||
|
?: DEFAULT_ROOM_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun upgradeToVersion(version: String): String {
|
||||||
|
return roomVersionUpgradeTask.execute(
|
||||||
|
RoomVersionUpgradeTask.Params(
|
||||||
|
roomId, version
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getRecommendedVersion(): String {
|
||||||
|
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||||
|
HomeServerCapabilitiesEntity.get(realm)?.let {
|
||||||
|
HomeServerCapabilitiesMapper.map(it)
|
||||||
|
}?.roomVersions?.defaultRoomVersion ?: DEFAULT_ROOM_VERSION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun userMayUpgradeRoom(userId: String): Boolean {
|
||||||
|
val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
|
||||||
|
?.content?.toModel<PowerLevelsContent>()
|
||||||
|
?.let { PowerLevelsHelper(it) }
|
||||||
|
|
||||||
|
return powerLevelsHelper?.isUserAllowedToSend(userId, true, EventType.STATE_ROOM_TOMBSTONE) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DEFAULT_ROOM_VERSION = "1"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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.session.room.version
|
||||||
|
|
||||||
|
import io.realm.RealmConfiguration
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
|
import org.matrix.android.sdk.internal.session.room.RoomAPI
|
||||||
|
import org.matrix.android.sdk.internal.session.room.RoomUpgradeBody
|
||||||
|
import org.matrix.android.sdk.internal.task.Task
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal interface RoomVersionUpgradeTask : Task<RoomVersionUpgradeTask.Params, String> {
|
||||||
|
data class Params(
|
||||||
|
val roomId: String,
|
||||||
|
val newVersion: String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultRoomVersionUpgradeTask @Inject constructor(
|
||||||
|
private val roomAPI: RoomAPI,
|
||||||
|
private val globalErrorReceiver: GlobalErrorReceiver,
|
||||||
|
@SessionDatabase
|
||||||
|
private val realmConfiguration: RealmConfiguration
|
||||||
|
) : RoomVersionUpgradeTask {
|
||||||
|
|
||||||
|
override suspend fun execute(params: RoomVersionUpgradeTask.Params): String {
|
||||||
|
val replacementRoomId = executeRequest(globalErrorReceiver) {
|
||||||
|
roomAPI.upgradeRoom(
|
||||||
|
roomId = params.roomId,
|
||||||
|
body = RoomUpgradeBody(params.newVersion)
|
||||||
|
)
|
||||||
|
}.replacementRoomId
|
||||||
|
|
||||||
|
// Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before)
|
||||||
|
tryOrNull {
|
||||||
|
awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
|
||||||
|
realm.where(RoomSummaryEntity::class.java)
|
||||||
|
.equalTo(RoomSummaryEntityFields.ROOM_ID, replacementRoomId)
|
||||||
|
.equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return replacementRoomId
|
||||||
|
}
|
||||||
|
}
|
@ -86,6 +86,12 @@ internal class DefaultSpace(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getChildInfo(roomId: String): SpaceChildContent? {
|
||||||
|
return room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
||||||
|
.firstOrNull()
|
||||||
|
?.content.toModel<SpaceChildContent>()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun setChildrenOrder(roomId: String, order: String?) {
|
override suspend fun setChildrenOrder(roomId: String, order: String?) {
|
||||||
val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
|
@ -159,7 +159,6 @@ class VectorApplication :
|
|||||||
// Do not display the name change popup
|
// Do not display the name change popup
|
||||||
doNotShowDisclaimerDialog(this)
|
doNotShowDisclaimerDialog(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
|
if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
|
||||||
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
|
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
|
||||||
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
|
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
|
||||||
|
@ -40,12 +40,14 @@ import im.vector.app.features.debug.DebugMenuActivity
|
|||||||
import im.vector.app.features.devtools.RoomDevToolActivity
|
import im.vector.app.features.devtools.RoomDevToolActivity
|
||||||
import im.vector.app.features.home.HomeActivity
|
import im.vector.app.features.home.HomeActivity
|
||||||
import im.vector.app.features.home.HomeModule
|
import im.vector.app.features.home.HomeModule
|
||||||
|
import im.vector.app.features.home.room.detail.JoinReplacementRoomBottomSheet
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||||
import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
|
import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
|
||||||
import im.vector.app.features.home.room.detail.search.SearchActivity
|
import im.vector.app.features.home.room.detail.search.SearchActivity
|
||||||
import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet
|
import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet
|
||||||
import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
|
import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
|
||||||
import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
||||||
|
import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet
|
||||||
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
|
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
|
||||||
import im.vector.app.features.home.room.filtered.FilteredRoomsActivity
|
import im.vector.app.features.home.room.filtered.FilteredRoomsActivity
|
||||||
import im.vector.app.features.home.room.list.RoomListModule
|
import im.vector.app.features.home.room.list.RoomListModule
|
||||||
@ -191,6 +193,8 @@ interface ScreenComponent {
|
|||||||
fun inject(bottomSheet: SpaceSettingsMenuBottomSheet)
|
fun inject(bottomSheet: SpaceSettingsMenuBottomSheet)
|
||||||
fun inject(bottomSheet: InviteRoomSpaceChooserBottomSheet)
|
fun inject(bottomSheet: InviteRoomSpaceChooserBottomSheet)
|
||||||
fun inject(bottomSheet: SpaceInviteBottomSheet)
|
fun inject(bottomSheet: SpaceInviteBottomSheet)
|
||||||
|
fun inject(bottomSheet: JoinReplacementRoomBottomSheet)
|
||||||
|
fun inject(bottomSheet: MigrateRoomBottomSheet)
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* Others
|
* Others
|
||||||
|
@ -46,7 +46,7 @@ import java.util.concurrent.TimeUnit
|
|||||||
/**
|
/**
|
||||||
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
||||||
*/
|
*/
|
||||||
abstract class VectorBaseBottomSheetDialogFragment<VB: ViewBinding> : BottomSheetDialogFragment(), MvRxView {
|
abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomSheetDialogFragment(), MvRxView {
|
||||||
|
|
||||||
private val mvrxViewIdProperty = MvRxViewId()
|
private val mvrxViewIdProperty = MvRxViewId()
|
||||||
final override val mvrxViewId: String by mvrxViewIdProperty
|
final override val mvrxViewId: String by mvrxViewIdProperty
|
||||||
@ -168,6 +168,10 @@ abstract class VectorBaseBottomSheetDialogFragment<VB: ViewBinding> : BottomShee
|
|||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun invalidate() {
|
override fun invalidate() {
|
||||||
|
forceExpandState()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun forceExpandState() {
|
||||||
if (showExpanded) {
|
if (showExpanded) {
|
||||||
// Force the bottom sheet to be expanded
|
// Force the bottom sheet to be expanded
|
||||||
bottomSheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED
|
bottomSheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.core.ui.list
|
||||||
|
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic list item.
|
||||||
|
* Displays an item with a title, and optional description.
|
||||||
|
* Can display an accessory on the right, that can be an image or an indeterminate progress.
|
||||||
|
* If provided with an action, will display a button at the bottom of the list item.
|
||||||
|
*/
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_generic_progress)
|
||||||
|
abstract class GenericProgressBarItem : VectorEpoxyModel<GenericProgressBarItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var progress: Int = 0
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var total: Int = 100
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var indeterminate: Boolean = false
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.progressbar.progress = progress
|
||||||
|
holder.progressbar.max = total
|
||||||
|
holder.progressbar.isIndeterminate = indeterminate
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val progressbar by bind<ProgressBar>(R.id.genericProgressBar)
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ import android.graphics.Color
|
|||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RelativeLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.text.italic
|
import androidx.core.text.italic
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
@ -44,7 +44,7 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
) : RelativeLayout(context, attrs, defStyleAttr) {
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
var delegate: Delegate? = null
|
var delegate: Delegate? = null
|
||||||
private var state: State = State.Initial
|
private var state: State = State.Initial
|
||||||
@ -127,7 +127,7 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||||||
|
|
||||||
private fun renderTombstone(state: State.Tombstone) {
|
private fun renderTombstone(state: State.Tombstone) {
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
views.roomNotificationIcon.setImageResource(R.drawable.error)
|
views.roomNotificationIcon.setImageResource(R.drawable.ic_warning_badge)
|
||||||
val message = span {
|
val message = span {
|
||||||
+resources.getString(R.string.room_tombstone_versioned_description)
|
+resources.getString(R.string.room_tombstone_versioned_description)
|
||||||
+"\n"
|
+"\n"
|
||||||
|
@ -50,7 +50,8 @@ enum class Command(val command: String, val parameters: String, @StringRes val d
|
|||||||
CREATE_SPACE("/createspace", "<name> <invitee>*", R.string.command_description_create_space, true),
|
CREATE_SPACE("/createspace", "<name> <invitee>*", R.string.command_description_create_space, true),
|
||||||
ADD_TO_SPACE("/addToSpace", "spaceId", R.string.command_description_create_space, true),
|
ADD_TO_SPACE("/addToSpace", "spaceId", R.string.command_description_create_space, true),
|
||||||
JOIN_SPACE("/joinSpace", "spaceId", R.string.command_description_join_space, true),
|
JOIN_SPACE("/joinSpace", "spaceId", R.string.command_description_join_space, true),
|
||||||
LEAVE_ROOM("/leave", "<roomId?>", R.string.command_description_leave_room, true);
|
LEAVE_ROOM("/leave", "<roomId?>", R.string.command_description_leave_room, true),
|
||||||
|
UPGRADE_ROOM("/upgraderoom", "newVersion", R.string.command_description_upgrade_room, true);
|
||||||
|
|
||||||
val length
|
val length
|
||||||
get() = command.length + 1
|
get() = command.length + 1
|
||||||
|
@ -330,6 +330,10 @@ object CommandParser {
|
|||||||
spaceIdOrAlias
|
spaceIdOrAlias
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Command.UPGRADE_ROOM.command -> {
|
||||||
|
val newVersion = textMessage.substring(Command.UPGRADE_ROOM.command.length).trim()
|
||||||
|
ParsedCommand.UpgradeRoom(newVersion)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// Unknown command
|
// Unknown command
|
||||||
ParsedCommand.ErrorUnknownSlashCommand(slashCommand)
|
ParsedCommand.ErrorUnknownSlashCommand(slashCommand)
|
||||||
|
@ -61,4 +61,5 @@ sealed class ParsedCommand {
|
|||||||
class AddToSpace(val spaceId: String) : ParsedCommand()
|
class AddToSpace(val spaceId: String) : ParsedCommand()
|
||||||
class JoinSpace(val spaceIdOrAlias: String) : ParsedCommand()
|
class JoinSpace(val spaceIdOrAlias: String) : ParsedCommand()
|
||||||
class LeaveRoom(val roomId: String) : ParsedCommand()
|
class LeaveRoom(val roomId: String) : ParsedCommand()
|
||||||
|
class UpgradeRoom(val newVersion: String) : ParsedCommand()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.features.home.room.detail
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.di.ScreenComponent
|
||||||
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
|
import im.vector.app.core.platform.ButtonStateView
|
||||||
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
|
import im.vector.app.databinding.BottomSheetTombstoneJoinBinding
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class JoinReplacementRoomBottomSheet :
|
||||||
|
VectorBaseBottomSheetDialogFragment<BottomSheetTombstoneJoinBinding>() {
|
||||||
|
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
|
||||||
|
BottomSheetTombstoneJoinBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var errorFormatter: ErrorFormatter
|
||||||
|
|
||||||
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
|
injector.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val viewModel: RoomDetailViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
|
override val showExpanded: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
views.roomUpgradeButton.retryClicked = object : ClickListener {
|
||||||
|
override fun invoke(view: View) {
|
||||||
|
withState(viewModel) { it.tombstoneEvent }?.let {
|
||||||
|
viewModel.handle(RoomDetailAction.HandleTombstoneEvent(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.selectSubscribe(this, RoomDetailViewState::tombstoneEventHandling) { joinState ->
|
||||||
|
when (joinState) {
|
||||||
|
// it should never be Uninitialized
|
||||||
|
Uninitialized -> views.roomUpgradeButton.render(ButtonStateView.State.Loaded)
|
||||||
|
is Loading -> {
|
||||||
|
views.roomUpgradeButton.render(ButtonStateView.State.Loading)
|
||||||
|
views.descriptionText.setText(R.string.it_may_take_some_time)
|
||||||
|
}
|
||||||
|
is Success -> {
|
||||||
|
views.roomUpgradeButton.render(ButtonStateView.State.Loaded)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
is Fail -> {
|
||||||
|
// display the error message
|
||||||
|
views.descriptionText.text = errorFormatter.toHumanReadable(joinState.error)
|
||||||
|
views.roomUpgradeButton.render(ButtonStateView.State.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -108,4 +108,5 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||||||
|
|
||||||
// Failed messages
|
// Failed messages
|
||||||
object RemoveAllFailedMessages : RoomDetailAction()
|
object RemoveAllFailedMessages : RoomDetailAction()
|
||||||
|
data class RoomUpgradeSuccess(val replacementRoom: String): RoomDetailAction()
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ import androidx.core.view.ViewCompat
|
|||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.fragment.app.setFragmentResultListener
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@ -147,6 +148,7 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageTextItem
|
|||||||
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
|
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
|
||||||
import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
||||||
import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
|
import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
|
||||||
|
import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet
|
||||||
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
|
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
|
||||||
import im.vector.app.features.html.EventHtmlRenderer
|
import im.vector.app.features.html.EventHtmlRenderer
|
||||||
import im.vector.app.features.html.PillImageSpan
|
import im.vector.app.features.html.PillImageSpan
|
||||||
@ -306,6 +308,15 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
|
|
||||||
private lateinit var emojiPopup: EmojiPopup
|
private lateinit var emojiPopup: EmojiPopup
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle ->
|
||||||
|
bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId ->
|
||||||
|
roomDetailViewModel.handle(RoomDetailAction.RoomUpgradeSuccess(replacementRoomId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||||
@ -405,6 +416,8 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
is RoomDetailViewEvents.StartChatEffect -> handleChatEffect(it.type)
|
is RoomDetailViewEvents.StartChatEffect -> handleChatEffect(it.type)
|
||||||
RoomDetailViewEvents.StopChatEffects -> handleStopChatEffects()
|
RoomDetailViewEvents.StopChatEffects -> handleStopChatEffects()
|
||||||
is RoomDetailViewEvents.DisplayAndAcceptCall -> acceptIncomingCall(it)
|
is RoomDetailViewEvents.DisplayAndAcceptCall -> acceptIncomingCall(it)
|
||||||
|
RoomDetailViewEvents.RoomReplacementStarted -> handleRoomReplacement()
|
||||||
|
is RoomDetailViewEvents.ShowRoomUpgradeDialog -> handleShowRoomUpgradeDialog(it)
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,6 +436,19 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleRoomReplacement() {
|
||||||
|
// this will join a new room, it can take time and might fail
|
||||||
|
// so we need to report progress and retry
|
||||||
|
val tag = JoinReplacementRoomBottomSheet::javaClass.name
|
||||||
|
JoinReplacementRoomBottomSheet().show(childFragmentManager, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleShowRoomUpgradeDialog(roomDetailViewEvents: RoomDetailViewEvents.ShowRoomUpgradeDialog) {
|
||||||
|
val tag = MigrateRoomBottomSheet::javaClass.name
|
||||||
|
MigrateRoomBottomSheet.newInstance(roomDetailArgs.roomId, roomDetailViewEvents.newVersion)
|
||||||
|
.show(parentFragmentManager, tag)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleChatEffect(chatEffect: ChatEffect) {
|
private fun handleChatEffect(chatEffect: ChatEffect) {
|
||||||
when (chatEffect) {
|
when (chatEffect) {
|
||||||
ChatEffect.CONFETTI -> {
|
ChatEffect.CONFETTI -> {
|
||||||
@ -1306,16 +1332,14 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
private fun renderTombstoneEventHandling(async: Async<String>) {
|
private fun renderTombstoneEventHandling(async: Async<String>) {
|
||||||
when (async) {
|
when (async) {
|
||||||
is Loading -> {
|
is Loading -> {
|
||||||
// TODO Better handling progress
|
// shown in bottom sheet
|
||||||
vectorBaseActivity.showWaitingView(getString(R.string.joining_room))
|
|
||||||
}
|
}
|
||||||
is Success -> {
|
is Success -> {
|
||||||
navigator.openRoom(vectorBaseActivity, async())
|
navigator.openRoom(vectorBaseActivity, async())
|
||||||
vectorBaseActivity.finish()
|
vectorBaseActivity.finish()
|
||||||
}
|
}
|
||||||
is Fail -> {
|
is Fail -> {
|
||||||
vectorBaseActivity.hideWaitingView()
|
// shown in bottom sheet
|
||||||
vectorBaseActivity.toast(errorFormatter.toHumanReadable(async.error))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,4 +94,6 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
|||||||
|
|
||||||
data class StartChatEffect(val type: ChatEffect) : RoomDetailViewEvents()
|
data class StartChatEffect(val type: ChatEffect) : RoomDetailViewEvents()
|
||||||
object StopChatEffects : RoomDetailViewEvents()
|
object StopChatEffects : RoomDetailViewEvents()
|
||||||
|
object RoomReplacementStarted : RoomDetailViewEvents()
|
||||||
|
data class ShowRoomUpgradeDialog(val newVersion: String, val isPublic: Boolean): RoomDetailViewEvents()
|
||||||
}
|
}
|
||||||
|
@ -321,6 +321,11 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
is RoomDetailAction.DoNotShowPreviewUrlFor -> handleDoNotShowPreviewUrlFor(action)
|
is RoomDetailAction.DoNotShowPreviewUrlFor -> handleDoNotShowPreviewUrlFor(action)
|
||||||
RoomDetailAction.RemoveAllFailedMessages -> handleRemoveAllFailedMessages()
|
RoomDetailAction.RemoveAllFailedMessages -> handleRemoveAllFailedMessages()
|
||||||
RoomDetailAction.ResendAll -> handleResendAll()
|
RoomDetailAction.ResendAll -> handleResendAll()
|
||||||
|
is RoomDetailAction.RoomUpgradeSuccess -> {
|
||||||
|
setState {
|
||||||
|
copy(tombstoneEventHandling = Success(action.replacementRoom))
|
||||||
|
}
|
||||||
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,6 +590,11 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
val viaServers = MatrixPatterns.extractServerNameFromId(action.event.senderId)
|
val viaServers = MatrixPatterns.extractServerNameFromId(action.event.senderId)
|
||||||
?.let { listOf(it) }
|
?.let { listOf(it) }
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
|
// need to provide feedback as joining could take some time
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.RoomReplacementStarted)
|
||||||
|
setState {
|
||||||
|
copy(tombstoneEventHandling = Loading())
|
||||||
|
}
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val result = runCatchingToAsync {
|
val result = runCatchingToAsync {
|
||||||
session.joinRoom(roomId, viaServers = viaServers)
|
session.joinRoom(roomId, viaServers = viaServers)
|
||||||
@ -817,6 +827,23 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
|
||||||
popDraft()
|
popDraft()
|
||||||
}
|
}
|
||||||
|
is ParsedCommand.UpgradeRoom -> {
|
||||||
|
_viewEvents.post(
|
||||||
|
RoomDetailViewEvents.ShowRoomUpgradeDialog(
|
||||||
|
slashCommandResult.newVersion,
|
||||||
|
room.roomSummary()?.isPublic ?: false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// session.coroutineScope.launch {
|
||||||
|
// try {
|
||||||
|
// room.upgradeToVersion(slashCommandResult.newVersion)
|
||||||
|
// } catch (failure: Throwable) {
|
||||||
|
// _viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
|
||||||
|
popDraft()
|
||||||
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
is SendMode.EDIT -> {
|
is SendMode.EDIT -> {
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.features.home.room.detail.upgrade
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
|
sealed class MigrateRoomAction : VectorViewModelAction {
|
||||||
|
data class SetAutoInvite(val autoInvite: Boolean) : MigrateRoomAction()
|
||||||
|
data class SetUpdateKnownParentSpace(val update: Boolean) : MigrateRoomAction()
|
||||||
|
object UpgradeRoom : MigrateRoomAction()
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.features.home.room.detail.upgrade
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import im.vector.app.core.di.ScreenComponent
|
||||||
|
import im.vector.app.core.extensions.cleanup
|
||||||
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
|
import im.vector.app.databinding.BottomSheetGenericListBinding
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MigrateRoomBottomSheet :
|
||||||
|
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
|
||||||
|
MigrateRoomViewModel.Factory, MigrateRoomController.InteractionListener {
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class Args(
|
||||||
|
val roomId: String,
|
||||||
|
val newVersion: String
|
||||||
|
) : Parcelable
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewModelFactory: MigrateRoomViewModel.Factory
|
||||||
|
|
||||||
|
override val showExpanded = true
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var epoxyController: MigrateRoomController
|
||||||
|
|
||||||
|
val viewModel: MigrateRoomViewModel by fragmentViewModel()
|
||||||
|
|
||||||
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
|
injector.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
|
||||||
|
BottomSheetGenericListBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
|
epoxyController.setData(state)
|
||||||
|
super.invalidate()
|
||||||
|
|
||||||
|
when (val result = state.upgradingStatus) {
|
||||||
|
is Success -> {
|
||||||
|
val result = result.invoke()
|
||||||
|
if (result is UpgradeRoomViewModelTask.Result.Success) {
|
||||||
|
setFragmentResult(REQUEST_KEY, Bundle().apply {
|
||||||
|
putString(BUNDLE_KEY_REPLACEMENT_ROOM, result.replacementRoomId)
|
||||||
|
})
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val postBuild = OnModelBuildFinishedListener {
|
||||||
|
view?.post { forceExpandState() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
epoxyController.callback = this
|
||||||
|
views.bottomSheetRecyclerView.configureWith(epoxyController)
|
||||||
|
epoxyController.addModelBuildListener(postBuild)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
views.bottomSheetRecyclerView.cleanup()
|
||||||
|
epoxyController.removeModelBuildListener(postBuild)
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel {
|
||||||
|
return viewModelFactory.create(initialState)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val REQUEST_KEY = "MigrateRoomBottomSheetRequest"
|
||||||
|
const val BUNDLE_KEY_REPLACEMENT_ROOM = "BUNDLE_KEY_REPLACEMENT_ROOM"
|
||||||
|
|
||||||
|
fun newInstance(roomId: String, newVersion: String)
|
||||||
|
: MigrateRoomBottomSheet {
|
||||||
|
return MigrateRoomBottomSheet().apply {
|
||||||
|
setArguments(Args(roomId, newVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutoInvite(autoInvite: Boolean) {
|
||||||
|
viewModel.handle(MigrateRoomAction.SetAutoInvite(autoInvite))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutoUpdateParent(update: Boolean) {
|
||||||
|
viewModel.handle(MigrateRoomAction.SetUpdateKnownParentSpace(update))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConfirmUpgrade() {
|
||||||
|
viewModel.handle(MigrateRoomAction.UpgradeRoom)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.features.home.room.detail.upgrade
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.errorWithRetryItem
|
||||||
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.core.ui.bottomsheet.bottomSheetTitleItem
|
||||||
|
import im.vector.app.core.ui.list.ItemStyle
|
||||||
|
import im.vector.app.core.ui.list.genericFooterItem
|
||||||
|
import im.vector.app.core.ui.list.genericProgressBarItem
|
||||||
|
import im.vector.app.features.form.formSubmitButtonItem
|
||||||
|
import im.vector.app.features.form.formSwitchItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MigrateRoomController @Inject constructor(
|
||||||
|
private val stringProvider: StringProvider,
|
||||||
|
private val errorFormatter: ErrorFormatter
|
||||||
|
) : TypedEpoxyController<MigrateRoomViewState>() {
|
||||||
|
|
||||||
|
interface InteractionListener {
|
||||||
|
fun onAutoInvite(autoInvite: Boolean)
|
||||||
|
fun onAutoUpdateParent(update: Boolean)
|
||||||
|
fun onConfirmUpgrade()
|
||||||
|
}
|
||||||
|
|
||||||
|
var callback: InteractionListener? = null
|
||||||
|
|
||||||
|
override fun buildModels(data: MigrateRoomViewState?) {
|
||||||
|
data ?: return
|
||||||
|
|
||||||
|
val host = this@MigrateRoomController
|
||||||
|
|
||||||
|
bottomSheetTitleItem {
|
||||||
|
id("title")
|
||||||
|
title(
|
||||||
|
host.stringProvider.getString(if (data.isPublic) R.string.upgrade_public_room else R.string.upgrade_private_room)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
genericFooterItem {
|
||||||
|
id("warning_text")
|
||||||
|
centered(false)
|
||||||
|
style(ItemStyle.NORMAL_TEXT)
|
||||||
|
text(host.stringProvider.getString(R.string.upgrade_room_warning))
|
||||||
|
}
|
||||||
|
|
||||||
|
genericFooterItem {
|
||||||
|
id("from_to_room")
|
||||||
|
centered(false)
|
||||||
|
style(ItemStyle.NORMAL_TEXT)
|
||||||
|
text(host.stringProvider.getString(R.string.upgrade_public_room_from_to, data.currentVersion, data.newVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.isPublic && data.otherMemberCount > 0) {
|
||||||
|
formSwitchItem {
|
||||||
|
id("auto_invite")
|
||||||
|
switchChecked(data.shouldIssueInvites)
|
||||||
|
title(host.stringProvider.getString(R.string.upgrade_room_auto_invite))
|
||||||
|
listener { switch -> host.callback?.onAutoInvite(switch) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.knownParents.isNotEmpty()) {
|
||||||
|
formSwitchItem {
|
||||||
|
id("update_parent")
|
||||||
|
switchChecked(data.shouldUpdateKnownParents)
|
||||||
|
title(host.stringProvider.getString(R.string.upgrade_room_update_parent))
|
||||||
|
listener { switch -> host.callback?.onAutoUpdateParent(switch) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when (data.upgradingStatus) {
|
||||||
|
is Loading -> {
|
||||||
|
genericProgressBarItem {
|
||||||
|
id("upgrade_progress")
|
||||||
|
indeterminate(data.upgradingProgressIndeterminate)
|
||||||
|
progress(data.upgradingProgress)
|
||||||
|
total(data.upgradingProgressTotal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Success -> {
|
||||||
|
when (val result = data.upgradingStatus.invoke()) {
|
||||||
|
is UpgradeRoomViewModelTask.Result.Failure -> {
|
||||||
|
val errorText = when (result) {
|
||||||
|
is UpgradeRoomViewModelTask.Result.UnknownRoom -> {
|
||||||
|
// should not happen
|
||||||
|
host.stringProvider.getString(R.string.unknown_error)
|
||||||
|
}
|
||||||
|
is UpgradeRoomViewModelTask.Result.NotAllowed -> {
|
||||||
|
host.stringProvider.getString(R.string.upgrade_room_no_power_to_manage)
|
||||||
|
}
|
||||||
|
is UpgradeRoomViewModelTask.Result.ErrorFailure -> {
|
||||||
|
host.errorFormatter.toHumanReadable(result.throwable)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
errorWithRetryItem {
|
||||||
|
id("error")
|
||||||
|
text(errorText)
|
||||||
|
listener { host.callback?.onConfirmUpgrade() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is UpgradeRoomViewModelTask.Result.Success -> {
|
||||||
|
// nop, dismisses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
formSubmitButtonItem {
|
||||||
|
id("migrate")
|
||||||
|
buttonTitleId(R.string.upgrade)
|
||||||
|
buttonClickListener { host.callback?.onConfirmUpgrade() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.features.home.room.detail.upgrade
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.ActivityViewModelContext
|
||||||
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import im.vector.app.core.platform.EmptyViewEvents
|
||||||
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import im.vector.app.features.session.coroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
|
||||||
|
class MigrateRoomViewModel @AssistedInject constructor(
|
||||||
|
@Assisted initialState: MigrateRoomViewState,
|
||||||
|
private val session: Session,
|
||||||
|
private val upgradeRoomViewModelTask: UpgradeRoomViewModelTask)
|
||||||
|
: VectorViewModel<MigrateRoomViewState, MigrateRoomAction, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
val room = session.getRoom(initialState.roomId)
|
||||||
|
val summary = session.getRoomSummary(initialState.roomId)
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
currentVersion = room?.getRoomVersion(),
|
||||||
|
isPublic = summary?.isPublic ?: false,
|
||||||
|
otherMemberCount = summary?.otherMemberIds?.count() ?: 0,
|
||||||
|
knownParents = summary?.flattenParentIds ?: emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<MigrateRoomViewModel, MigrateRoomViewState> {
|
||||||
|
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: MigrateRoomViewState): MigrateRoomViewModel? {
|
||||||
|
val factory = when (viewModelContext) {
|
||||||
|
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
||||||
|
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
||||||
|
}
|
||||||
|
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: MigrateRoomAction) {
|
||||||
|
when (action) {
|
||||||
|
is MigrateRoomAction.SetAutoInvite -> {
|
||||||
|
setState {
|
||||||
|
copy(shouldIssueInvites = action.autoInvite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is MigrateRoomAction.SetUpdateKnownParentSpace -> {
|
||||||
|
setState {
|
||||||
|
copy(shouldUpdateKnownParents = action.update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MigrateRoomAction.UpgradeRoom -> {
|
||||||
|
handleUpgradeRoom(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val upgradingProgress: ((indeterminate: Boolean, progress: Int, total: Int) -> Unit) = { indeterminate, progress, total ->
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
upgradingProgress = progress,
|
||||||
|
upgradingProgressTotal = total,
|
||||||
|
upgradingProgressIndeterminate = indeterminate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleUpgradeRoom(action: MigrateRoomAction) = withState { state ->
|
||||||
|
val summary = session.getRoomSummary(state.roomId)
|
||||||
|
setState {
|
||||||
|
copy(upgradingStatus = Loading())
|
||||||
|
}
|
||||||
|
session.coroutineScope.launch {
|
||||||
|
val result = upgradeRoomViewModelTask.execute(UpgradeRoomViewModelTask.Params(
|
||||||
|
roomId = state.roomId,
|
||||||
|
newVersion = state.newVersion,
|
||||||
|
userIdsToAutoInvite = summary?.otherMemberIds?.takeIf { state.shouldIssueInvites } ?: emptyList(),
|
||||||
|
parentSpaceToUpdate = summary?.flattenParentIds?.takeIf { state.shouldUpdateKnownParents } ?: emptyList(),
|
||||||
|
progressReporter = upgradingProgress
|
||||||
|
))
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(upgradingStatus = Success(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.features.home.room.detail.upgrade
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
|
||||||
|
data class MigrateRoomViewState(
|
||||||
|
val roomId: String,
|
||||||
|
val newVersion: String,
|
||||||
|
val currentVersion: String? = null,
|
||||||
|
val isPublic: Boolean = false,
|
||||||
|
val shouldIssueInvites: Boolean = false,
|
||||||
|
val shouldUpdateKnownParents: Boolean = false,
|
||||||
|
val otherMemberCount: Int = 0,
|
||||||
|
val knownParents: List<String> = emptyList(),
|
||||||
|
val upgradingStatus: Async<UpgradeRoomViewModelTask.Result> = Uninitialized,
|
||||||
|
val upgradingProgress: Int = 0,
|
||||||
|
val upgradingProgressTotal: Int = 0,
|
||||||
|
val upgradingProgressIndeterminate: Boolean = true
|
||||||
|
) : MvRxState {
|
||||||
|
constructor(args: MigrateRoomBottomSheet.Args) : this(
|
||||||
|
roomId = args.roomId,
|
||||||
|
newVersion = args.newVersion
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* 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 im.vector.app.features.home.room.detail.upgrade
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.ViewModelTask
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class UpgradeRoomViewModelTask @Inject constructor(
|
||||||
|
val session: Session,
|
||||||
|
val stringProvider: StringProvider
|
||||||
|
) : ViewModelTask<UpgradeRoomViewModelTask.Params, UpgradeRoomViewModelTask.Result> {
|
||||||
|
|
||||||
|
sealed class Result {
|
||||||
|
data class Success(val replacementRoomId: String) : Result()
|
||||||
|
abstract class Failure(val throwable: Throwable?) : Result()
|
||||||
|
object UnknownRoom : Failure(null)
|
||||||
|
object NotAllowed : Failure(null)
|
||||||
|
class ErrorFailure(throwable: Throwable) : Failure(throwable)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Params(
|
||||||
|
val roomId: String,
|
||||||
|
val newVersion: String,
|
||||||
|
val userIdsToAutoInvite: List<String> = emptyList(),
|
||||||
|
val parentSpaceToUpdate: List<String> = emptyList(),
|
||||||
|
val progressReporter: ((indeterminate: Boolean, progress: Int, total: Int) -> Unit)? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun execute(params: Params): Result {
|
||||||
|
params.progressReporter?.invoke(true, 0, 0)
|
||||||
|
|
||||||
|
val room = session.getRoom(params.roomId)
|
||||||
|
?: return Result.UnknownRoom
|
||||||
|
if (!room.userMayUpgradeRoom(session.myUserId)) {
|
||||||
|
return Result.NotAllowed
|
||||||
|
}
|
||||||
|
|
||||||
|
val updatedRoomId = try {
|
||||||
|
room.upgradeToVersion(params.newVersion)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
return Result.ErrorFailure(failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
val totalStep = params.userIdsToAutoInvite.size + params.parentSpaceToUpdate.size
|
||||||
|
var currentStep = 0
|
||||||
|
params.userIdsToAutoInvite.forEach {
|
||||||
|
params.progressReporter?.invoke(false, currentStep, totalStep)
|
||||||
|
tryOrNull {
|
||||||
|
session.getRoom(updatedRoomId)?.invite(it)
|
||||||
|
}
|
||||||
|
currentStep++
|
||||||
|
}
|
||||||
|
|
||||||
|
params.parentSpaceToUpdate.forEach { parentId ->
|
||||||
|
params.progressReporter?.invoke(false, currentStep, totalStep)
|
||||||
|
// we try and silently fail
|
||||||
|
try {
|
||||||
|
session.getRoom(parentId)?.asSpace()?.let { parentSpace ->
|
||||||
|
val currentInfo = parentSpace.getChildInfo(params.roomId)
|
||||||
|
if (currentInfo != null) {
|
||||||
|
parentSpace.addChildren(
|
||||||
|
roomId = updatedRoomId,
|
||||||
|
viaServers = currentInfo.via,
|
||||||
|
order = currentInfo.order,
|
||||||
|
autoJoin = currentInfo.autoJoin ?: false,
|
||||||
|
suggested = currentInfo.suggested
|
||||||
|
)
|
||||||
|
|
||||||
|
parentSpace.removeChildren(params.roomId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.d("## Migrate: Failed to update space parent. cause: ${failure.localizedMessage}")
|
||||||
|
} finally {
|
||||||
|
currentStep++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success(updatedRoomId)
|
||||||
|
}
|
||||||
|
}
|
@ -26,16 +26,20 @@ import im.vector.app.core.epoxy.errorWithRetryItem
|
|||||||
import im.vector.app.core.epoxy.loadingItem
|
import im.vector.app.core.epoxy.loadingItem
|
||||||
import im.vector.app.core.error.ErrorFormatter
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.core.ui.list.genericWithValueItem
|
||||||
import im.vector.app.features.discovery.settingsCenteredImageItem
|
import im.vector.app.features.discovery.settingsCenteredImageItem
|
||||||
import im.vector.app.features.discovery.settingsInfoItem
|
import im.vector.app.features.discovery.settingsInfoItem
|
||||||
import im.vector.app.features.discovery.settingsSectionTitleItem
|
import im.vector.app.features.discovery.settingsSectionTitleItem
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import org.matrix.android.sdk.api.federation.FederationVersion
|
import org.matrix.android.sdk.api.federation.FederationVersion
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||||
|
import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class HomeserverSettingsController @Inject constructor(
|
class HomeserverSettingsController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val errorFormatter: ErrorFormatter
|
private val errorFormatter: ErrorFormatter,
|
||||||
|
private val vectorPreferences: VectorPreferences
|
||||||
) : TypedEpoxyController<HomeServerSettingsViewState>() {
|
) : TypedEpoxyController<HomeServerSettingsViewState>() {
|
||||||
|
|
||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
@ -118,5 +122,36 @@ class HomeserverSettingsController @Inject constructor(
|
|||||||
helperText(host.stringProvider.getString(R.string.settings_server_upload_size_content, "${limit / 1048576L} MB"))
|
helperText(host.stringProvider.getString(R.string.settings_server_upload_size_content, "${limit / 1048576L} MB"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vectorPreferences.developerMode()) {
|
||||||
|
val roomCapabilities = data.homeServerCapabilities.roomVersions
|
||||||
|
if (roomCapabilities != null) {
|
||||||
|
settingsSectionTitleItem {
|
||||||
|
id("room_versions")
|
||||||
|
titleResId(R.string.settings_server_room_versions)
|
||||||
|
}
|
||||||
|
|
||||||
|
genericWithValueItem {
|
||||||
|
id("room_version_default")
|
||||||
|
title(host.stringProvider.getString(R.string.settings_server_default_room_version))
|
||||||
|
value(roomCapabilities.defaultRoomVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
roomCapabilities.supportedVersion.forEach {
|
||||||
|
genericWithValueItem {
|
||||||
|
id("room_version_${it.version}")
|
||||||
|
title(it.version)
|
||||||
|
value(
|
||||||
|
host.stringProvider.getString(
|
||||||
|
when (it.status) {
|
||||||
|
RoomVersionStatus.STABLE -> R.string.settings_server_room_version_stable
|
||||||
|
RoomVersionStatus.UNSTABLE -> R.string.settings_server_room_version_unstable
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
vector/src/main/res/layout/bottom_sheet_tombstone_join.xml
Normal file
48
vector/src/main/res/layout/bottom_sheet_tombstone_join.xml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?colorSurface"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/headerText"
|
||||||
|
style="@style/Widget.Vector.TextView.Subtitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/joining_replacement_room"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/descriptionText"
|
||||||
|
style="@style/Widget.Vector.TextView.Subtitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="?vctr_content_secondary"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/joinInfoHelpText"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/headerText"
|
||||||
|
app:layout_constraintVertical_bias="1"
|
||||||
|
tools:text="@string/it_may_take_some_time" />
|
||||||
|
|
||||||
|
<im.vector.app.core.platform.ButtonStateView
|
||||||
|
android:id="@+id/roomUpgradeButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="@dimen/layout_vertical_margin_big"
|
||||||
|
app:bsv_button_text="@string/join"
|
||||||
|
app:bsv_loaded_image_src="@drawable/ic_tick"
|
||||||
|
app:bsv_use_flat_button="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
6
vector/src/main/res/layout/item_generic_progress.xml
Normal file
6
vector/src/main/res/layout/item_generic_progress.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/genericProgressBar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp" />
|
@ -10,7 +10,7 @@
|
|||||||
style="@style/Widget.Vector.TextView.Body"
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="0dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:background="?vctr_keys_backup_banner_accent_color"
|
android:background="?vctr_keys_backup_banner_accent_color"
|
||||||
@ -18,7 +18,7 @@
|
|||||||
android:gravity="center|start"
|
android:gravity="center|start"
|
||||||
android:minHeight="80dp"
|
android:minHeight="80dp"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
app:drawableStartCompat="@drawable/error"
|
app:drawableStartCompat="@drawable/ic_warning_badge"
|
||||||
tools:text="This room is continuation…" />
|
tools:text="This room is continuation…" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
@ -1,38 +1,34 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?vctr_keys_backup_banner_accent_color"
|
||||||
android:minHeight="48dp"
|
android:minHeight="48dp"
|
||||||
tools:parentTag="android.widget.RelativeLayout">
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?vctr_list_separator" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/roomNotificationIcon"
|
android:id="@+id/roomNotificationIcon"
|
||||||
android:layout_width="32dp"
|
android:layout_width="32dp"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_gravity="top"
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
tools:src="@drawable/error" />
|
tools:src="@drawable/ic_warning_badge" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/roomNotificationMessage"
|
android:id="@+id/roomNotificationMessage"
|
||||||
style="@style/Widget.Vector.TextView.Body"
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginStart="64dp"
|
android:paddingStart="4dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:paddingEnd="0dp"
|
||||||
android:accessibilityLiveRegion="polite"
|
android:accessibilityLiveRegion="polite"
|
||||||
android:gravity="center"
|
android:gravity="start"
|
||||||
android:textColor="?vctr_content_primary"
|
android:textColor="?vctr_content_primary"
|
||||||
tools:text="@string/room_do_not_have_permission_to_post" />
|
tools:text="@string/room_do_not_have_permission_to_post" />
|
||||||
|
|
||||||
</merge>
|
</LinearLayout>
|
@ -926,7 +926,7 @@
|
|||||||
<string name="room_resend_unsent_messages">Resend unsent messages</string>
|
<string name="room_resend_unsent_messages">Resend unsent messages</string>
|
||||||
<string name="room_delete_unsent_messages">Delete unsent messages</string>
|
<string name="room_delete_unsent_messages">Delete unsent messages</string>
|
||||||
<string name="room_message_file_not_found">File not found</string>
|
<string name="room_message_file_not_found">File not found</string>
|
||||||
<string name="room_do_not_have_permission_to_post">You do not have permission to post to this room</string>
|
<string name="room_do_not_have_permission_to_post">You do not have permission to post to this room.</string>
|
||||||
<plurals name="room_new_messages_notification">
|
<plurals name="room_new_messages_notification">
|
||||||
<item quantity="one">%d new message</item>
|
<item quantity="one">%d new message</item>
|
||||||
<item quantity="other">%d new messages</item>
|
<item quantity="other">%d new messages</item>
|
||||||
@ -1820,7 +1820,7 @@
|
|||||||
|
|
||||||
<string name="error_empty_field_enter_user_name">Please enter a username.</string>
|
<string name="error_empty_field_enter_user_name">Please enter a username.</string>
|
||||||
<string name="error_empty_field_your_password">Please enter your password.</string>
|
<string name="error_empty_field_your_password">Please enter your password.</string>
|
||||||
<string name="room_tombstone_versioned_description">This room has been replaced and is no longer active</string>
|
<string name="room_tombstone_versioned_description">This room has been replaced and is no longer active.</string>
|
||||||
<string name="room_tombstone_continuation_link">The conversation continues here</string>
|
<string name="room_tombstone_continuation_link">The conversation continues here</string>
|
||||||
<string name="room_tombstone_continuation_description">This room is a continuation of another conversation</string>
|
<string name="room_tombstone_continuation_description">This room is a continuation of another conversation</string>
|
||||||
<string name="room_tombstone_predecessor_link">Click here to see older messages</string>
|
<string name="room_tombstone_predecessor_link">Click here to see older messages</string>
|
||||||
@ -2735,6 +2735,11 @@
|
|||||||
<string name="settings_server_upload_size_title">Server file upload limit</string>
|
<string name="settings_server_upload_size_title">Server file upload limit</string>
|
||||||
<string name="settings_server_upload_size_content">Your homeserver accepts attachments (files, media, etc.) with a size up to %s.</string>
|
<string name="settings_server_upload_size_content">Your homeserver accepts attachments (files, media, etc.) with a size up to %s.</string>
|
||||||
<string name="settings_server_upload_size_unknown">The limit is unknown.</string>
|
<string name="settings_server_upload_size_unknown">The limit is unknown.</string>
|
||||||
|
<!-- Only visible in developer mode-->
|
||||||
|
<string name="settings_server_room_versions">Room Versions 🕶</string>
|
||||||
|
<string name="settings_server_default_room_version">Default Version</string>
|
||||||
|
<string name="settings_server_room_version_stable">stable</string>
|
||||||
|
<string name="settings_server_room_version_unstable">unstable</string>
|
||||||
|
|
||||||
<string name="settings_failed_to_get_crypto_device_info">No cryptographic information available</string>
|
<string name="settings_failed_to_get_crypto_device_info">No cryptographic information available</string>
|
||||||
|
|
||||||
@ -3295,6 +3300,7 @@
|
|||||||
<string name="command_description_create_space">Create a Space</string>
|
<string name="command_description_create_space">Create a Space</string>
|
||||||
<string name="command_description_join_space">Join the Space with the given id</string>
|
<string name="command_description_join_space">Join the Space with the given id</string>
|
||||||
<string name="command_description_leave_room">Leave room with given id (or current room if null)</string>
|
<string name="command_description_leave_room">Leave room with given id (or current room if null)</string>
|
||||||
|
<string name="command_description_upgrade_room">Upgrades a room to a new version</string>
|
||||||
|
|
||||||
<string name="event_status_a11y_sending">Sending</string>
|
<string name="event_status_a11y_sending">Sending</string>
|
||||||
<string name="event_status_a11y_sent">Sent</string>
|
<string name="event_status_a11y_sent">Sent</string>
|
||||||
@ -3406,4 +3412,19 @@
|
|||||||
|
|
||||||
<string name="teammate_spaces_arent_quite_ready">"Teammate spaces aren’t quite ready but you can still give them a try"</string>
|
<string name="teammate_spaces_arent_quite_ready">"Teammate spaces aren’t quite ready but you can still give them a try"</string>
|
||||||
<string name="teammate_spaces_might_not_join">"At the moment people might not be able to join any private rooms you make.\n\nWe’ll be improving this as part of the beta, but just wanted to let you know."</string>
|
<string name="teammate_spaces_might_not_join">"At the moment people might not be able to join any private rooms you make.\n\nWe’ll be improving this as part of the beta, but just wanted to let you know."</string>
|
||||||
</resources>
|
|
||||||
|
<string name="joining_replacement_room">Join replacement room</string>
|
||||||
|
<string name="it_may_take_some_time">Please be patient, it may take some time.</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="upgrade">Upgrade</string>
|
||||||
|
<string name="upgrade_public_room">Upgrade public room</string>
|
||||||
|
<string name="upgrade_private_room">Upgrade private room</string>
|
||||||
|
<string name="upgrade_room_warning">Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.\nThis usually only affects how the room is processed on the server.</string>
|
||||||
|
<string name="upgrade_public_room_from_to">You\'ll upgrade this room from %s to %s.</string>
|
||||||
|
<string name="upgrade_room_auto_invite">Automatically invite users</string>
|
||||||
|
<string name="upgrade_room_update_parent_sapce">Automatically update space parent</string>
|
||||||
|
<string name="upgrade_room_update_parent">Automatically update parent space</string>
|
||||||
|
<string name="upgrade_room_no_power_to_manage">You need permission to upgrade a room</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user