diff --git a/newsfragment/1458.feature b/newsfragment/1458.feature new file mode 100644 index 0000000000..ded4f549ed --- /dev/null +++ b/newsfragment/1458.feature @@ -0,0 +1 @@ +Allow user to add custom "network" in room search \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/core/ui/list/GenericSpaceItem.kt b/vector/src/main/java/im/vector/app/core/ui/list/GenericSpaceItem.kt new file mode 100644 index 0000000000..137fac9abe --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/ui/list/GenericSpaceItem.kt @@ -0,0 +1,45 @@ +/* + * Copyright 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.core.ui.list + +import android.view.View +import androidx.core.view.updateLayoutParams +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 item with empty space. + */ +@EpoxyModelClass(layout = R.layout.item_generic_space) +abstract class GenericSpaceItem : VectorEpoxyModel() { + + @EpoxyAttribute + var heightInPx: Int = 0 + + override fun bind(holder: Holder) { + super.bind(holder) + holder.space.updateLayoutParams { + height = heightInPx + } + } + + class Holder : VectorEpoxyHolder() { + val space by bind(R.id.item_generic_space) + } +} diff --git a/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt b/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt index b59b24fe55..47059128a1 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt @@ -33,6 +33,9 @@ abstract class SettingsContinueCancelItem : EpoxyModelWithHolder() { @EpoxyAttribute var inputType: Int? = null + // TODO Should be true by default @EpoxyAttribute var singleLine: Boolean? = null diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryServer.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryServer.kt index 63ca4998f4..0f29ae5986 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryServer.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryServer.kt @@ -24,6 +24,11 @@ data class RoomDirectoryServer( */ val isUserServer: Boolean, + /** + * True if manually added, so it can be removed by the user + */ + val isManuallyAdded: Boolean, + /** * Supported protocols * TODO Rename RoomDirectoryData to RoomDirectoryProtocols diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt index e3cd9278a3..65d8f2d1cb 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt @@ -29,7 +29,8 @@ class RoomDirectoryListCreator @Inject constructor( private val session: Session ) { - fun computeDirectories(thirdPartyProtocolData: Map): List { + fun computeDirectories(thirdPartyProtocolData: Map, + customHomeservers: Set): List { val result = ArrayList() val protocols = ArrayList() @@ -75,6 +76,7 @@ class RoomDirectoryListCreator @Inject constructor( RoomDirectoryServer( serverName = userHsName, isUserServer = true, + isManuallyAdded = false, protocols = protocols ) ) @@ -88,6 +90,7 @@ class RoomDirectoryListCreator @Inject constructor( RoomDirectoryServer( serverName = it, isUserServer = false, + isManuallyAdded = false, protocols = listOf( RoomDirectoryData( homeServer = it, @@ -99,7 +102,25 @@ class RoomDirectoryListCreator @Inject constructor( ) } - // TODO Add manually added server by the user + // Add manually added server by the user + customHomeservers + .forEach { + // Use the server name as a default display name + result.add( + RoomDirectoryServer( + serverName = it, + isUserServer = false, + isManuallyAdded = true, + protocols = listOf( + RoomDirectoryData( + homeServer = it, + displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME, + includeAllNetworks = false + ) + ) + ) + ) + } return result } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt index 36f2cd4296..8be3c6b2b2 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt @@ -17,7 +17,14 @@ package im.vector.app.features.roomdirectory.picker import im.vector.app.core.platform.VectorViewModelAction +import im.vector.app.features.roomdirectory.RoomDirectoryServer sealed class RoomDirectoryPickerAction : VectorViewModelAction { object Retry : RoomDirectoryPickerAction() + object EnterEditMode : RoomDirectoryPickerAction() + object ExitEditMode : RoomDirectoryPickerAction() + data class SetServerUrl(val url: String) : RoomDirectoryPickerAction() + data class RemoveServer(val roomDirectoryServer: RoomDirectoryServer) : RoomDirectoryPickerAction() + + object Submit : RoomDirectoryPickerAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt index c3f461cb46..0a28ad5d52 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt @@ -16,10 +16,14 @@ package im.vector.app.features.roomdirectory.picker +import android.text.InputType +import android.view.View import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Incomplete +import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized import im.vector.app.R import im.vector.app.core.epoxy.dividerItem import im.vector.app.core.epoxy.errorWithRetryItem @@ -28,13 +32,22 @@ import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.extensions.join import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider +import im.vector.app.core.ui.list.genericButtonItem +import im.vector.app.core.ui.list.genericSpaceItem +import im.vector.app.core.utils.DimensionConverter +import im.vector.app.features.discovery.settingsContinueCancelItem +import im.vector.app.features.discovery.settingsInformationItem +import im.vector.app.features.form.formEditTextItem import im.vector.app.features.roomdirectory.RoomDirectoryData import im.vector.app.features.roomdirectory.RoomDirectoryServer +import org.matrix.android.sdk.api.failure.Failure import javax.inject.Inject +import javax.net.ssl.HttpsURLConnection class RoomDirectoryPickerController @Inject constructor( private val stringProvider: StringProvider, - colorProvider: ColorProvider, + private val colorProvider: ColorProvider, + private val dimensionConverter: DimensionConverter, private val errorFormatter: ErrorFormatter, private val roomDirectoryListCreator: RoomDirectoryListCreator ) : TypedEpoxyController() { @@ -44,16 +57,24 @@ class RoomDirectoryPickerController @Inject constructor( private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color) - override fun buildModels(viewState: RoomDirectoryPickerViewState) { + override fun buildModels(data: RoomDirectoryPickerViewState) { val host = this - when (val asyncThirdPartyProtocol = viewState.asyncThirdPartyRequest) { + when (val asyncThirdPartyProtocol = data.asyncThirdPartyRequest) { is Success -> { - val directories = roomDirectoryListCreator.computeDirectories(asyncThirdPartyProtocol()) + val directories = roomDirectoryListCreator.computeDirectories( + asyncThirdPartyProtocol(), + data.customHomeservers + ) directories.join( each = { _, roomDirectoryServer -> buildDirectory(roomDirectoryServer) }, between = { idx, _ -> buildDivider(idx) } ) + buildForm(data) + genericSpaceItem { + id("space_bottom") + heightInPx(host.dimensionConverter.dpToPx(16)) + } } is Incomplete -> { loadingItem { @@ -70,6 +91,77 @@ class RoomDirectoryPickerController @Inject constructor( } } + private fun buildForm(data: RoomDirectoryPickerViewState) { + buildDivider(1000) + val host = this + if (data.inEditMode) { + genericSpaceItem { + id("form_space") + heightInPx(host.dimensionConverter.dpToPx(16)) + } + settingsInformationItem { + id("form_notice") + message(host.stringProvider.getString(R.string.directory_add_a_new_server_prompt)) + colorProvider(host.colorProvider) + } + genericSpaceItem { + id("form_space_2") + heightInPx(host.dimensionConverter.dpToPx(8)) + } + formEditTextItem { + id("edit") + showBottomSeparator(false) + value(data.enteredServer) + hint(host.stringProvider.getString(R.string.directory_server_placeholder)) + inputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI) + onTextChange { text -> + host.callback?.onEnterServerChange(text) + } + when (data.addServerAsync) { + Uninitialized -> enabled(true) + is Loading -> enabled(false) + is Success -> enabled(false) + is Fail -> { + enabled(true) + errorMessage(host.getErrorMessage(data.addServerAsync.error)) + } + } + } + when (data.addServerAsync) { + Uninitialized, + is Fail -> settingsContinueCancelItem { + id("continueCancel") + continueText(host.stringProvider.getString(R.string.ok)) + canContinue(data.enteredServer.isNotEmpty()) + continueOnClick { host.callback?.onSubmitServer() } + cancelOnClick { host.callback?.onCancelEnterServer() } + } + is Loading -> loadingItem { + id("addLoading") + } + is Success -> Unit /* This is a transitive state */ + } + } else { + genericButtonItem { + id("add") + text(host.stringProvider.getString(R.string.directory_add_a_new_server)) + textColor(host.colorProvider.getColor(R.color.riotx_accent)) + buttonClickAction(View.OnClickListener { + host.callback?.onStartEnterServer() + }) + } + } + } + + private fun getErrorMessage(error: Throwable): String { + return if (error is Failure.ServerError + && error.httpCode == HttpsURLConnection.HTTP_INTERNAL_ERROR /* 500 */) { + stringProvider.getString(R.string.directory_add_a_new_server_error) + } else { + errorFormatter.toHumanReadable(error) + } + } + private fun buildDivider(idx: Int) { val host = this dividerItem { @@ -81,8 +173,10 @@ class RoomDirectoryPickerController @Inject constructor( private fun buildDirectory(roomDirectoryServer: RoomDirectoryServer) { val host = this roomDirectoryServerItem { - id("server_" + roomDirectoryServer.serverName) + id("server_$roomDirectoryServer") serverName(roomDirectoryServer.serverName) + canRemove(roomDirectoryServer.isManuallyAdded) + removeListener { host.callback?.onRemoveServer(roomDirectoryServer) } if (roomDirectoryServer.isUserServer) { serverDescription(host.stringProvider.getString(R.string.directory_your_server)) @@ -91,7 +185,7 @@ class RoomDirectoryPickerController @Inject constructor( roomDirectoryServer.protocols.forEach { roomDirectoryData -> roomDirectoryItem { - id("server_" + roomDirectoryServer.serverName + "_proto_" + roomDirectoryData.displayName) + id("server_${roomDirectoryServer}_proto_$roomDirectoryData") directoryName( if (roomDirectoryData.includeAllNetworks) { host.stringProvider.getString(R.string.directory_server_all_rooms_on_server, roomDirectoryServer.serverName) @@ -117,5 +211,10 @@ class RoomDirectoryPickerController @Inject constructor( interface Callback { fun onRoomDirectoryClicked(roomDirectoryData: RoomDirectoryData) fun retry() + fun onStartEnterServer() + fun onEnterServerChange(server: String) + fun onSubmitServer() + fun onCancelEnterServer() + fun onRemoveServer(roomDirectoryServer: RoomDirectoryServer) } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt index 701e8632c4..e3c39a2ccb 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt @@ -28,20 +28,22 @@ 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.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding import im.vector.app.features.roomdirectory.RoomDirectoryAction import im.vector.app.features.roomdirectory.RoomDirectoryData +import im.vector.app.features.roomdirectory.RoomDirectoryServer import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel import im.vector.app.features.roomdirectory.RoomDirectoryViewModel import timber.log.Timber import javax.inject.Inject -// TODO Menu to add custom room directory (not done in RiotWeb so far...) class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory, private val roomDirectoryPickerController: RoomDirectoryPickerController ) : VectorBaseFragment(), + OnBackPressed, RoomDirectoryPickerController.Callback { private val viewModel: RoomDirectoryViewModel by activityViewModel() @@ -77,18 +79,6 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie super.onDestroyView() } - override fun getMenuRes() = R.menu.menu_directory_server_picker - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.action_add_custom_hs) { - // TODO - vectorBaseActivity.notImplemented("Entering custom homeserver") - return true - } - - return super.onOptionsItemSelected(item) - } - private fun setupRecyclerView() { views.roomDirectoryPickerList.configureWith(roomDirectoryPickerController) roomDirectoryPickerController.callback = this @@ -101,6 +91,26 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie sharedActionViewModel.post(RoomDirectorySharedAction.Back) } + override fun onStartEnterServer() { + pickerViewModel.handle(RoomDirectoryPickerAction.EnterEditMode) + } + + override fun onCancelEnterServer() { + pickerViewModel.handle(RoomDirectoryPickerAction.ExitEditMode) + } + + override fun onEnterServerChange(server: String) { + pickerViewModel.handle(RoomDirectoryPickerAction.SetServerUrl(server)) + } + + override fun onSubmitServer() { + pickerViewModel.handle(RoomDirectoryPickerAction.Submit) + } + + override fun onRemoveServer(roomDirectoryServer: RoomDirectoryServer) { + pickerViewModel.handle(RoomDirectoryPickerAction.RemoveServer(roomDirectoryServer)) + } + override fun onResume() { super.onResume() (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.select_room_directory) @@ -115,4 +125,16 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie // Populate list with Epoxy roomDirectoryPickerController.setData(state) } + + override fun onBackPressed(toolbarButton: Boolean): Boolean { + // Leave the add server mode if started + return withState(pickerViewModel) { + if (it.inEditMode) { + pickerViewModel.handle(RoomDirectoryPickerAction.ExitEditMode) + true + } else { + false + } + } + } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt index d85b7937a2..049293cafd 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt @@ -22,18 +22,24 @@ import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted -import dagger.assisted.AssistedInject import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.ui.UiStateRepository import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams -class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initialState: RoomDirectoryPickerViewState, - private val session: Session) - : VectorViewModel(initialState) { +class RoomDirectoryPickerViewModel @AssistedInject constructor( + @Assisted initialState: RoomDirectoryPickerViewState, + private val session: Session, + private val uiStateRepository: UiStateRepository +) : VectorViewModel(initialState) { @AssistedFactory interface Factory { @@ -51,6 +57,7 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initial init { load() + loadCustomRoomDirectoryHomeservers() } private fun load() { @@ -71,9 +78,89 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initial } } + private fun loadCustomRoomDirectoryHomeservers() { + setState { + copy( + customHomeservers = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId) + ) + } + } + override fun handle(action: RoomDirectoryPickerAction) { when (action) { - RoomDirectoryPickerAction.Retry -> load() + RoomDirectoryPickerAction.Retry -> load() + RoomDirectoryPickerAction.EnterEditMode -> handleEnterEditMode() + RoomDirectoryPickerAction.ExitEditMode -> handleExitEditMode() + is RoomDirectoryPickerAction.SetServerUrl -> handleSetServerUrl(action) + RoomDirectoryPickerAction.Submit -> handleSubmit() + is RoomDirectoryPickerAction.RemoveServer -> handleRemoveServer(action) + }.exhaustive + } + + private fun handleEnterEditMode() { + setState { + copy( + inEditMode = true, + enteredServer = "", + addServerAsync = Uninitialized + ) + } + } + + private fun handleExitEditMode() { + setState { + copy( + inEditMode = false, + enteredServer = "", + addServerAsync = Uninitialized + ) + } + } + + private fun handleSetServerUrl(action: RoomDirectoryPickerAction.SetServerUrl) { + setState { + copy( + enteredServer = action.url, + ) + } + } + + private fun handleSubmit() = withState { state -> + viewModelScope.launch { + setState { + copy(addServerAsync = Loading()) + } + try { + session.getPublicRooms( + server = state.enteredServer, + publicRoomsParams = PublicRoomsParams(limit = 1) + ) + // Success, let add the server to our local repository, and update the state + val newSet = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId) + state.enteredServer + uiStateRepository.setCustomRoomDirectoryHomeservers(session.sessionId, newSet) + setState { + copy( + inEditMode = false, + enteredServer = "", + addServerAsync = Uninitialized, + customHomeservers = newSet + ) + } + } catch (failure: Throwable) { + setState { + copy(addServerAsync = Fail(failure)) + } + } + } + } + + private fun handleRemoveServer(action: RoomDirectoryPickerAction.RemoveServer) { + val newSet = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId) - action.roomDirectoryServer.serverName + uiStateRepository.setCustomRoomDirectoryHomeservers(session.sessionId, newSet) + setState { + copy( + customHomeservers = newSet + ) } } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt index 61cf50e8dd..c78d4ac55c 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt @@ -22,5 +22,9 @@ import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol data class RoomDirectoryPickerViewState( - val asyncThirdPartyRequest: Async> = Uninitialized + val asyncThirdPartyRequest: Async> = Uninitialized, + val customHomeservers: Set = emptySet(), + val inEditMode: Boolean = false, + val enteredServer: String = "", + val addServerAsync: Async = Uninitialized ) : MvRxState diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryServerItem.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryServerItem.kt index 83acfa581c..6efb41d5b1 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryServerItem.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryServerItem.kt @@ -16,12 +16,16 @@ package im.vector.app.features.roomdirectory.picker +import android.view.View import android.widget.TextView +import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R +import im.vector.app.core.epoxy.ClickListener import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.epoxy.onClick import im.vector.app.core.extensions.setTextOrHide @EpoxyModelClass(layout = R.layout.item_room_directory_server) @@ -33,14 +37,23 @@ abstract class RoomDirectoryServerItem : VectorEpoxyModel(R.id.itemRoomDirectoryServerName) val descriptionView by bind(R.id.itemRoomDirectoryServerDescription) + val deleteView by bind(R.id.itemRoomDirectoryServerRemove) } } diff --git a/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt b/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt index 1ec3a8ab46..e46c3516ca 100644 --- a/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt +++ b/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt @@ -39,7 +39,7 @@ class SharedPreferencesUiStateRepository @Inject constructor( override fun getDisplayMode(): RoomListDisplayMode { return when (sharedPreferences.getInt(KEY_DISPLAY_MODE, VALUE_DISPLAY_MODE_CATCHUP)) { VALUE_DISPLAY_MODE_PEOPLE -> RoomListDisplayMode.PEOPLE - VALUE_DISPLAY_MODE_ROOMS -> RoomListDisplayMode.ROOMS + VALUE_DISPLAY_MODE_ROOMS -> RoomListDisplayMode.ROOMS else -> if (vectorPreferences.labAddNotificationTab()) { RoomListDisplayMode.NOTIFICATIONS } else { @@ -89,6 +89,18 @@ class SharedPreferencesUiStateRepository @Inject constructor( return sharedPreferences.getBoolean("$KEY_SELECTED_METHOD@$sessionId", true) } + override fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set) { + sharedPreferences.edit { + putStringSet("$KEY_CUSTOM_DIRECTORY_HOMESERVER@$sessionId", servers) + } + } + + override fun getCustomRoomDirectoryHomeservers(sessionId: String): Set { + return sharedPreferences.getStringSet("$KEY_CUSTOM_DIRECTORY_HOMESERVER@$sessionId", null) + .orEmpty() + .toSet() + } + companion object { private const val KEY_DISPLAY_MODE = "UI_STATE_DISPLAY_MODE" private const val VALUE_DISPLAY_MODE_CATCHUP = 0 @@ -98,5 +110,7 @@ class SharedPreferencesUiStateRepository @Inject constructor( private const val KEY_SELECTED_SPACE = "UI_STATE_SELECTED_SPACE" private const val KEY_SELECTED_GROUP = "UI_STATE_SELECTED_GROUP" private const val KEY_SELECTED_METHOD = "UI_STATE_SELECTED_METHOD" + + private const val KEY_CUSTOM_DIRECTORY_HOMESERVER = "KEY_CUSTOM_DIRECTORY_HOMESERVER" } } diff --git a/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt b/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt index 935da83f5d..3c48f8972d 100644 --- a/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt +++ b/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt @@ -32,6 +32,7 @@ interface UiStateRepository { fun storeDisplayMode(displayMode: RoomListDisplayMode) + // TODO Handle SharedPreference per session in a better way, also to cleanup when login out fun storeSelectedSpace(spaceId: String?, sessionId: String) fun storeSelectedGroup(groupId: String?, sessionId: String) @@ -40,4 +41,7 @@ interface UiStateRepository { fun getSelectedSpace(sessionId: String): String? fun getSelectedGroup(sessionId: String): String? fun isGroupingMethodSpace(sessionId: String): Boolean + + fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set) + fun getCustomRoomDirectoryHomeservers(sessionId: String): Set } diff --git a/vector/src/main/res/layout/item_generic_space.xml b/vector/src/main/res/layout/item_generic_space.xml new file mode 100644 index 0000000000..aef6664f94 --- /dev/null +++ b/vector/src/main/res/layout/item_generic_space.xml @@ -0,0 +1,5 @@ + + diff --git a/vector/src/main/res/layout/item_room_directory_server.xml b/vector/src/main/res/layout/item_room_directory_server.xml index 5459652e2c..5705e1c623 100644 --- a/vector/src/main/res/layout/item_room_directory_server.xml +++ b/vector/src/main/res/layout/item_room_directory_server.xml @@ -12,7 +12,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/layout_horizontal_margin" - android:layout_marginEnd="@dimen/layout_horizontal_margin" + android:layout_marginEnd="8dp" android:ellipsize="end" android:lines="1" android:maxLines="2" @@ -20,10 +20,11 @@ android:textSize="16sp" android:textStyle="bold" app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryServerDescription" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@id/itemRoomDirectoryServerRemove" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" + app:layout_goneMarginEnd="@dimen/layout_horizontal_margin" tools:text="@tools:sample/lorem/random" /> + + \ No newline at end of file diff --git a/vector/src/main/res/menu/menu_directory_server_picker.xml b/vector/src/main/res/menu/menu_directory_server_picker.xml deleted file mode 100644 index c544c80f8c..0000000000 --- a/vector/src/main/res/menu/menu_directory_server_picker.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 442b79b5b0..7b8a933d30 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1584,10 +1584,13 @@ Select a room directory The server may be unavailable or overloaded Type a homeserver to list public rooms from - Homeserver URL + Server name All rooms on %s server All native %s rooms Your server + Add a new server + Enter the name of a new server you want to explore. + "Can't find this server or its room list" Type hereā€¦