mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Create room screen - Better navigation pattern
This commit is contained in:
parent
4c5bffe0f5
commit
aa95ce3d02
8 changed files with 99 additions and 17 deletions
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.core.mvrx
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||||
|
import im.vector.riotredesign.core.utils.LiveEvent
|
||||||
|
|
||||||
|
// MvRx require a state with at least one attribute
|
||||||
|
data class NavigationState(val dummy: Boolean = false) : MvRxState
|
||||||
|
|
||||||
|
abstract class NavigationViewModel<NavigationClass>(initialState: NavigationState) : VectorViewModel<NavigationState>(initialState) {
|
||||||
|
|
||||||
|
private val _navigateTo = MutableLiveData<LiveEvent<NavigationClass>>()
|
||||||
|
val navigateTo: LiveData<LiveEvent<NavigationClass>>
|
||||||
|
get() = _navigateTo
|
||||||
|
|
||||||
|
|
||||||
|
fun goTo(navigation: NavigationClass) {
|
||||||
|
_navigateTo.postValue(LiveEvent(navigation))
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,11 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var onTextChange: ((String) -> Unit)? = null
|
var onTextChange: ((String) -> Unit)? = null
|
||||||
|
|
||||||
|
private val onTextChangeListener = object : SimpleTextWatcher() {
|
||||||
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
|
onTextChange?.invoke(s.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
holder.textInputLayout.isEnabled = enabled
|
holder.textInputLayout.isEnabled = enabled
|
||||||
|
@ -51,11 +56,7 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||||
}
|
}
|
||||||
holder.textInputEditText.isEnabled = enabled
|
holder.textInputEditText.isEnabled = enabled
|
||||||
|
|
||||||
holder.textInputEditText.addTextChangedListener(object : SimpleTextWatcher() {
|
holder.textInputEditText.addTextChangedListener(onTextChangeListener)
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
|
||||||
onTextChange?.invoke(s.toString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shouldSaveViewState(): Boolean {
|
override fun shouldSaveViewState(): Boolean {
|
||||||
|
@ -64,9 +65,7 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||||
|
|
||||||
override fun unbind(holder: Holder) {
|
override fun unbind(holder: Holder) {
|
||||||
super.unbind(holder)
|
super.unbind(holder)
|
||||||
|
holder.textInputEditText.removeTextChangedListener(onTextChangeListener)
|
||||||
// TODO Remove onTextChanged?
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
|
|
@ -49,6 +49,7 @@ import java.util.concurrent.TimeUnit
|
||||||
class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback {
|
class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback {
|
||||||
|
|
||||||
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||||
|
private val navigationViewModel: RoomDirectoryNavigationViewModel by activityViewModel()
|
||||||
private val publicRoomsController: PublicRoomsController by inject()
|
private val publicRoomsController: PublicRoomsController by inject()
|
||||||
private val errorFormatter: ErrorFormatter by inject()
|
private val errorFormatter: ErrorFormatter by inject()
|
||||||
|
|
||||||
|
@ -76,8 +77,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
|
||||||
.disposeOnDestroy()
|
.disposeOnDestroy()
|
||||||
|
|
||||||
publicRoomsCreateNewRoom.setOnClickListener {
|
publicRoomsCreateNewRoom.setOnClickListener {
|
||||||
// TODO Not the best navigation pattern
|
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.CreateRoom)
|
||||||
(vectorBaseActivity as? RoomDirectoryActivity)?.gotoCreateRoom()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.joinRoomErrorLiveData.observe(this, Observer {
|
viewModel.joinRoomErrorLiveData.observe(this, Observer {
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package im.vector.riotredesign.features.roomdirectory
|
package im.vector.riotredesign.features.roomdirectory
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import com.airbnb.mvrx.viewModel
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.extensions.addFragment
|
import im.vector.riotredesign.core.extensions.addFragment
|
||||||
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
||||||
|
@ -27,6 +29,14 @@ import org.koin.android.scope.ext.android.getOrCreateScope
|
||||||
|
|
||||||
class RoomDirectoryActivity : VectorBaseActivity() {
|
class RoomDirectoryActivity : VectorBaseActivity() {
|
||||||
|
|
||||||
|
// Supported navigation actions for this Activity
|
||||||
|
sealed class Navigation {
|
||||||
|
object Back : Navigation()
|
||||||
|
object CreateRoom : Navigation()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val navigationViewModel: RoomDirectoryNavigationViewModel by viewModel()
|
||||||
|
|
||||||
override fun getLayoutRes() = R.layout.activity_simple
|
override fun getLayoutRes() = R.layout.activity_simple
|
||||||
|
|
||||||
|
@ -34,6 +44,13 @@ class RoomDirectoryActivity : VectorBaseActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||||
|
|
||||||
|
navigationViewModel.navigateTo.observe(this, Observer { liveEvent ->
|
||||||
|
when (liveEvent.getContentIfNotHandled() ?: return@Observer) {
|
||||||
|
is Navigation.Back -> onBackPressed()
|
||||||
|
is Navigation.CreateRoom -> gotoCreateRoom()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initUiAndData() {
|
override fun initUiAndData() {
|
||||||
|
@ -42,8 +59,7 @@ class RoomDirectoryActivity : VectorBaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun gotoCreateRoom() {
|
||||||
fun gotoCreateRoom() {
|
|
||||||
addFragmentToBackstack(CreateRoomFragment(), R.id.simpleFragmentContainer)
|
addFragmentToBackstack(CreateRoomFragment(), R.id.simpleFragmentContainer)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import im.vector.riotredesign.core.mvrx.NavigationState
|
||||||
|
import im.vector.riotredesign.core.mvrx.NavigationViewModel
|
||||||
|
|
||||||
|
class RoomDirectoryNavigationViewModel(initialState: NavigationState)
|
||||||
|
: NavigationViewModel<RoomDirectoryActivity.Navigation>(initialState)
|
|
@ -20,11 +20,14 @@ import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryActivity
|
||||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryNavigationViewModel
|
||||||
import kotlinx.android.synthetic.main.fragment_create_room.*
|
import kotlinx.android.synthetic.main.fragment_create_room.*
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.android.scope.ext.android.bindScope
|
import org.koin.android.scope.ext.android.bindScope
|
||||||
|
@ -33,6 +36,7 @@ import timber.log.Timber
|
||||||
|
|
||||||
class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
|
class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
|
||||||
|
|
||||||
|
private val navigationViewModel: RoomDirectoryNavigationViewModel by activityViewModel()
|
||||||
private val viewModel: CreateRoomViewModel by fragmentViewModel()
|
private val viewModel: CreateRoomViewModel by fragmentViewModel()
|
||||||
private val createRoomController: CreateRoomController by inject()
|
private val createRoomController: CreateRoomController by inject()
|
||||||
|
|
||||||
|
@ -49,8 +53,7 @@ class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
|
|
||||||
createRoomClose.setOnClickListener {
|
createRoomClose.setOnClickListener {
|
||||||
// TODO Not the best way to manage Fragment Backstack...
|
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
|
||||||
vectorBaseActivity.onBackPressed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class CreateRoomViewModel(initialState: CreateRoomViewState,
|
||||||
|
|
||||||
fun setName(newName: String) = setState { copy(roomName = newName) }
|
fun setName(newName: String) = setState { copy(roomName = newName) }
|
||||||
|
|
||||||
fun setIsPublic(value: Boolean) = setState { copy(isPublic = value) }
|
fun setIsPublic(isPublic: Boolean) = setState { copy(isPublic = isPublic) }
|
||||||
|
|
||||||
fun setIsInRoomDirectory(isInRoomDirectory: Boolean) = setState { copy(isInRoomDirectory = isInRoomDirectory) }
|
fun setIsInRoomDirectory(isInRoomDirectory: Boolean) = setState { copy(isInRoomDirectory = isInRoomDirectory) }
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ class CreateRoomViewModel(initialState: CreateRoomViewState,
|
||||||
// Directory visibility
|
// Directory visibility
|
||||||
visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE
|
visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE
|
||||||
|
|
||||||
|
// Public room
|
||||||
preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
|
preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,9 @@ import com.airbnb.mvrx.withState
|
||||||
import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData
|
import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryActivity
|
||||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryNavigationViewModel
|
||||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel
|
||||||
import kotlinx.android.synthetic.main.fragment_room_directory_picker.*
|
import kotlinx.android.synthetic.main.fragment_room_directory_picker.*
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
@ -39,6 +41,7 @@ import timber.log.Timber
|
||||||
class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerController.Callback {
|
class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerController.Callback {
|
||||||
|
|
||||||
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||||
|
private val navigationViewModel: RoomDirectoryNavigationViewModel by activityViewModel()
|
||||||
private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel()
|
private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel()
|
||||||
private val roomDirectoryPickerController: RoomDirectoryPickerController by inject()
|
private val roomDirectoryPickerController: RoomDirectoryPickerController by inject()
|
||||||
|
|
||||||
|
@ -88,8 +91,7 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon
|
||||||
Timber.v("onRoomDirectoryClicked: $roomDirectoryData")
|
Timber.v("onRoomDirectoryClicked: $roomDirectoryData")
|
||||||
viewModel.setRoomDirectoryData(roomDirectoryData)
|
viewModel.setRoomDirectoryData(roomDirectoryData)
|
||||||
|
|
||||||
// TODO Not the best way to manage Fragment Backstack...
|
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
|
||||||
vectorBaseActivity.onBackPressed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun retry() {
|
override fun retry() {
|
||||||
|
|
Loading…
Reference in a new issue