forked from GitHub-Mirror/riotX-android
Join room from room preview
This commit is contained in:
@ -28,9 +28,10 @@ class ErrorFormatter(val stringProvider: StringProvider) {
|
||||
return failure.localizedMessage
|
||||
}
|
||||
|
||||
fun toHumanReadable(throwable: Throwable): String {
|
||||
fun toHumanReadable(throwable: Throwable?): String {
|
||||
|
||||
return when (throwable) {
|
||||
null -> ""
|
||||
is Failure.NetworkConnection -> stringProvider.getString(R.string.error_no_network)
|
||||
else -> throwable.localizedMessage
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
@ -43,14 +44,13 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
||||
fun onRetryClicked()
|
||||
}
|
||||
|
||||
// Big or Flat button
|
||||
var button: Button
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.view_button_state, this)
|
||||
layoutParams = LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
buttonStateButton.setOnClickListener {
|
||||
callback?.onButtonClicked()
|
||||
}
|
||||
|
||||
buttonStateRetry.setOnClickListener {
|
||||
callback?.onRetryClicked()
|
||||
}
|
||||
@ -62,20 +62,32 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
||||
0, 0)
|
||||
.apply {
|
||||
try {
|
||||
buttonStateButton.text = getString(R.styleable.ButtonStateView_bsv_button_text)
|
||||
if (getBoolean(R.styleable.ButtonStateView_bsv_use_flat_button, true)) {
|
||||
button = buttonStateButtonFlat
|
||||
buttonStateButtonBig.isVisible = false
|
||||
} else {
|
||||
button = buttonStateButtonBig
|
||||
buttonStateButtonFlat.isVisible = false
|
||||
}
|
||||
|
||||
button.text = getString(R.styleable.ButtonStateView_bsv_button_text)
|
||||
buttonStateLoaded.setImageDrawable(getDrawable(R.styleable.ButtonStateView_bsv_loaded_image_src))
|
||||
} finally {
|
||||
recycle()
|
||||
}
|
||||
}
|
||||
|
||||
button.setOnClickListener {
|
||||
callback?.onButtonClicked()
|
||||
}
|
||||
}
|
||||
|
||||
fun render(newState: State) {
|
||||
if (newState == State.Button) {
|
||||
buttonStateButton.isVisible = true
|
||||
button.isVisible = true
|
||||
} else {
|
||||
// We use isInvisible because we want to keep button space in the layout
|
||||
buttonStateButton.isInvisible = true
|
||||
button.isInvisible = true
|
||||
}
|
||||
|
||||
buttonStateLoading.isVisible = newState == State.Loading
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.roomdirectory
|
||||
|
||||
/**
|
||||
* Join state of a room
|
||||
*/
|
||||
enum class JoinState {
|
||||
NOT_JOINED,
|
||||
JOINING,
|
||||
JOINING_ERROR,
|
||||
// Room is joined and this is confirmed by the sync
|
||||
JOINED
|
||||
}
|
@ -30,13 +30,6 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
@EpoxyModelClass(layout = R.layout.item_public_room)
|
||||
abstract class PublicRoomItem : VectorEpoxyModel<PublicRoomItem.Holder>() {
|
||||
|
||||
enum class JoinState {
|
||||
NOT_JOINED,
|
||||
JOINING,
|
||||
JOINING_ERROR,
|
||||
JOINED
|
||||
}
|
||||
|
||||
@EpoxyAttribute
|
||||
var avatarUrl: String? = null
|
||||
|
||||
|
@ -85,10 +85,10 @@ class PublicRoomsController(private val stringProvider: StringProvider,
|
||||
nbOfMembers(publicRoom.numJoinedMembers)
|
||||
|
||||
val joinState = when {
|
||||
viewState.joinedRoomsIds.contains(publicRoom.roomId) -> PublicRoomItem.JoinState.JOINED
|
||||
viewState.joiningRoomsIds.contains(publicRoom.roomId) -> PublicRoomItem.JoinState.JOINING
|
||||
viewState.joiningErrorRoomsIds.contains(publicRoom.roomId) -> PublicRoomItem.JoinState.JOINING_ERROR
|
||||
else -> PublicRoomItem.JoinState.NOT_JOINED
|
||||
viewState.joinedRoomsIds.contains(publicRoom.roomId) -> JoinState.JOINED
|
||||
viewState.joiningRoomsIds.contains(publicRoom.roomId) -> JoinState.JOINING
|
||||
viewState.joiningErrorRoomsIds.contains(publicRoom.roomId) -> JoinState.JOINING_ERROR
|
||||
else -> JoinState.NOT_JOINED
|
||||
}
|
||||
|
||||
joinState(joinState)
|
||||
@ -103,7 +103,7 @@ class PublicRoomsController(private val stringProvider: StringProvider,
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: PublicRoomItem.JoinState)
|
||||
fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: JoinState)
|
||||
fun onPublicRoomJoin(publicRoom: PublicRoom)
|
||||
fun loadMore()
|
||||
}
|
||||
|
@ -117,21 +117,21 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
|
||||
publicRoomsList.setController(publicRoomsController)
|
||||
}
|
||||
|
||||
override fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: PublicRoomItem.JoinState) {
|
||||
override fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: JoinState) {
|
||||
Timber.v("PublicRoomClicked: $publicRoom")
|
||||
|
||||
when (joinState) {
|
||||
PublicRoomItem.JoinState.JOINED -> {
|
||||
JoinState.JOINED -> {
|
||||
val args = RoomDetailArgs(publicRoom.roomId)
|
||||
val roomDetailIntent = RoomDetailActivity.newIntent(requireActivity(), args)
|
||||
requireActivity().startActivity(roomDetailIntent)
|
||||
}
|
||||
PublicRoomItem.JoinState.NOT_JOINED,
|
||||
PublicRoomItem.JoinState.JOINING_ERROR -> {
|
||||
JoinState.NOT_JOINED,
|
||||
JoinState.JOINING_ERROR -> {
|
||||
// ROOM PREVIEW
|
||||
requireActivity().startActivity(RoomPreviewActivity.getIntent(requireActivity(), publicRoom))
|
||||
}
|
||||
else -> {
|
||||
else -> {
|
||||
Snackbar.make(publicRoomsCoordinator, getString(R.string.please_wait), Snackbar.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
@ -19,13 +19,20 @@ package im.vector.riotredesign.features.roomdirectory.roompreview
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionManager
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||
import im.vector.riotredesign.core.extensions.setTextOrHide
|
||||
import im.vector.riotredesign.core.platform.ButtonStateView
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
import im.vector.riotredesign.features.roomdirectory.JoinState
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||
import kotlinx.android.synthetic.main.fragment_room_preview_no_preview.*
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.scope.ext.android.bindScope
|
||||
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||
|
||||
@ -37,12 +44,17 @@ class RoomPreviewNoPreviewFragment : VectorBaseFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private val errorFormatter = get<ErrorFormatter>()
|
||||
private val roomPreviewViewModel: RoomPreviewViewModel by fragmentViewModel()
|
||||
|
||||
private val roomPreviewData: RoomPreviewData by args()
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
setupToolbar(roomPreviewNoPreviewToolbar)
|
||||
|
||||
roomPreviewViewModel.init(roomPreviewData.roomId)
|
||||
}
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_room_preview_no_preview
|
||||
@ -54,8 +66,35 @@ class RoomPreviewNoPreviewFragment : VectorBaseFragment() {
|
||||
roomPreviewNoPreviewName.text = roomPreviewData.roomName
|
||||
roomPreviewNoPreviewTopic.setTextOrHide(roomPreviewData.topic)
|
||||
|
||||
roomPreviewNoPreviewJoin.setOnClickListener {
|
||||
vectorBaseActivity.notImplemented("Join from preview")
|
||||
roomPreviewNoPreviewJoin.callback = object : ButtonStateView.Callback {
|
||||
override fun onButtonClicked() {
|
||||
roomPreviewViewModel.joinRoom()
|
||||
}
|
||||
|
||||
override fun onRetryClicked() {
|
||||
// Same action
|
||||
onButtonClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(roomPreviewViewModel) { state ->
|
||||
TransitionManager.beginDelayedTransition(roomPreviewNoPreviewRoot)
|
||||
|
||||
roomPreviewNoPreviewJoin.render(
|
||||
when (state.roomJoinState) {
|
||||
JoinState.NOT_JOINED -> ButtonStateView.State.Button
|
||||
JoinState.JOINING -> ButtonStateView.State.Loading
|
||||
JoinState.JOINED -> ButtonStateView.State.Loaded
|
||||
JoinState.JOINING_ERROR -> ButtonStateView.State.Error
|
||||
}
|
||||
)
|
||||
|
||||
roomPreviewNoPreviewError.setTextOrHide(errorFormatter.toHumanReadable(state.lastError))
|
||||
|
||||
if (state.roomJoinState == JoinState.JOINED) {
|
||||
// TODO Quit this screen and open the room
|
||||
vectorBaseActivity.notImplemented("Open newly join room")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.roomdirectory.roompreview
|
||||
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.features.roomdirectory.JoinState
|
||||
import org.koin.android.ext.android.get
|
||||
import timber.log.Timber
|
||||
|
||||
class RoomPreviewViewModel(initialState: RoomPreviewViewState,
|
||||
private val session: Session) : VectorViewModel<RoomPreviewViewState>(initialState) {
|
||||
|
||||
companion object : MvRxViewModelFactory<RoomPreviewViewModel, RoomPreviewViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: RoomPreviewViewState): RoomPreviewViewModel? {
|
||||
val currentSession = viewModelContext.activity.get<Session>()
|
||||
|
||||
return RoomPreviewViewModel(state, currentSession)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// Observe joined room (from the sync)
|
||||
observeJoinedRooms()
|
||||
}
|
||||
|
||||
private fun observeJoinedRooms() {
|
||||
session
|
||||
.rx()
|
||||
.liveRoomSummaries()
|
||||
.execute { async ->
|
||||
val isRoomJoined = async.invoke()
|
||||
// Keep only joined room
|
||||
?.filter { it.membership == Membership.JOIN }
|
||||
?.map { it.roomId }
|
||||
?.toList()
|
||||
?.contains(roomId) == true
|
||||
|
||||
if (isRoomJoined) {
|
||||
copy(
|
||||
roomJoinState = JoinState.JOINED
|
||||
)
|
||||
} else {
|
||||
// TODO No change...
|
||||
copy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO I should not have to do that
|
||||
fun init(roomId: String) = withState {
|
||||
setState {
|
||||
copy(
|
||||
roomId = roomId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun joinRoom() = withState { state ->
|
||||
if (state.roomJoinState == JoinState.JOINING) {
|
||||
// Request already sent, should not happen
|
||||
Timber.w("Try to join an already joining room. Should not happen")
|
||||
return@withState
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(
|
||||
roomJoinState = JoinState.JOINING,
|
||||
lastError = null
|
||||
)
|
||||
}
|
||||
|
||||
session.joinRoom(state.roomId, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
// We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
|
||||
// Instead, we wait for the room to be joined
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
setState {
|
||||
copy(
|
||||
roomJoinState = JoinState.JOINING_ERROR,
|
||||
lastError = failure
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.roomdirectory.roompreview
|
||||
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import im.vector.riotredesign.features.roomdirectory.JoinState
|
||||
|
||||
data class RoomPreviewViewState(
|
||||
// The room id
|
||||
val roomId: String = "",
|
||||
// Current state of the room in preview
|
||||
val roomJoinState: JoinState = JoinState.NOT_JOINED,
|
||||
// Last error of join room request
|
||||
val lastError: Throwable? = null
|
||||
) : MvRxState
|
Reference in New Issue
Block a user