diff --git a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt index 86f2d26808..826ada358b 100644 --- a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt +++ b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt @@ -127,14 +127,6 @@ class RxRoom(private val room: Room) { room.updateName(name, it) } - fun addRoomAlias(alias: String): Completable = completableBuilder { - room.addRoomAlias(alias, it) - } - - fun updateCanonicalAlias(alias: String): Completable = completableBuilder { - room.updateCanonicalAlias(alias, it) - } - fun updateHistoryReadability(readability: RoomHistoryVisibility): Completable = completableBuilder { room.updateHistoryReadability(readability, it) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt index 837bda031b..cb6690b5c5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.room import androidx.lifecycle.LiveData import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.session.room.alias.AliasService import org.matrix.android.sdk.api.session.room.call.RoomCallService import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService import org.matrix.android.sdk.api.session.room.members.MembershipService @@ -46,6 +47,7 @@ interface Room : DraftService, ReadService, TypingService, + AliasService, TagsService, MembershipService, StateService, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/AliasService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/AliasService.kt new file mode 100644 index 0000000000..c7d5657157 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/AliasService.kt @@ -0,0 +1,24 @@ +/* + * 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.room.alias + +interface AliasService { + /** + * Get list of local alias of the room + */ + suspend fun getRoomAliases(): List +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt index c7bb640f7c..7a819250cf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt @@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.alias.AliasService import org.matrix.android.sdk.api.session.room.call.RoomCallService import org.matrix.android.sdk.api.session.room.members.MembershipService import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -58,6 +59,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String, private val roomCallService: RoomCallService, private val readService: ReadService, private val typingService: TypingService, + private val aliasService: AliasService, private val tagsService: TagsService, private val cryptoService: CryptoService, private val relationService: RelationService, @@ -76,6 +78,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String, RoomCallService by roomCallService, ReadService by readService, TypingService by typingService, + AliasService by aliasService, TagsService by tagsService, RelationService by relationService, MembershipService by roomMembersService, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index fc80842f73..f0a8dc5177 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtoc import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.network.NetworkConstants import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasBody +import org.matrix.android.sdk.internal.session.room.alias.GetAliasesResponse import org.matrix.android.sdk.internal.session.room.alias.RoomAliasDescription import org.matrix.android.sdk.internal.session.room.create.CreateRoomBody import org.matrix.android.sdk.internal.session.room.create.CreateRoomResponse @@ -332,10 +333,17 @@ internal interface RoomAPI { * Add alias to the room. * @param roomAlias the room alias. */ + // TODO Remove (https://github.com/matrix-org/matrix-doc/blob/rav/proposal/alt_canonical_aliases/proposals/2432-revised-alias-publishing.md) @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}") fun addRoomAlias(@Path("roomAlias") roomAlias: String, @Body body: AddRoomAliasBody): Call + /** + * Get local aliases of this room + */ + @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc2432/rooms/{roomId}/aliases") + fun getAliases(@Path("roomId") roomId: String): Call + /** * Inform that the user is starting to type or has stopped typing */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt index d4fa040d06..63370a1ad8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.room import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService import org.matrix.android.sdk.internal.session.room.membership.DefaultMembershipService @@ -54,6 +55,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: private val roomCallServiceFactory: DefaultRoomCallService.Factory, private val readServiceFactory: DefaultReadService.Factory, private val typingServiceFactory: DefaultTypingService.Factory, + private val aliasServiceFactory: DefaultAliasService.Factory, private val tagsServiceFactory: DefaultTagsService.Factory, private val relationServiceFactory: DefaultRelationService.Factory, private val membershipServiceFactory: DefaultMembershipService.Factory, @@ -76,6 +78,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: roomCallService = roomCallServiceFactory.create(roomId), readService = readServiceFactory.create(roomId), typingService = typingServiceFactory.create(roomId), + aliasService = aliasServiceFactory.create(roomId), tagsService = tagsServiceFactory.create(roomId), cryptoService = cryptoService, relationService = relationServiceFactory.create(roomId), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index 6381796ee0..70721264bd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -29,7 +29,9 @@ import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask import org.matrix.android.sdk.internal.session.room.alias.DefaultAddRoomAliasTask import org.matrix.android.sdk.internal.session.room.alias.DefaultGetRoomIdByAliasTask +import org.matrix.android.sdk.internal.session.room.alias.DefaultGetRoomLocalAliasesTask import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask +import org.matrix.android.sdk.internal.session.room.alias.GetRoomLocalAliasesTask import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask import org.matrix.android.sdk.internal.session.room.directory.DefaultGetPublicRoomTask @@ -181,6 +183,9 @@ internal abstract class RoomModule { @Binds abstract fun bindGetRoomIdByAliasTask(task: DefaultGetRoomIdByAliasTask): GetRoomIdByAliasTask + @Binds + abstract fun bindGetRoomLocalAliasesTask(task: DefaultGetRoomLocalAliasesTask): GetRoomLocalAliasesTask + @Binds abstract fun bindAddRoomAliasTask(task: DefaultAddRoomAliasTask): AddRoomAliasTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DefaultAliasService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DefaultAliasService.kt new file mode 100644 index 0000000000..129eb82333 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DefaultAliasService.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.alias + +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import org.matrix.android.sdk.api.session.room.alias.AliasService + +internal class DefaultAliasService @AssistedInject constructor( + @Assisted private val roomId: String, + private val getRoomLocalAliasesTask: GetRoomLocalAliasesTask +) : AliasService { + + @AssistedInject.Factory + interface Factory { + fun create(roomId: String): AliasService + } + + override suspend fun getRoomAliases(): List { + return getRoomLocalAliasesTask.execute(GetRoomLocalAliasesTask.Params(roomId)) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetAliasesResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetAliasesResponse.kt new file mode 100644 index 0000000000..499abf33aa --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetAliasesResponse.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.alias + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class GetAliasesResponse( + /** + * The list of aliases currently defined on the local server for the given room + */ + @Json(name = "aliases") val aliases: List = emptyList() +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomLocalAliasesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomLocalAliasesTask.kt new file mode 100644 index 0000000000..7cfce4ecdc --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomLocalAliasesTask.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.alias + +import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.session.room.RoomAPI +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface GetRoomLocalAliasesTask : Task> { + data class Params( + val roomId: String + ) +} + +internal class DefaultGetRoomLocalAliasesTask @Inject constructor( + private val roomAPI: RoomAPI, + private val eventBus: EventBus +) : GetRoomLocalAliasesTask { + + override suspend fun execute(params: GetRoomLocalAliasesTask.Params): List { + // We do not check for "org.matrix.msc2432", so the API may be missing + val response = executeRequest(eventBus) { + apiCall = roomAPI.getAliases(roomId = params.roomId) + } + + return response.aliases + } +} diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index 32c98922fb..60c14d1579 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -83,6 +83,7 @@ import im.vector.app.features.roomprofile.RoomProfileFragment import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment import im.vector.app.features.roomprofile.members.RoomMemberListFragment import im.vector.app.features.roomprofile.settings.RoomSettingsFragment +import im.vector.app.features.roomprofile.alias.RoomAliasFragment import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment @@ -363,6 +364,11 @@ interface FragmentModule { @FragmentKey(RoomSettingsFragment::class) fun bindRoomSettingsFragment(fragment: RoomSettingsFragment): Fragment + @Binds + @IntoMap + @FragmentKey(RoomAliasFragment::class) + fun bindRoomAliasFragment(fragment: RoomAliasFragment): Fragment + @Binds @IntoMap @FragmentKey(RoomMemberProfileFragment::class) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt index 609042ffa4..2204150a35 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt @@ -36,6 +36,7 @@ import im.vector.app.features.room.RequireActiveMembershipViewState import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment import im.vector.app.features.roomprofile.members.RoomMemberListFragment import im.vector.app.features.roomprofile.settings.RoomSettingsFragment +import im.vector.app.features.roomprofile.alias.RoomAliasFragment import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment import javax.inject.Inject @@ -100,6 +101,7 @@ class RoomProfileActivity : when (sharedAction) { is RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers() is RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings() + is RoomProfileSharedAction.OpenRoomAlias -> openRoomAlias() is RoomProfileSharedAction.OpenRoomUploads -> openRoomUploads() is RoomProfileSharedAction.OpenBannedRoomMembers -> openBannedRoomMembers() } @@ -135,6 +137,10 @@ class RoomProfileActivity : addFragmentToBackstack(R.id.simpleFragmentContainer, RoomSettingsFragment::class.java, roomProfileArgs) } + private fun openRoomAlias() { + addFragmentToBackstack(R.id.simpleFragmentContainer, RoomAliasFragment::class.java, roomProfileArgs) + } + private fun openRoomMembers() { addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt index 0052ddee99..0449f0db15 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt @@ -23,6 +23,7 @@ import im.vector.app.core.platform.VectorSharedAction */ sealed class RoomProfileSharedAction : VectorSharedAction { object OpenRoomSettings : RoomProfileSharedAction() + object OpenRoomAlias : RoomProfileSharedAction() object OpenRoomUploads : RoomProfileSharedAction() object OpenRoomMembers : RoomProfileSharedAction() object OpenBannedRoomMembers : RoomProfileSharedAction() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasAction.kt new file mode 100644 index 0000000000..cb5916747a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasAction.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2020 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.roomprofile.alias + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class RoomAliasAction : VectorViewModelAction { + // Canonical + data class AddAlias(val alias: String) : RoomAliasAction() + data class RemoveAlias(val alias: String) : RoomAliasAction() + data class SetCanonicalAlias(val canonicalAlias: String) : RoomAliasAction() + object UnSetCanonicalAlias : RoomAliasAction() + + // Local + data class AddLocalAlias(val aliasLocalPart: String) : RoomAliasAction() + data class RemoveLocalAlias(val alias: String) : RoomAliasAction() +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt new file mode 100644 index 0000000000..b8e1a12688 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt @@ -0,0 +1,120 @@ +/* + * Copyright 2020 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.roomprofile.alias + +import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized +import im.vector.app.R +import im.vector.app.core.epoxy.errorWithRetryItem +import im.vector.app.core.epoxy.loadingItem +import im.vector.app.core.epoxy.profiles.buildProfileSection +import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.discovery.settingsInfoItem +import im.vector.app.features.settings.threepids.threePidItem +import javax.inject.Inject + +class RoomAliasController @Inject constructor( + private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter, + colorProvider: ColorProvider +) : TypedEpoxyController() { + + interface Callback { + fun removeAlias(altAlias: String) + fun setCanonicalAlias(alias: String) + fun unsetCanonicalAlias() + fun addLocalAlias(alias: String) + fun removeLocalAlias(alias: String) + } + + private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color) + + var callback: Callback? = null + + init { + setData(null) + } + + override fun buildModels(data: RoomAliasViewState?) { + data ?: return + + buildProfileSection( + stringProvider.getString(R.string.room_alias_published_alias_title) + ) + settingsInfoItem { + id("publishedInfo") + helperTextResId(R.string.room_alias_published_alias_subtitle) + } + + // TODO Canonical + if (data.alternativeAliases.isNotEmpty()) { + settingsInfoItem { + id("otherPublished") + helperTextResId(R.string.room_alias_published_other) + } + data.alternativeAliases.forEachIndexed { idx, altAlias -> + // TODO Rename this item to a more generic name + threePidItem { + id("alt_$idx") + title(altAlias) + deleteClickListener { callback?.removeAlias(altAlias) } + } + } + } + + // Local + buildProfileSection( + stringProvider.getString(R.string.room_alias_local_address_title) + ) + settingsInfoItem { + id("localInfo") + helperText(stringProvider.getString(R.string.room_alias_local_address_subtitle, data.homeServerName)) + } + + buildLocalInfo(data) + } + + private fun buildLocalInfo(data: RoomAliasViewState) { + when (val localAliases = data.localAliases) { + is Uninitialized -> { + loadingItem { + id("loadingAliases") + } + } + is Success -> { + localAliases().forEachIndexed { idx, localAlias -> + // TODO Rename this item to a more generic name + threePidItem { + id("loc_$idx") + title(localAlias) + deleteClickListener { callback?.removeLocalAlias(localAlias) } + } + } + } + is Fail -> { + errorWithRetryItem { + id("alt_error") + text(errorFormatter.toHumanReadable(localAliases.error)) + } + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt new file mode 100644 index 0000000000..3947937643 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2020 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.roomprofile.alias + +import android.os.Bundle +import android.view.View +import androidx.core.view.isVisible +import com.airbnb.mvrx.args +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import im.vector.app.R +import im.vector.app.core.extensions.cleanup +import im.vector.app.core.extensions.configureWith +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.utils.toast +import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.roomprofile.RoomProfileArgs +import kotlinx.android.synthetic.main.fragment_room_setting_generic.* +import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import org.matrix.android.sdk.api.util.toMatrixItem +import javax.inject.Inject + +class RoomAliasFragment @Inject constructor( + val viewModelFactory: RoomAliasViewModel.Factory, + private val controller: RoomAliasController, + private val avatarRenderer: AvatarRenderer +) : + VectorBaseFragment(), + RoomAliasController.Callback { + + private val viewModel: RoomAliasViewModel by fragmentViewModel() + private val roomProfileArgs: RoomProfileArgs by args() + + override fun getLayoutResId() = R.layout.fragment_room_setting_generic + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + controller.callback = this + setupToolbar(roomSettingsToolbar) + roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) + waiting_view_status_text.setText(R.string.please_wait) + waiting_view_status_text.isVisible = true + + viewModel.observeViewEvents { + when (it) { + is RoomAliasViewEvents.Failure -> showFailure(it.throwable) + RoomAliasViewEvents.Success -> showSuccess() + }.exhaustive + } + } + + private fun showSuccess() { + activity?.toast(R.string.room_settings_save_success) + } + + override fun onDestroyView() { + controller.callback = null + roomSettingsRecyclerView.cleanup() + super.onDestroyView() + } + + override fun invalidate() = withState(viewModel) { viewState -> + controller.setData(viewState) + renderRoomSummary(viewState) + } + + private fun renderRoomSummary(state: RoomAliasViewState) { + waiting_view.isVisible = state.isLoading + + state.roomSummary()?.let { + roomSettingsToolbarTitleView.text = it.displayName + avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView) + } + + invalidateOptionsMenu() + } + + override fun removeAlias(altAlias: String) { + viewModel.handle(RoomAliasAction.RemoveAlias(altAlias)) + } + + override fun setCanonicalAlias(alias: String) { + viewModel.handle(RoomAliasAction.SetCanonicalAlias(alias)) + } + + override fun unsetCanonicalAlias() { + viewModel.handle(RoomAliasAction.UnSetCanonicalAlias) + } + + override fun addLocalAlias(alias: String) { + viewModel.handle(RoomAliasAction.AddLocalAlias(alias)) + } + + override fun removeLocalAlias(alias: String) { + viewModel.handle(RoomAliasAction.RemoveLocalAlias(alias)) + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewEvents.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewEvents.kt new file mode 100644 index 0000000000..bbd44741b5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewEvents.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2020 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.roomprofile.alias + +import im.vector.app.core.platform.VectorViewEvents + +/** + * Transient events for room settings screen + */ +sealed class RoomAliasViewEvents : VectorViewEvents { + data class Failure(val throwable: Throwable) : RoomAliasViewEvents() + object Success : RoomAliasViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt new file mode 100644 index 0000000000..104b003387 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt @@ -0,0 +1,182 @@ +/* + * Copyright 2020 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.roomprofile.alias + +import androidx.lifecycle.viewModelScope +import com.airbnb.mvrx.Fail +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 com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.session.Session +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.RoomCanonicalAliasContent +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper +import org.matrix.android.sdk.rx.mapOptional +import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.rx.unwrap + +class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: RoomAliasViewState, + private val session: Session) + : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: RoomAliasViewState): RoomAliasViewModel + } + + companion object : MvRxViewModelFactory { + + @JvmStatic + override fun create(viewModelContext: ViewModelContext, state: RoomAliasViewState): RoomAliasViewModel? { + val fragment: RoomAliasFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.viewModelFactory.create(state) + } + } + + private val room = session.getRoom(initialState.roomId)!! + + init { + initHomeServerName() + observeRoomSummary() + observeMowerLevel() + observeRoomCanonicalAlias() + getRoomAlias() + } + + private fun initHomeServerName() { + setState { + copy( + homeServerName = session.myUserId.substringAfter(":") + ) + } + } + + private fun getRoomAlias() { + setState { + copy( + localAliases = Loading() + ) + } + + viewModelScope.launch { + runCatching { room.getRoomAliases() } + .fold( + { + setState { copy(localAliases = Success(it)) } + }, + { + setState { copy(localAliases = Fail(it)) } + } + ) + } + } + + private fun observeRoomSummary() { + room.rx().liveRoomSummary() + .unwrap() + .execute { async -> + copy( + roomSummary = async + ) + } + } + + private fun observeMowerLevel() { + PowerLevelsObservableFactory(room) + .createObservable() + .subscribe { + val powerLevelsHelper = PowerLevelsHelper(it) + val permissions = RoomAliasViewState.ActionPermissions( + canChangeCanonicalAlias = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, + EventType.STATE_ROOM_CANONICAL_ALIAS), + ) + setState { copy(actionPermissions = permissions) } + } + .disposeOnClear() + } + + /** + * We do not want to use the fallback avatar url, which can be the other user avatar, or the current user avatar. + */ + private fun observeRoomCanonicalAlias() { + room.rx() + .liveStateEvent(EventType.STATE_ROOM_CANONICAL_ALIAS, QueryStringValue.NoCondition) + .mapOptional { it.content.toModel() } + .unwrap() + .subscribe { + setState { + copy( + canonicalAlias = it.canonicalAlias, + alternativeAliases = it.alternativeAliases.orEmpty() + ) + } + } + .disposeOnClear() + } + + override fun handle(action: RoomAliasAction) { + when (action) { + is RoomAliasAction.AddAlias -> handleAddAlias(action) + is RoomAliasAction.RemoveAlias -> handleRemoveAlias(action) + is RoomAliasAction.SetCanonicalAlias -> handleSetCanonicalAlias(action) + RoomAliasAction.UnSetCanonicalAlias -> handleUnsetCanonicalAlias() + is RoomAliasAction.AddLocalAlias -> handleAddLocalAlias(action) + is RoomAliasAction.RemoveLocalAlias -> handleRemoveLocalAlias(action) + }.exhaustive + } + + private fun handleAddAlias(action: RoomAliasAction.AddAlias) { + TODO("Not yet implemented") + } + + private fun handleRemoveAlias(action: RoomAliasAction.RemoveAlias) { + TODO("Not yet implemented") + } + + private fun handleSetCanonicalAlias(action: RoomAliasAction.SetCanonicalAlias) { + //room.updateCanonicalAlias() + TODO("Not yet implemented") + } + + private fun handleUnsetCanonicalAlias() { + TODO("Not yet implemented") + } + + private fun handleAddLocalAlias(action: RoomAliasAction.AddLocalAlias) { + TODO("Not yet implemented") + } + + private fun handleRemoveLocalAlias(action: RoomAliasAction.RemoveLocalAlias) { + TODO("Not yet implemented") + } + + private fun postLoading(isLoading: Boolean) { + setState { + copy(isLoading = isLoading) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewState.kt new file mode 100644 index 0000000000..be9bde27a6 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewState.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2020 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.roomprofile.alias + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized +import im.vector.app.features.roomprofile.RoomProfileArgs +import org.matrix.android.sdk.api.session.room.model.RoomSummary + +data class RoomAliasViewState( + val roomId: String, + val homeServerName: String = "", + val roomSummary: Async = Uninitialized, + val isLoading: Boolean = false, + val canonicalAlias: String? = null, + val alternativeAliases: List = emptyList(), + val localAliases: Async> = Uninitialized, + val actionPermissions: ActionPermissions = ActionPermissions() +) : MvRxState { + + constructor(args: RoomProfileArgs) : this(roomId = args.roomId) + + data class ActionPermissions( + val canChangeCanonicalAlias: Boolean = false + ) +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt index f0a7b38478..f88a7cbfd5 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt @@ -24,7 +24,6 @@ sealed class RoomSettingsAction : VectorViewModelAction { data class SetRoomName(val newName: String) : RoomSettingsAction() data class SetRoomTopic(val newTopic: String) : RoomSettingsAction() data class SetRoomHistoryVisibility(val visibility: RoomHistoryVisibility) : RoomSettingsAction() - data class SetRoomCanonicalAlias(val newCanonicalAlias: String) : RoomSettingsAction() object Save : RoomSettingsAction() object Cancel : RoomSettingsAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index 3c73e6ed46..6c944ef2f8 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -46,7 +46,7 @@ class RoomSettingsController @Inject constructor( fun onNameChanged(name: String) fun onTopicChanged(topic: String) fun onHistoryVisibilityClicked() - fun onAliasChanged(alias: String) + fun onOpenAlias() } private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color) @@ -67,13 +67,13 @@ class RoomSettingsController @Inject constructor( id("avatar") enabled(data.actionPermissions.canChangeAvatar) when (val avatarAction = data.avatarAction) { - RoomSettingsViewState.AvatarAction.None -> { + RoomSettingsViewState.AvatarAction.None -> { // Use the current value avatarRenderer(avatarRenderer) // We do not want to use the fallback avatar url, which can be the other user avatar, or the current user avatar. matrixItem(roomSummary.toMatrixItem().copy(avatarUrl = data.currentRoomAvatarUrl)) } - RoomSettingsViewState.AvatarAction.DeleteAvatar -> + RoomSettingsViewState.AvatarAction.DeleteAvatar -> imageUri(null) is RoomSettingsViewState.AvatarAction.UpdateAvatar -> imageUri(avatarAction.newAvatarUri) @@ -108,16 +108,15 @@ class RoomSettingsController @Inject constructor( } } - formEditTextItem { - id("alias") - enabled(data.actionPermissions.canChangeCanonicalAlias) - value(data.newCanonicalAlias ?: roomSummary.canonicalAlias) - hint(stringProvider.getString(R.string.room_settings_addresses_add_new_address)) - - onTextChange { text -> - callback?.onAliasChanged(text) - } - } + buildProfileAction( + id = "alias", + title = stringProvider.getString(R.string.room_settings_alias_title), + subtitle = stringProvider.getString(R.string.room_settings_alias_subtitle), + dividerColor = dividerColor, + divider = true, + editable = true, + action = { callback?.onOpenAlias() } + ) buildProfileAction( id = "historyReadability", diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index 6637b7d943..01ee1cf9b8 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -39,6 +39,8 @@ import im.vector.app.core.utils.toast import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.format.RoomHistoryVisibilityFormatter import im.vector.app.features.roomprofile.RoomProfileArgs +import im.vector.app.features.roomprofile.RoomProfileSharedAction +import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel import kotlinx.android.synthetic.main.fragment_room_setting_generic.* import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* import org.matrix.android.sdk.api.session.events.model.toModel @@ -61,6 +63,7 @@ class RoomSettingsFragment @Inject constructor( GalleryOrCameraDialogHelper.Listener { private val viewModel: RoomSettingsViewModel by fragmentViewModel() + private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel private val roomProfileArgs: RoomProfileArgs by args() private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) @@ -70,6 +73,7 @@ class RoomSettingsFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + roomProfileSharedActionViewModel = activityViewModelProvider.get(RoomProfileSharedActionViewModel::class.java) controller.callback = this setupToolbar(roomSettingsToolbar) roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) @@ -164,8 +168,8 @@ class RoomSettingsFragment @Inject constructor( return@withState } - override fun onAliasChanged(alias: String) { - viewModel.handle(RoomSettingsAction.SetRoomCanonicalAlias(alias)) + override fun onOpenAlias() { + roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomAlias) } override fun onImageReady(uri: Uri?) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index 05a75a585b..7e76f85d44 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -68,12 +68,10 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: selectSubscribe( RoomSettingsViewState::avatarAction, RoomSettingsViewState::newName, - RoomSettingsViewState::newCanonicalAlias, RoomSettingsViewState::newTopic, RoomSettingsViewState::newHistoryVisibility, RoomSettingsViewState::roomSummary) { avatarAction, newName, - newCanonicalAlias, newTopic, newHistoryVisibility, asyncSummary -> @@ -83,7 +81,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: showSaveAction = avatarAction !is RoomSettingsViewState.AvatarAction.None || summary?.name != newName || summary?.topic != newTopic - || summary?.canonicalAlias != newCanonicalAlias?.takeIf { it.isNotEmpty() } || newHistoryVisibility != null ) } @@ -99,8 +96,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: historyVisibilityEvent = room.getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY), roomSummary = async, newName = roomSummary?.name, - newTopic = roomSummary?.topic, - newCanonicalAlias = roomSummary?.canonicalAlias + newTopic = roomSummary?.topic ) } @@ -113,8 +109,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR), canChangeName = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_NAME), canChangeTopic = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_TOPIC), - canChangeCanonicalAlias = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, - EventType.STATE_ROOM_CANONICAL_ALIAS), canChangeHistoryReadability = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_HISTORY_VISIBILITY) ) @@ -143,7 +137,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: is RoomSettingsAction.SetRoomName -> setState { copy(newName = action.newName) } is RoomSettingsAction.SetRoomTopic -> setState { copy(newTopic = action.newTopic) } is RoomSettingsAction.SetRoomHistoryVisibility -> setState { copy(newHistoryVisibility = action.visibility) } - is RoomSettingsAction.SetRoomCanonicalAlias -> setState { copy(newCanonicalAlias = action.newCanonicalAlias) } is RoomSettingsAction.Save -> saveSettings() is RoomSettingsAction.Cancel -> cancel() }.exhaustive @@ -191,11 +184,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: operationList.add(room.rx().updateTopic(state.newTopic ?: "")) } - if (state.newCanonicalAlias != null && summary?.canonicalAlias != state.newCanonicalAlias.takeIf { it.isNotEmpty() }) { - operationList.add(room.rx().addRoomAlias(state.newCanonicalAlias)) - operationList.add(room.rx().updateCanonicalAlias(state.newCanonicalAlias)) - } - if (state.newHistoryVisibility != null) { operationList.add(room.rx().updateHistoryReadability(state.newHistoryVisibility)) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt index 2cadc8f798..bdcd9e6bc7 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt @@ -35,7 +35,6 @@ data class RoomSettingsViewState( val newName: String? = null, val newTopic: String? = null, val newHistoryVisibility: RoomHistoryVisibility? = null, - val newCanonicalAlias: String? = null, val showSaveAction: Boolean = false, val actionPermissions: ActionPermissions = ActionPermissions() ) : MvRxState { @@ -46,7 +45,6 @@ data class RoomSettingsViewState( val canChangeAvatar: Boolean = false, val canChangeName: Boolean = false, val canChangeTopic: Boolean = false, - val canChangeCanonicalAlias: Boolean = false, val canChangeHistoryReadability: Boolean = false ) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 2cb6eb9af9..59bd17ee70 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1022,6 +1022,25 @@ Who can read history? Who can access this room? + + Room addresses + See and managed addresses of this room + + Room Addresses + Published Addresses + Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first. + Main address + Other published addresses: + + Publish this room to the public in %1$s\'s room directory? + No other published addresses yet, add one below + New published address (e.g. #alias:server) + + Local Addresses + + Set addresses for this room so users can find this room through your homeserver (%1$s) + This room has no local addresses + Anyone Members only (since the point in time of selecting this option)