Merge pull request #3419 from vector-im/feature/bma/gitter
Feature/bma/gitter
This commit is contained in:
commit
0db5dd3d50
|
@ -22,16 +22,16 @@ import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class ThirdPartyUser(
|
data class ThirdPartyUser(
|
||||||
/*
|
/**
|
||||||
Required. A Matrix User ID represting a third party user.
|
* Required. A Matrix User ID representing a third party user.
|
||||||
*/
|
*/
|
||||||
@Json(name = "userid") val userId: String,
|
@Json(name = "userid") val userId: String,
|
||||||
/*
|
/**
|
||||||
Required. The protocol ID that the third party location is a part of.
|
* Required. The protocol ID that the third party location is a part of.
|
||||||
*/
|
*/
|
||||||
@Json(name = "protocol") val protocol: String,
|
@Json(name = "protocol") val protocol: String,
|
||||||
/*
|
/**
|
||||||
Required. Information used to identify this third party location.
|
* Required. Information used to identify this third party location.
|
||||||
*/
|
*/
|
||||||
@Json(name = "fields") val fields: JsonDict
|
@Json(name = "fields") val fields: JsonDict
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Allow user to add custom "network" in room search
|
|
@ -0,0 +1 @@
|
||||||
|
Add Gitter.im as a default in the Change Network menu
|
|
@ -94,6 +94,10 @@ fun <T : Fragment> AppCompatActivity.addFragmentToBackstack(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun AppCompatActivity.popBackstack() {
|
||||||
|
supportFragmentManager.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
fun AppCompatActivity.resetBackstack() {
|
fun AppCompatActivity.resetBackstack() {
|
||||||
repeat(supportFragmentManager.backStackEntryCount) {
|
repeat(supportFragmentManager.backStackEntryCount) {
|
||||||
supportFragmentManager.popBackStack()
|
supportFragmentManager.popBackStack()
|
||||||
|
|
|
@ -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_vertical_margin)
|
||||||
|
abstract class VerticalMarginItem : VectorEpoxyModel<VerticalMarginItem.Holder>() {
|
||||||
|
|
||||||
|
@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<View>(R.id.item_vertical_margin_space)
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,9 @@ abstract class SettingsContinueCancelItem : EpoxyModelWithHolder<SettingsContinu
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var continueOnClick: ClickListener? = null
|
var continueOnClick: ClickListener? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var canContinue: Boolean = true
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var cancelOnClick: ClickListener? = null
|
var cancelOnClick: ClickListener? = null
|
||||||
|
|
||||||
|
@ -43,6 +46,7 @@ abstract class SettingsContinueCancelItem : EpoxyModelWithHolder<SettingsContinu
|
||||||
|
|
||||||
continueText?.let { holder.continueButton.text = it }
|
continueText?.let { holder.continueButton.text = it }
|
||||||
holder.continueButton.onClick(continueOnClick)
|
holder.continueButton.onClick(continueOnClick)
|
||||||
|
holder.continueButton.isEnabled = canContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.form
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
import com.airbnb.epoxy.EpoxyModelClass
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
@ -52,7 +53,7 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||||
var inputType: Int? = null
|
var inputType: Int? = null
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var singleLine: Boolean? = null
|
var singleLine: Boolean = true
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var imeOptions: Int? = null
|
var imeOptions: Int? = null
|
||||||
|
@ -60,9 +61,13 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var endIconMode: Int? = null
|
var endIconMode: Int? = null
|
||||||
|
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
// FIXME restore EpoxyAttribute.Option.DoNotHash and fix that properly
|
||||||
|
@EpoxyAttribute
|
||||||
var onTextChange: ((String) -> Unit)? = null
|
var onTextChange: ((String) -> Unit)? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var editorActionListener: TextView.OnEditorActionListener? = null
|
||||||
|
|
||||||
private val onTextChangeListener = object : SimpleTextWatcher() {
|
private val onTextChangeListener = object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
onTextChange?.invoke(s.toString())
|
onTextChange?.invoke(s.toString())
|
||||||
|
@ -80,10 +85,11 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||||
|
|
||||||
holder.textInputEditText.isEnabled = enabled
|
holder.textInputEditText.isEnabled = enabled
|
||||||
inputType?.let { holder.textInputEditText.inputType = it }
|
inputType?.let { holder.textInputEditText.inputType = it }
|
||||||
holder.textInputEditText.isSingleLine = singleLine ?: false
|
holder.textInputEditText.isSingleLine = singleLine
|
||||||
holder.textInputEditText.imeOptions = imeOptions ?: EditorInfo.IME_ACTION_NONE
|
holder.textInputEditText.imeOptions = imeOptions ?: EditorInfo.IME_ACTION_NONE
|
||||||
|
|
||||||
holder.textInputEditText.addTextChangedListener(onTextChangeListener)
|
holder.textInputEditText.addTextChangedListener(onTextChangeListener)
|
||||||
|
holder.textInputEditText.setOnEditorActionListener(editorActionListener)
|
||||||
holder.bottomSeparator.isVisible = showBottomSeparator
|
holder.bottomSeparator.isVisible = showBottomSeparator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ import im.vector.app.features.pin.PinActivity
|
||||||
import im.vector.app.features.pin.PinArgs
|
import im.vector.app.features.pin.PinArgs
|
||||||
import im.vector.app.features.pin.PinMode
|
import im.vector.app.features.pin.PinMode
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectoryActivity
|
import im.vector.app.features.roomdirectory.RoomDirectoryActivity
|
||||||
|
import im.vector.app.features.roomdirectory.RoomDirectoryData
|
||||||
import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
|
import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
|
||||||
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewActivity
|
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewActivity
|
||||||
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
|
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
|
||||||
|
@ -86,7 +87,6 @@ import im.vector.app.features.widgets.WidgetArgsBuilder
|
||||||
import im.vector.app.space
|
import im.vector.app.space
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||||
|
|
|
@ -26,11 +26,11 @@ import im.vector.app.features.crypto.recover.SetupMode
|
||||||
import im.vector.app.features.login.LoginConfig
|
import im.vector.app.features.login.LoginConfig
|
||||||
import im.vector.app.features.media.AttachmentData
|
import im.vector.app.features.media.AttachmentData
|
||||||
import im.vector.app.features.pin.PinMode
|
import im.vector.app.features.pin.PinMode
|
||||||
|
import im.vector.app.features.roomdirectory.RoomDirectoryData
|
||||||
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
|
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity
|
import im.vector.app.features.settings.VectorSettingsActivity
|
||||||
import im.vector.app.features.share.SharedData
|
import im.vector.app.features.share.SharedData
|
||||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
|
|
@ -21,7 +21,6 @@ import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
|
|
||||||
data class PublicRoomsViewState(
|
data class PublicRoomsViewState(
|
||||||
// The current filter
|
// The current filter
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package im.vector.app.features.roomdirectory
|
package im.vector.app.features.roomdirectory
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
|
|
||||||
sealed class RoomDirectoryAction : VectorViewModelAction {
|
sealed class RoomDirectoryAction : VectorViewModelAction {
|
||||||
data class SetRoomDirectoryData(val roomDirectoryData: RoomDirectoryData) : RoomDirectoryAction()
|
data class SetRoomDirectoryData(val roomDirectoryData: RoomDirectoryData) : RoomDirectoryAction()
|
||||||
|
|
|
@ -25,6 +25,7 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.di.ScreenComponent
|
import im.vector.app.core.di.ScreenComponent
|
||||||
import im.vector.app.core.extensions.addFragment
|
import im.vector.app.core.extensions.addFragment
|
||||||
import im.vector.app.core.extensions.addFragmentToBackstack
|
import im.vector.app.core.extensions.addFragmentToBackstack
|
||||||
|
import im.vector.app.core.extensions.popBackstack
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivitySimpleBinding
|
import im.vector.app.databinding.ActivitySimpleBinding
|
||||||
import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
|
import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
|
||||||
|
@ -58,7 +59,7 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
|
||||||
.observe()
|
.observe()
|
||||||
.subscribe { sharedAction ->
|
.subscribe { sharedAction ->
|
||||||
when (sharedAction) {
|
when (sharedAction) {
|
||||||
is RoomDirectorySharedAction.Back -> onBackPressed()
|
is RoomDirectorySharedAction.Back -> popBackstack()
|
||||||
is RoomDirectorySharedAction.CreateRoom -> {
|
is RoomDirectorySharedAction.CreateRoom -> {
|
||||||
// Transmit the filter to the CreateRoomFragment
|
// Transmit the filter to the CreateRoomFragment
|
||||||
withState(roomDirectoryViewModel) {
|
withState(roomDirectoryViewModel) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -14,13 +14,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.room.model.thirdparty
|
package im.vector.app.features.roomdirectory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class describes a rooms directory server.
|
* This class describes a rooms directory server protocol.
|
||||||
*/
|
*/
|
||||||
data class RoomDirectoryData(
|
data class RoomDirectoryData(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The server name (might be null)
|
* The server name (might be null)
|
||||||
* Set null when the server is the current user's home server.
|
* Set null when the server is the current user's home server.
|
||||||
|
@ -30,7 +29,12 @@ data class RoomDirectoryData(
|
||||||
/**
|
/**
|
||||||
* The display name (the server description)
|
* The display name (the server description)
|
||||||
*/
|
*/
|
||||||
val displayName: String = DEFAULT_HOME_SERVER_NAME,
|
val displayName: String = MATRIX_PROTOCOL_NAME,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the avatar url
|
||||||
|
*/
|
||||||
|
val avatarUrl: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The third party server identifier
|
* The third party server identifier
|
||||||
|
@ -40,15 +44,10 @@ data class RoomDirectoryData(
|
||||||
/**
|
/**
|
||||||
* Tell if all the federated servers must be included
|
* Tell if all the federated servers must be included
|
||||||
*/
|
*/
|
||||||
val includeAllNetworks: Boolean = false,
|
val includeAllNetworks: Boolean = false
|
||||||
|
|
||||||
/**
|
|
||||||
* the avatar url
|
|
||||||
*/
|
|
||||||
val avatarUrl: String? = null
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val DEFAULT_HOME_SERVER_NAME = "Matrix"
|
const val MATRIX_PROTOCOL_NAME = "Matrix"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.roomdirectory
|
||||||
|
|
||||||
|
data class RoomDirectoryServer(
|
||||||
|
val serverName: String,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if this is the current user server
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
val protocols: List<RoomDirectoryData>
|
||||||
|
)
|
|
@ -37,7 +37,6 @@ import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter
|
||||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.rx.rx
|
import org.matrix.android.sdk.rx.rx
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -230,9 +229,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(
|
||||||
Timber.w("Try to join an already joining room. Should not happen")
|
Timber.w("Try to join an already joining room. Should not happen")
|
||||||
return@withState
|
return@withState
|
||||||
}
|
}
|
||||||
val viaServers = state.roomDirectoryData.homeServer
|
val viaServers = listOfNotNull(state.roomDirectoryData.homeServer)
|
||||||
?.let { listOf(it) }
|
|
||||||
.orEmpty()
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
session.joinRoom(action.roomId, viaServers = viaServers)
|
session.joinRoom(action.roomId, viaServers = viaServers)
|
||||||
|
|
|
@ -75,6 +75,7 @@ class CreateRoomController @Inject constructor(
|
||||||
id("topic")
|
id("topic")
|
||||||
enabled(enableFormElement)
|
enabled(enableFormElement)
|
||||||
value(viewState.roomTopic)
|
value(viewState.roomTopic)
|
||||||
|
singleLine(false)
|
||||||
hint(host.stringProvider.getString(R.string.create_room_topic_hint))
|
hint(host.stringProvider.getString(R.string.create_room_topic_hint))
|
||||||
|
|
||||||
onTextChange { text ->
|
onTextChange { text ->
|
||||||
|
|
|
@ -16,10 +16,12 @@
|
||||||
|
|
||||||
package im.vector.app.features.roomdirectory.picker
|
package im.vector.app.features.roomdirectory.picker
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
import com.airbnb.epoxy.EpoxyModelClass
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
@ -43,6 +45,9 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var includeAllNetworks: Boolean = false
|
var includeAllNetworks: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var checked: Boolean = false
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var globalListener: (() -> Unit)? = null
|
var globalListener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
@ -63,6 +68,7 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
|
||||||
|
|
||||||
holder.nameView.text = directoryName
|
holder.nameView.text = directoryName
|
||||||
holder.descriptionView.setTextOrHide(directoryDescription)
|
holder.descriptionView.setTextOrHide(directoryDescription)
|
||||||
|
holder.checkedView.isVisible = checked
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
@ -71,5 +77,6 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
|
||||||
val avatarView by bind<ImageView>(R.id.itemRoomDirectoryAvatar)
|
val avatarView by bind<ImageView>(R.id.itemRoomDirectoryAvatar)
|
||||||
val nameView by bind<TextView>(R.id.itemRoomDirectoryName)
|
val nameView by bind<TextView>(R.id.itemRoomDirectoryName)
|
||||||
val descriptionView by bind<TextView>(R.id.itemRoomDirectoryDescription)
|
val descriptionView by bind<TextView>(R.id.itemRoomDirectoryDescription)
|
||||||
|
val checkedView by bind<View>(R.id.itemRoomDirectoryChecked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,55 +18,110 @@ package im.vector.app.features.roomdirectory.picker
|
||||||
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringArrayProvider
|
import im.vector.app.core.resources.StringArrayProvider
|
||||||
|
import im.vector.app.features.roomdirectory.RoomDirectoryData
|
||||||
|
import im.vector.app.features.roomdirectory.RoomDirectoryServer
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RoomDirectoryListCreator @Inject constructor(private val stringArrayProvider: StringArrayProvider,
|
class RoomDirectoryListCreator @Inject constructor(
|
||||||
private val session: Session) {
|
private val stringArrayProvider: StringArrayProvider,
|
||||||
|
private val session: Session
|
||||||
|
) {
|
||||||
|
|
||||||
fun computeDirectories(thirdPartyProtocolData: Map<String, ThirdPartyProtocol>): List<RoomDirectoryData> {
|
fun computeDirectories(thirdPartyProtocolData: Map<String, ThirdPartyProtocol>,
|
||||||
val result = ArrayList<RoomDirectoryData>()
|
customHomeservers: Set<String>): List<RoomDirectoryServer> {
|
||||||
|
val result = ArrayList<RoomDirectoryServer>()
|
||||||
|
|
||||||
|
val protocols = ArrayList<RoomDirectoryData>()
|
||||||
|
|
||||||
// Add user homeserver name
|
// Add user homeserver name
|
||||||
val userHsName = session.myUserId.substringAfter(":")
|
val userHsName = session.myUserId.substringAfter(":")
|
||||||
|
|
||||||
result.add(RoomDirectoryData(
|
// Add default protocol
|
||||||
displayName = userHsName,
|
protocols.add(
|
||||||
includeAllNetworks = true
|
RoomDirectoryData(
|
||||||
))
|
homeServer = null,
|
||||||
|
displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME,
|
||||||
// Add user's HS but for Matrix public rooms only
|
includeAllNetworks = false
|
||||||
result.add(RoomDirectoryData())
|
)
|
||||||
|
)
|
||||||
// Add custom directory servers
|
|
||||||
val hsNamesList = stringArrayProvider.getStringArray(R.array.room_directory_servers)
|
|
||||||
hsNamesList.forEach {
|
|
||||||
if (it != userHsName) {
|
|
||||||
// Use the server name as a default display name
|
|
||||||
result.add(RoomDirectoryData(
|
|
||||||
homeServer = it,
|
|
||||||
displayName = it,
|
|
||||||
includeAllNetworks = true
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add result of the request
|
// Add result of the request
|
||||||
thirdPartyProtocolData.forEach {
|
thirdPartyProtocolData.forEach {
|
||||||
it.value.instances?.forEach { thirdPartyProtocolInstance ->
|
it.value.instances?.forEach { thirdPartyProtocolInstance ->
|
||||||
result.add(RoomDirectoryData(
|
protocols.add(
|
||||||
|
RoomDirectoryData(
|
||||||
homeServer = null,
|
homeServer = null,
|
||||||
displayName = thirdPartyProtocolInstance.desc ?: "",
|
displayName = thirdPartyProtocolInstance.desc ?: "",
|
||||||
thirdPartyInstanceId = thirdPartyProtocolInstance.instanceId,
|
thirdPartyInstanceId = thirdPartyProtocolInstance.instanceId,
|
||||||
includeAllNetworks = false,
|
includeAllNetworks = false,
|
||||||
// Default to protocol icon
|
// Default to protocol icon
|
||||||
avatarUrl = thirdPartyProtocolInstance.icon ?: it.value.icon
|
avatarUrl = thirdPartyProtocolInstance.icon ?: it.value.icon
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add all rooms
|
||||||
|
protocols.add(
|
||||||
|
RoomDirectoryData(
|
||||||
|
homeServer = null,
|
||||||
|
displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME,
|
||||||
|
includeAllNetworks = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
result.add(
|
||||||
|
RoomDirectoryServer(
|
||||||
|
serverName = userHsName,
|
||||||
|
isUserServer = true,
|
||||||
|
isManuallyAdded = false,
|
||||||
|
protocols = protocols
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add custom directory servers, form the config file, excluding the current user homeserver
|
||||||
|
stringArrayProvider.getStringArray(R.array.room_directory_servers)
|
||||||
|
.filter { it != userHsName }
|
||||||
|
.forEach {
|
||||||
|
// Use the server name as a default display name
|
||||||
|
result.add(
|
||||||
|
RoomDirectoryServer(
|
||||||
|
serverName = it,
|
||||||
|
isUserServer = false,
|
||||||
|
isManuallyAdded = false,
|
||||||
|
protocols = listOf(
|
||||||
|
RoomDirectoryData(
|
||||||
|
homeServer = it,
|
||||||
|
displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME,
|
||||||
|
includeAllNetworks = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,14 @@
|
||||||
package im.vector.app.features.roomdirectory.picker
|
package im.vector.app.features.roomdirectory.picker
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
import im.vector.app.features.roomdirectory.RoomDirectoryServer
|
||||||
|
|
||||||
sealed class RoomDirectoryPickerAction : VectorViewModelAction {
|
sealed class RoomDirectoryPickerAction : VectorViewModelAction {
|
||||||
object Retry : RoomDirectoryPickerAction()
|
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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,37 +16,62 @@
|
||||||
|
|
||||||
package im.vector.app.features.roomdirectory.picker
|
package im.vector.app.features.roomdirectory.picker
|
||||||
|
|
||||||
|
import android.text.InputType
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
|
import android.widget.TextView
|
||||||
import com.airbnb.epoxy.TypedEpoxyController
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Incomplete
|
import com.airbnb.mvrx.Incomplete
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.dividerItem
|
||||||
import im.vector.app.core.epoxy.errorWithRetryItem
|
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.extensions.join
|
||||||
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
import im.vector.app.core.ui.list.genericButtonItem
|
||||||
|
import im.vector.app.core.ui.list.verticalMarginItem
|
||||||
|
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.inject.Inject
|
||||||
|
import javax.net.ssl.HttpsURLConnection
|
||||||
|
|
||||||
class RoomDirectoryPickerController @Inject constructor(private val stringProvider: StringProvider,
|
class RoomDirectoryPickerController @Inject constructor(
|
||||||
private val errorFormatter: ErrorFormatter,
|
private val stringProvider: StringProvider,
|
||||||
private val roomDirectoryListCreator: RoomDirectoryListCreator
|
private val colorProvider: ColorProvider,
|
||||||
|
private val dimensionConverter: DimensionConverter,
|
||||||
|
private val errorFormatter: ErrorFormatter
|
||||||
) : TypedEpoxyController<RoomDirectoryPickerViewState>() {
|
) : TypedEpoxyController<RoomDirectoryPickerViewState>() {
|
||||||
|
|
||||||
|
var currentRoomDirectoryData: RoomDirectoryData? = null
|
||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
|
|
||||||
var index = 0
|
private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color)
|
||||||
|
|
||||||
override fun buildModels(viewState: RoomDirectoryPickerViewState) {
|
override fun buildModels(data: RoomDirectoryPickerViewState) {
|
||||||
val host = this
|
val host = this
|
||||||
val asyncThirdPartyProtocol = viewState.asyncThirdPartyRequest
|
|
||||||
|
|
||||||
when (asyncThirdPartyProtocol) {
|
when (val asyncThirdPartyProtocol = data.asyncThirdPartyRequest) {
|
||||||
is Success -> {
|
is Success -> {
|
||||||
val directories = roomDirectoryListCreator.computeDirectories(asyncThirdPartyProtocol())
|
data.directories.join(
|
||||||
|
each = { _, roomDirectoryServer -> buildDirectory(roomDirectoryServer) },
|
||||||
directories.forEach {
|
between = { idx, _ -> buildDivider(idx) }
|
||||||
buildDirectory(it)
|
)
|
||||||
|
buildForm(data)
|
||||||
|
verticalMarginItem {
|
||||||
|
id("space_bottom")
|
||||||
|
heightInPx(host.dimensionConverter.dpToPx(16))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Incomplete -> {
|
is Incomplete -> {
|
||||||
|
@ -64,34 +89,142 @@ class RoomDirectoryPickerController @Inject constructor(private val stringProvid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildDirectory(roomDirectoryData: RoomDirectoryData) {
|
private fun buildForm(data: RoomDirectoryPickerViewState) {
|
||||||
|
buildDivider(1000)
|
||||||
val host = this
|
val host = this
|
||||||
roomDirectoryItem {
|
if (data.inEditMode) {
|
||||||
id(host.index++)
|
verticalMarginItem {
|
||||||
|
id("form_space")
|
||||||
directoryName(roomDirectoryData.displayName)
|
heightInPx(host.dimensionConverter.dpToPx(16))
|
||||||
|
}
|
||||||
val description = when {
|
settingsInformationItem {
|
||||||
roomDirectoryData.includeAllNetworks ->
|
id("form_notice")
|
||||||
host.stringProvider.getString(R.string.directory_server_all_rooms_on_server, roomDirectoryData.displayName)
|
message(host.stringProvider.getString(R.string.directory_add_a_new_server_prompt))
|
||||||
"Matrix" == roomDirectoryData.displayName ->
|
colorProvider(host.colorProvider)
|
||||||
host.stringProvider.getString(R.string.directory_server_native_rooms, roomDirectoryData.displayName)
|
}
|
||||||
else ->
|
verticalMarginItem {
|
||||||
null
|
id("form_space_2")
|
||||||
|
heightInPx(host.dimensionConverter.dpToPx(8))
|
||||||
|
}
|
||||||
|
formEditTextItem {
|
||||||
|
id("edit")
|
||||||
|
showBottomSeparator(false)
|
||||||
|
value(data.enteredServer)
|
||||||
|
imeOptions(EditorInfo.IME_ACTION_DONE)
|
||||||
|
editorActionListener(object : TextView.OnEditorActionListener {
|
||||||
|
override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
|
if (data.enteredServer.isNotEmpty()) {
|
||||||
|
host.callback?.onSubmitServer()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
directoryDescription(description)
|
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 {
|
||||||
|
id("divider_$idx")
|
||||||
|
color(host.dividerColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDirectory(roomDirectoryServer: RoomDirectoryServer) {
|
||||||
|
val host = this
|
||||||
|
roomDirectoryServerItem {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roomDirectoryServer.protocols.forEach { roomDirectoryData ->
|
||||||
|
roomDirectoryItem {
|
||||||
|
id("server_${roomDirectoryServer}_proto_$roomDirectoryData")
|
||||||
|
directoryName(
|
||||||
|
if (roomDirectoryData.includeAllNetworks) {
|
||||||
|
host.stringProvider.getString(R.string.directory_server_all_rooms_on_server, roomDirectoryServer.serverName)
|
||||||
|
} else {
|
||||||
|
roomDirectoryData.displayName
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (roomDirectoryData.displayName == RoomDirectoryData.MATRIX_PROTOCOL_NAME && !roomDirectoryData.includeAllNetworks) {
|
||||||
|
directoryDescription(
|
||||||
|
host.stringProvider.getString(R.string.directory_server_native_rooms, roomDirectoryServer.serverName)
|
||||||
|
)
|
||||||
|
}
|
||||||
directoryAvatarUrl(roomDirectoryData.avatarUrl)
|
directoryAvatarUrl(roomDirectoryData.avatarUrl)
|
||||||
includeAllNetworks(roomDirectoryData.includeAllNetworks)
|
includeAllNetworks(roomDirectoryData.includeAllNetworks)
|
||||||
|
checked(roomDirectoryData == host.currentRoomDirectoryData)
|
||||||
globalListener {
|
globalListener {
|
||||||
host.callback?.onRoomDirectoryClicked(roomDirectoryData)
|
host.callback?.onRoomDirectoryClicked(roomDirectoryData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun onRoomDirectoryClicked(roomDirectoryData: RoomDirectoryData)
|
fun onRoomDirectoryClicked(roomDirectoryData: RoomDirectoryData)
|
||||||
fun retry()
|
fun retry()
|
||||||
|
fun onStartEnterServer()
|
||||||
|
fun onEnterServerChange(server: String)
|
||||||
|
fun onSubmitServer()
|
||||||
|
fun onCancelEnterServer()
|
||||||
|
fun onRemoveServer(roomDirectoryServer: RoomDirectoryServer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package im.vector.app.features.roomdirectory.picker
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
@ -28,21 +27,22 @@ import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
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.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding
|
import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectoryAction
|
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.RoomDirectorySharedAction
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectoryViewModel
|
import im.vector.app.features.roomdirectory.RoomDirectoryViewModel
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
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,
|
class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory,
|
||||||
private val roomDirectoryPickerController: RoomDirectoryPickerController
|
private val roomDirectoryPickerController: RoomDirectoryPickerController
|
||||||
) : VectorBaseFragment<FragmentRoomDirectoryPickerBinding>(),
|
) : VectorBaseFragment<FragmentRoomDirectoryPickerBinding>(),
|
||||||
|
OnBackPressed,
|
||||||
RoomDirectoryPickerController.Callback {
|
RoomDirectoryPickerController.Callback {
|
||||||
|
|
||||||
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||||
|
@ -65,6 +65,11 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
|
||||||
|
|
||||||
sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
|
|
||||||
|
// Give the current data to our controller. There maybe a better way to do that...
|
||||||
|
withState(viewModel) {
|
||||||
|
roomDirectoryPickerController.currentRoomDirectoryData = it.roomDirectoryData
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -73,18 +78,6 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
|
||||||
super.onDestroyView()
|
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() {
|
private fun setupRecyclerView() {
|
||||||
views.roomDirectoryPickerList.configureWith(roomDirectoryPickerController)
|
views.roomDirectoryPickerList.configureWith(roomDirectoryPickerController)
|
||||||
roomDirectoryPickerController.callback = this
|
roomDirectoryPickerController.callback = this
|
||||||
|
@ -97,6 +90,26 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
|
||||||
sharedActionViewModel.post(RoomDirectorySharedAction.Back)
|
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() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.select_room_directory)
|
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.select_room_directory)
|
||||||
|
@ -111,4 +124,16 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
|
||||||
// Populate list with Epoxy
|
// Populate list with Epoxy
|
||||||
roomDirectoryPickerController.setData(state)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,18 +22,28 @@ import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.session.Session
|
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,
|
class RoomDirectoryPickerViewModel @AssistedInject constructor(
|
||||||
private val session: Session)
|
@Assisted initialState: RoomDirectoryPickerViewState,
|
||||||
: VectorViewModel<RoomDirectoryPickerViewState, RoomDirectoryPickerAction, EmptyViewEvents>(initialState) {
|
private val session: Session,
|
||||||
|
private val uiStateRepository: UiStateRepository,
|
||||||
|
private val stringProvider: StringProvider,
|
||||||
|
private val roomDirectoryListCreator: RoomDirectoryListCreator
|
||||||
|
) : VectorViewModel<RoomDirectoryPickerViewState, RoomDirectoryPickerAction, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
@ -50,7 +60,22 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initial
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
observeAndCompute()
|
||||||
load()
|
load()
|
||||||
|
loadCustomRoomDirectoryHomeservers()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeAndCompute() {
|
||||||
|
selectSubscribe(
|
||||||
|
RoomDirectoryPickerViewState::asyncThirdPartyRequest,
|
||||||
|
RoomDirectoryPickerViewState::customHomeservers
|
||||||
|
) { async, custom ->
|
||||||
|
async()?.let {
|
||||||
|
setState {
|
||||||
|
copy(directories = roomDirectoryListCreator.computeDirectories(it, custom))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun load() {
|
private fun load() {
|
||||||
|
@ -71,9 +96,101 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadCustomRoomDirectoryHomeservers() {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
customHomeservers = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun handle(action: RoomDirectoryPickerAction) {
|
override fun handle(action: RoomDirectoryPickerAction) {
|
||||||
when (action) {
|
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 ->
|
||||||
|
// First avoid duplicate
|
||||||
|
val enteredServer = state.enteredServer
|
||||||
|
|
||||||
|
val existingServerList = state.directories.map { it.serverName }
|
||||||
|
|
||||||
|
if (enteredServer in existingServerList) {
|
||||||
|
setState {
|
||||||
|
copy(addServerAsync = Fail(Throwable(stringProvider.getString(R.string.directory_add_a_new_server_error_already_added))))
|
||||||
|
}
|
||||||
|
return@withState
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
setState {
|
||||||
|
copy(addServerAsync = Loading())
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
session.getPublicRooms(
|
||||||
|
server = enteredServer,
|
||||||
|
publicRoomsParams = PublicRoomsParams(limit = 1)
|
||||||
|
)
|
||||||
|
// Success, let add the server to our local repository, and update the state
|
||||||
|
val newSet = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId) + 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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,15 @@ package im.vector.app.features.roomdirectory.picker
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.app.features.roomdirectory.RoomDirectoryServer
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||||
|
|
||||||
data class RoomDirectoryPickerViewState(
|
data class RoomDirectoryPickerViewState(
|
||||||
val asyncThirdPartyRequest: Async<Map<String, ThirdPartyProtocol>> = Uninitialized
|
val asyncThirdPartyRequest: Async<Map<String, ThirdPartyProtocol>> = Uninitialized,
|
||||||
|
val customHomeservers: Set<String> = emptySet(),
|
||||||
|
val inEditMode: Boolean = false,
|
||||||
|
val enteredServer: String = "",
|
||||||
|
val addServerAsync: Async<Unit> = Uninitialized,
|
||||||
|
// computed
|
||||||
|
val directories: List<RoomDirectoryServer> = emptyList()
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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.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)
|
||||||
|
abstract class RoomDirectoryServerItem : VectorEpoxyModel<RoomDirectoryServerItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var serverName: String? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var serverDescription: String? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var canRemove: Boolean = false
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var removeListener: ClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.nameView.text = serverName
|
||||||
|
holder.descriptionView.setTextOrHide(serverDescription)
|
||||||
|
holder.deleteView.isVisible = canRemove
|
||||||
|
holder.deleteView.onClick(removeListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val nameView by bind<TextView>(R.id.itemRoomDirectoryServerName)
|
||||||
|
val descriptionView by bind<TextView>(R.id.itemRoomDirectoryServerDescription)
|
||||||
|
val deleteView by bind<View>(R.id.itemRoomDirectoryServerRemove)
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,9 +25,9 @@ import im.vector.app.core.extensions.addFragment
|
||||||
import im.vector.app.core.platform.ToolbarConfigurable
|
import im.vector.app.core.platform.ToolbarConfigurable
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivitySimpleBinding
|
import im.vector.app.databinding.ActivitySimpleBinding
|
||||||
|
import im.vector.app.features.roomdirectory.RoomDirectoryData
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ class RoomSettingsController @Inject constructor(
|
||||||
id("topic")
|
id("topic")
|
||||||
enabled(data.actionPermissions.canChangeTopic)
|
enabled(data.actionPermissions.canChangeTopic)
|
||||||
value(data.newTopic ?: roomSummary.topic)
|
value(data.newTopic ?: roomSummary.topic)
|
||||||
|
singleLine(false)
|
||||||
hint(host.stringProvider.getString(R.string.room_settings_topic_hint))
|
hint(host.stringProvider.getString(R.string.room_settings_topic_hint))
|
||||||
|
|
||||||
onTextChange { text ->
|
onTextChange { text ->
|
||||||
|
|
|
@ -69,7 +69,6 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
|
||||||
id("roomName1")
|
id("roomName1")
|
||||||
enabled(true)
|
enabled(true)
|
||||||
value(firstRoomName)
|
value(firstRoomName)
|
||||||
singleLine(true)
|
|
||||||
hint(host.stringProvider.getString(R.string.create_room_name_section))
|
hint(host.stringProvider.getString(R.string.create_room_name_section))
|
||||||
endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
|
endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
|
||||||
showBottomSeparator(false)
|
showBottomSeparator(false)
|
||||||
|
@ -83,7 +82,6 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
|
||||||
id("roomName2")
|
id("roomName2")
|
||||||
enabled(true)
|
enabled(true)
|
||||||
value(secondRoomName)
|
value(secondRoomName)
|
||||||
singleLine(true)
|
|
||||||
hint(host.stringProvider.getString(R.string.create_room_name_section))
|
hint(host.stringProvider.getString(R.string.create_room_name_section))
|
||||||
endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
|
endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
|
||||||
showBottomSeparator(false)
|
showBottomSeparator(false)
|
||||||
|
@ -97,7 +95,6 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
|
||||||
id("roomName3")
|
id("roomName3")
|
||||||
enabled(true)
|
enabled(true)
|
||||||
value(thirdRoomName)
|
value(thirdRoomName)
|
||||||
singleLine(true)
|
|
||||||
hint(host.stringProvider.getString(R.string.create_room_name_section))
|
hint(host.stringProvider.getString(R.string.create_room_name_section))
|
||||||
endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
|
endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
|
||||||
showBottomSeparator(false)
|
showBottomSeparator(false)
|
||||||
|
|
|
@ -64,7 +64,6 @@ class SpaceDetailEpoxyController @Inject constructor(
|
||||||
enabled(true)
|
enabled(true)
|
||||||
value(data?.name)
|
value(data?.name)
|
||||||
hint(host.stringProvider.getString(R.string.create_room_name_hint))
|
hint(host.stringProvider.getString(R.string.create_room_name_hint))
|
||||||
singleLine(true)
|
|
||||||
showBottomSeparator(false)
|
showBottomSeparator(false)
|
||||||
errorMessage(data?.nameInlineError)
|
errorMessage(data?.nameInlineError)
|
||||||
// onBind { _, view, _ ->
|
// onBind { _, view, _ ->
|
||||||
|
|
|
@ -89,6 +89,18 @@ class SharedPreferencesUiStateRepository @Inject constructor(
|
||||||
return sharedPreferences.getBoolean("$KEY_SELECTED_METHOD@$sessionId", true)
|
return sharedPreferences.getBoolean("$KEY_SELECTED_METHOD@$sessionId", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set<String>) {
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putStringSet("$KEY_CUSTOM_DIRECTORY_HOMESERVER@$sessionId", servers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCustomRoomDirectoryHomeservers(sessionId: String): Set<String> {
|
||||||
|
return sharedPreferences.getStringSet("$KEY_CUSTOM_DIRECTORY_HOMESERVER@$sessionId", null)
|
||||||
|
.orEmpty()
|
||||||
|
.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY_DISPLAY_MODE = "UI_STATE_DISPLAY_MODE"
|
private const val KEY_DISPLAY_MODE = "UI_STATE_DISPLAY_MODE"
|
||||||
private const val VALUE_DISPLAY_MODE_CATCHUP = 0
|
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_SPACE = "UI_STATE_SELECTED_SPACE"
|
||||||
private const val KEY_SELECTED_GROUP = "UI_STATE_SELECTED_GROUP"
|
private const val KEY_SELECTED_GROUP = "UI_STATE_SELECTED_GROUP"
|
||||||
private const val KEY_SELECTED_METHOD = "UI_STATE_SELECTED_METHOD"
|
private const val KEY_SELECTED_METHOD = "UI_STATE_SELECTED_METHOD"
|
||||||
|
|
||||||
|
private const val KEY_CUSTOM_DIRECTORY_HOMESERVER = "KEY_CUSTOM_DIRECTORY_HOMESERVER"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ interface UiStateRepository {
|
||||||
|
|
||||||
fun storeDisplayMode(displayMode: RoomListDisplayMode)
|
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 storeSelectedSpace(spaceId: String?, sessionId: String)
|
||||||
fun storeSelectedGroup(groupId: String?, sessionId: String)
|
fun storeSelectedGroup(groupId: String?, sessionId: String)
|
||||||
|
|
||||||
|
@ -40,4 +41,7 @@ interface UiStateRepository {
|
||||||
fun getSelectedSpace(sessionId: String): String?
|
fun getSelectedSpace(sessionId: String): String?
|
||||||
fun getSelectedGroup(sessionId: String): String?
|
fun getSelectedGroup(sessionId: String): String?
|
||||||
fun isGroupingMethodSpace(sessionId: String): Boolean
|
fun isGroupingMethodSpace(sessionId: String): Boolean
|
||||||
|
|
||||||
|
fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set<String>)
|
||||||
|
fun getCustomRoomDirectoryHomeservers(sessionId: String): Set<String>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -15,23 +14,23 @@
|
||||||
android:id="@+id/itemRoomDirectoryAvatar"
|
android:id="@+id/itemRoomDirectoryAvatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:background="@drawable/circle"
|
android:background="@drawable/circle"
|
||||||
android:contentDescription="@string/avatar"
|
android:contentDescription="@string/avatar"
|
||||||
android:padding="8dp"
|
android:padding="8dp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryBottomSeparator"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@drawable/network_matrix" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/itemRoomDirectoryName"
|
android:id="@+id/itemRoomDirectoryName"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
|
@ -39,36 +38,46 @@
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryDescription"
|
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryDescription"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@+id/itemRoomDirectoryChecked"
|
||||||
app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
|
app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:layout_goneMarginEnd="@dimen/layout_horizontal_margin"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/itemRoomDirectoryDescription"
|
android:id="@+id/itemRoomDirectoryDescription"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:textColor="?riotx_text_primary"
|
android:textColor="?riotx_text_primary"
|
||||||
android:textSize="15sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryBottomSeparator"
|
android:visibility="gone"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/itemRoomDirectoryChecked"
|
||||||
app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
|
app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
|
||||||
app:layout_constraintTop_toBottomOf="@id/itemRoomDirectoryName"
|
app:layout_constraintTop_toBottomOf="@id/itemRoomDirectoryName"
|
||||||
tools:text="@string/directory_server_all_rooms_on_server" />
|
app:layout_goneMarginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
tools:text="@string/directory_server_native_rooms"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<View
|
<ImageView
|
||||||
android:id="@+id/itemRoomDirectoryBottomSeparator"
|
android:id="@+id/itemRoomDirectoryChecked"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="1dp"
|
android:layout_height="wrap_content"
|
||||||
android:background="?riotx_header_panel_border_mobile"
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:contentDescription="@string/avatar"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_check_on"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout 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="?vctr_list_header_background_color"
|
||||||
|
android:minHeight="?listPreferredItemHeight">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemRoomDirectoryServerName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lines="1"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryServerDescription"
|
||||||
|
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" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemRoomDirectoryServerDescription"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lines="1"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="?riotx_text_secondary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/itemRoomDirectoryServerRemove"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/itemRoomDirectoryServerName"
|
||||||
|
app:layout_goneMarginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
tools:text="@string/directory_your_server"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemRoomDirectoryServerRemove"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:contentDescription="@string/avatar"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_delete"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tint="@color/vector_error_color"
|
||||||
|
tools:ignore="MissingPrefix"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Space xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/item_vertical_margin_space"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/layout_vertical_margin" />
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_add_custom_hs"
|
|
||||||
android:icon="@drawable/ic_add_black"
|
|
||||||
android:title="@string/action_open"
|
|
||||||
android:visible="@bool/false_not_implemented"
|
|
||||||
app:iconTint="?colorAccent"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
|
|
||||||
</menu>
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
<string-array name="room_directory_servers" translatable="false">
|
<string-array name="room_directory_servers" translatable="false">
|
||||||
<item>matrix.org</item>
|
<item>matrix.org</item>
|
||||||
|
<item>gitter.im</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1584,9 +1584,14 @@
|
||||||
<string name="select_room_directory">Select a room directory</string>
|
<string name="select_room_directory">Select a room directory</string>
|
||||||
<string name="directory_server_fail_to_retrieve_server">The server may be unavailable or overloaded</string>
|
<string name="directory_server_fail_to_retrieve_server">The server may be unavailable or overloaded</string>
|
||||||
<string name="directory_server_type_homeserver">Type a homeserver to list public rooms from</string>
|
<string name="directory_server_type_homeserver">Type a homeserver to list public rooms from</string>
|
||||||
<string name="directory_server_placeholder">Homeserver URL</string>
|
<string name="directory_server_placeholder">Server name</string>
|
||||||
<string name="directory_server_all_rooms_on_server">All rooms on %s server</string>
|
<string name="directory_server_all_rooms_on_server">All rooms on %s server</string>
|
||||||
<string name="directory_server_native_rooms">All native %s rooms</string>
|
<string name="directory_server_native_rooms">All native %s rooms</string>
|
||||||
|
<string name="directory_your_server">Your server</string>
|
||||||
|
<string name="directory_add_a_new_server">Add a new server</string>
|
||||||
|
<string name="directory_add_a_new_server_prompt">Enter the name of a new server you want to explore.</string>
|
||||||
|
<string name="directory_add_a_new_server_error">"Can't find this server or its room list"</string>
|
||||||
|
<string name="directory_add_a_new_server_error_already_added">This server is already present in the list</string>
|
||||||
|
|
||||||
<!-- Lock screen-->
|
<!-- Lock screen-->
|
||||||
<string name="lock_screen_hint">Type here…</string>
|
<string name="lock_screen_hint">Type here…</string>
|
||||||
|
|
Loading…
Reference in New Issue