mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-21 17:05:39 +03:00
Introduce MvRx in the application + start managing UI
This commit is contained in:
parent
d0a241bd2d
commit
e5fc1e3412
52 changed files with 805 additions and 133 deletions
Binary file not shown.
|
@ -10,7 +10,7 @@
|
|||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/matrix-sdk-android" />
|
||||
<option value="$PROJECT_DIR$/matrix-sdk-rx" />
|
||||
<option value="$PROJECT_DIR$/matrix-sdk-android-rx" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
|
|
@ -41,6 +41,7 @@ dependencies {
|
|||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(":matrix-sdk-android")
|
||||
implementation project(":matrix-sdk-android-rx")
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
|
@ -51,11 +52,11 @@ dependencies {
|
|||
implementation("com.airbnb.android:epoxy:$epoxy_version")
|
||||
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
||||
implementation "com.airbnb.android:epoxy-paging:$epoxy_version"
|
||||
implementation 'com.airbnb.android:mvrx:0.6.0'
|
||||
|
||||
|
||||
implementation "org.koin:koin-android:$koin_version"
|
||||
implementation "org.koin:koin-android-scope:$koin_version"
|
||||
implementation "org.koin:koin-android-viewmodel:$koin_version"
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package im.vector.riotredesign.core.platform
|
||||
|
||||
import android.content.Context
|
||||
import android.support.constraint.ConstraintLayout
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.Checkable
|
||||
|
||||
class CheckableConstraintLayout : ConstraintLayout, Checkable {
|
||||
|
||||
private var mChecked = false
|
||||
|
||||
constructor(context: Context) : super(context) {}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
|
||||
|
||||
override fun isChecked(): Boolean {
|
||||
return mChecked
|
||||
}
|
||||
|
||||
override fun setChecked(b: Boolean) {
|
||||
if (b != mChecked) {
|
||||
mChecked = b
|
||||
refreshDrawableState()
|
||||
}
|
||||
}
|
||||
|
||||
override fun toggle() {
|
||||
isChecked = !mChecked
|
||||
}
|
||||
|
||||
public override fun onCreateDrawableState(extraSpace: Int): IntArray {
|
||||
val drawableState = super.onCreateDrawableState(extraSpace + 1)
|
||||
if (isChecked) {
|
||||
View.mergeDrawableStates(drawableState, CHECKED_STATE_SET)
|
||||
}
|
||||
return drawableState
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val CHECKED_STATE_SET = intArrayOf(android.R.attr.state_checked)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package im.vector.riotredesign.core.platform
|
||||
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import com.airbnb.mvrx.BaseMvRxActivity
|
||||
|
||||
open class RiotActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
abstract class RiotActivity : BaseMvRxActivity()
|
|
@ -1,6 +1,12 @@
|
|||
package im.vector.riotredesign.core.platform
|
||||
|
||||
import android.support.v4.app.Fragment
|
||||
import com.airbnb.mvrx.BaseMvRxFragment
|
||||
|
||||
abstract class RiotFragment : BaseMvRxFragment() {
|
||||
|
||||
override fun invalidate() {
|
||||
//no-ops by default
|
||||
}
|
||||
|
||||
|
||||
open class RiotFragment : Fragment() {
|
||||
}
|
81
app/src/main/java/im/vector/riotredesign/core/platform/StateView.kt
Executable file
81
app/src/main/java/im/vector/riotredesign/core/platform/StateView.kt
Executable file
|
@ -0,0 +1,81 @@
|
|||
package im.vector.riotredesign.core.platform
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import im.vector.riotredesign.R
|
||||
import kotlinx.android.synthetic.main.view_state.view.*
|
||||
|
||||
class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: FrameLayout(context, attrs, defStyle) {
|
||||
|
||||
sealed class State {
|
||||
object Content : State()
|
||||
object Loading : State()
|
||||
data class Empty(val message: CharSequence? = null) : State()
|
||||
data class Error(val message: CharSequence? = null) : State()
|
||||
}
|
||||
|
||||
|
||||
private var eventCallback: EventCallback? = null
|
||||
|
||||
var contentView: View? = null
|
||||
|
||||
var state: State = State.Empty()
|
||||
set(newState) {
|
||||
if (newState != state) {
|
||||
update(newState)
|
||||
}
|
||||
}
|
||||
|
||||
interface EventCallback {
|
||||
fun onRetryClicked()
|
||||
}
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.view_state, this)
|
||||
layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
errorRetryView.setOnClickListener {
|
||||
eventCallback?.onRetryClicked()
|
||||
}
|
||||
state = State.Content
|
||||
}
|
||||
|
||||
|
||||
private fun update(newState: State) {
|
||||
when (newState) {
|
||||
is StateView.State.Content -> {
|
||||
progressBar.visibility = View.INVISIBLE
|
||||
errorView.visibility = View.INVISIBLE
|
||||
emptyView.visibility = View.INVISIBLE
|
||||
contentView?.visibility = View.VISIBLE
|
||||
}
|
||||
is StateView.State.Loading -> {
|
||||
progressBar.visibility = View.VISIBLE
|
||||
errorView.visibility = View.INVISIBLE
|
||||
emptyView.visibility = View.INVISIBLE
|
||||
contentView?.visibility = View.INVISIBLE
|
||||
}
|
||||
is StateView.State.Empty -> {
|
||||
progressBar.visibility = View.INVISIBLE
|
||||
errorView.visibility = View.INVISIBLE
|
||||
emptyView.visibility = View.VISIBLE
|
||||
emptyMessageView.text = newState.message
|
||||
if (contentView != null) {
|
||||
contentView!!.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
is StateView.State.Error -> {
|
||||
progressBar.visibility = View.INVISIBLE
|
||||
errorView.visibility = View.VISIBLE
|
||||
emptyView.visibility = View.INVISIBLE
|
||||
errorMessageView.text = newState.message
|
||||
if (contentView != null) {
|
||||
contentView!!.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,23 +3,37 @@ package im.vector.riotredesign.features.home
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.replaceFragment
|
||||
import im.vector.riotredesign.core.platform.RiotActivity
|
||||
import im.vector.riotredesign.features.home.detail.LoadingRoomDetailFragment
|
||||
import im.vector.riotredesign.features.home.detail.RoomDetailFragment
|
||||
import im.vector.riotredesign.features.home.list.RoomListFragment
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import org.koin.standalone.StandAloneContext.loadKoinModules
|
||||
|
||||
|
||||
class HomeActivity : RiotActivity() {
|
||||
class HomeActivity : RiotActivity(), HomeNavigator {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_home)
|
||||
|
||||
loadKoinModules(listOf(HomeModule(this)))
|
||||
if (savedInstanceState == null) {
|
||||
val roomListFragment = RoomListFragment.newInstance()
|
||||
replaceFragment(roomListFragment, R.id.homeFragmentContainer)
|
||||
val loadingDetail = LoadingRoomDetailFragment.newInstance()
|
||||
replaceFragment(loadingDetail, R.id.homeDetailFragmentContainer)
|
||||
replaceFragment(roomListFragment, R.id.homeDrawerFragmentContainer)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openRoomDetail(roomId: String) {
|
||||
val roomDetailFragment = RoomDetailFragment.newInstance(roomId)
|
||||
replaceFragment(roomDetailFragment, R.id.homeDetailFragmentContainer)
|
||||
drawerLayout.closeDrawer(Gravity.LEFT)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newIntent(context: Context): Intent {
|
||||
return Intent(context, HomeActivity::class.java)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import org.koin.dsl.context.ModuleDefinition
|
||||
import org.koin.dsl.module.Module
|
||||
import org.koin.dsl.module.module
|
||||
|
||||
class HomeModule(private val homeActivity: HomeActivity) : Module {
|
||||
|
||||
override fun invoke(): ModuleDefinition = module(override = true) {
|
||||
|
||||
factory {
|
||||
homeActivity as HomeNavigator
|
||||
}
|
||||
|
||||
}.invoke()
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
interface HomeNavigator {
|
||||
|
||||
fun openRoomDetail(roomId: String)
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotredesign.core.platform.RiotFragment
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): RoomListFragment {
|
||||
return RoomListFragment()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val matrix by inject<Matrix>()
|
||||
private val currentSession = matrix.currentSession!!
|
||||
private lateinit var roomController: RoomSummaryController
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_room_list, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
roomController = RoomSummaryController(this)
|
||||
epoxyRecyclerView.setController(roomController)
|
||||
currentSession.liveRoomSummaries().observe(this, Observer<List<RoomSummary>> { renderRooms(it) })
|
||||
}
|
||||
|
||||
private fun renderRooms(rooms: List<RoomSummary>?) {
|
||||
roomController.setData(rooms)
|
||||
}
|
||||
|
||||
override fun onRoomSelected(room: RoomSummary) {
|
||||
val detailFragment = RoomDetailFragment.newInstance(room.roomId)
|
||||
addFragmentToBackstack(detailFragment, R.id.homeFragmentContainer)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
class RoomSummaryController(private val callback: Callback? = null
|
||||
) : TypedEpoxyController<List<RoomSummary>>() {
|
||||
|
||||
override fun buildModels(data: List<RoomSummary>?) {
|
||||
data?.forEach {
|
||||
RoomItem(it.displayName, listener = { callback?.onRoomSelected(it) })
|
||||
.id(it.roomId)
|
||||
.addTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onRoomSelected(room: RoomSummary)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
package im.vector.riotredesign.features.home.detail
|
||||
|
||||
import android.support.v7.util.DiffUtil
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
|
@ -0,0 +1,24 @@
|
|||
package im.vector.riotredesign.features.home.detail
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.RiotFragment
|
||||
|
||||
class LoadingRoomDetailFragment : RiotFragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): LoadingRoomDetailFragment {
|
||||
return LoadingRoomDetailFragment()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_loading_room_detail, container, false)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
package im.vector.riotredesign.features.home.detail
|
||||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.arch.paging.PagedList
|
|
@ -1,4 +1,4 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
package im.vector.riotredesign.features.home.detail
|
||||
|
||||
import android.arch.paging.PagedList
|
||||
import android.arch.paging.PagedListAdapter
|
|
@ -1,9 +1,10 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
package im.vector.riotredesign.features.home.detail
|
||||
|
||||
import com.airbnb.epoxy.EpoxyAsyncUtil
|
||||
import com.airbnb.epoxy.EpoxyModel
|
||||
import com.airbnb.epoxy.paging.PagedListEpoxyController
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.riotredesign.features.home.LoadingItemModel_
|
||||
|
||||
class TimelineEventController : PagedListEpoxyController<Event>(
|
||||
diffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
|
@ -1,4 +1,4 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
package im.vector.riotredesign.features.home.detail
|
||||
|
||||
import android.widget.TextView
|
||||
import im.vector.riotredesign.R
|
|
@ -0,0 +1,10 @@
|
|||
package im.vector.riotredesign.features.home.list
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
sealed class RoomListActions {
|
||||
|
||||
data class SelectRoom(val roomSummary: RoomSummary) : RoomListActions()
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package im.vector.riotredesign.features.home.list
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.*
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.RiotFragment
|
||||
import im.vector.riotredesign.core.platform.StateView
|
||||
import im.vector.riotredesign.features.home.HomeNavigator
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
|
||||
|
||||
companion object {
|
||||
fun newInstance(): RoomListFragment {
|
||||
return RoomListFragment()
|
||||
}
|
||||
}
|
||||
|
||||
private val homeNavigator by inject<HomeNavigator>()
|
||||
private val viewModel: RoomListViewModel by fragmentViewModel()
|
||||
private lateinit var roomController: RoomSummaryController
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_room_list, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
roomController = RoomSummaryController(this)
|
||||
stateView.contentView = epoxyRecyclerView
|
||||
epoxyRecyclerView.setController(roomController)
|
||||
viewModel.subscribe { renderState(it) }
|
||||
}
|
||||
|
||||
private fun renderState(state: RoomListViewState) {
|
||||
when (state.roomSummaries) {
|
||||
is Incomplete -> renderLoading()
|
||||
is Success -> renderSuccess(state.roomSummaries(), state.selectedRoom)
|
||||
is Fail -> renderFailure(state.roomSummaries.error)
|
||||
}
|
||||
if (state.showLastSelectedRoom && state.selectedRoom != null) {
|
||||
homeNavigator.openRoomDetail(state.selectedRoom.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSuccess(roomSummaries: List<RoomSummary>?, selectedRoom: RoomSummary?) {
|
||||
if (roomSummaries.isNullOrEmpty()) {
|
||||
stateView.state = StateView.State.Empty("Rejoignez une room pour commencer à utiliser l'application")
|
||||
} else {
|
||||
stateView.state = StateView.State.Content
|
||||
}
|
||||
roomController.setData(roomSummaries, selectedRoom)
|
||||
}
|
||||
|
||||
private fun renderLoading() {
|
||||
stateView.state = StateView.State.Loading
|
||||
}
|
||||
|
||||
private fun renderFailure(error: Throwable) {
|
||||
val message = when (error) {
|
||||
is Failure.NetworkConnection -> "Pas de connexion internet"
|
||||
else -> "Une erreur est survenue"
|
||||
}
|
||||
stateView.state = StateView.State.Error(message)
|
||||
}
|
||||
|
||||
override fun onRoomSelected(room: RoomSummary) {
|
||||
withState(viewModel) {
|
||||
if (it.selectedRoom != room) {
|
||||
viewModel.accept(RoomListActions.SelectRoom(room))
|
||||
homeNavigator.openRoomDetail(room.roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package im.vector.riotredesign.features.home.list
|
||||
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import com.airbnb.mvrx.BaseMvRxViewModel
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.rx.rx
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
class RoomListViewModel(initialState: RoomListViewState,
|
||||
private val session: Session
|
||||
) : BaseMvRxViewModel<RoomListViewState>(initialState) {
|
||||
|
||||
companion object : MvRxViewModelFactory<RoomListViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(activity: FragmentActivity, state: RoomListViewState): RoomListViewModel {
|
||||
val matrix = activity.get<Matrix>()
|
||||
val currentSession = matrix.currentSession!!
|
||||
return RoomListViewModel(state, currentSession)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
observeRoomSummaries()
|
||||
}
|
||||
|
||||
fun accept(action: RoomListActions) {
|
||||
when (action) {
|
||||
is RoomListActions.SelectRoom -> handleSelectRoom(action)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleSelectRoom(action: RoomListActions.SelectRoom) {
|
||||
session.saveLastSelectedRoom(action.roomSummary)
|
||||
setState { copy(selectedRoom = action.roomSummary) }
|
||||
}
|
||||
|
||||
private fun observeRoomSummaries() {
|
||||
session
|
||||
.rx().liveRoomSummaries()
|
||||
.execute {
|
||||
val selectedRoom = selectedRoom
|
||||
?: session.lastSelectedRoom()
|
||||
?: it.invoke()?.firstOrNull()
|
||||
|
||||
copy(roomSummaries = it, selectedRoom = selectedRoom)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package im.vector.riotredesign.features.home.list
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
data class RoomListViewState(
|
||||
val roomSummaries: Async<List<RoomSummary>> = Uninitialized,
|
||||
val selectedRoom: RoomSummary? = null
|
||||
) : MvRxState {
|
||||
|
||||
var showLastSelectedRoom: Boolean = true
|
||||
private set
|
||||
get() {
|
||||
if (field) {
|
||||
field = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package im.vector.riotredesign.features.home.list
|
||||
|
||||
import com.airbnb.epoxy.Typed2EpoxyController
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
class RoomSummaryController(private val callback: Callback? = null
|
||||
|
||||
) : Typed2EpoxyController<List<RoomSummary>, RoomSummary>() {
|
||||
|
||||
override fun buildModels(summaries: List<RoomSummary>?, selected: RoomSummary?) {
|
||||
summaries?.forEach {
|
||||
RoomSummaryItem(
|
||||
it.displayName,
|
||||
isSelected = it == selected,
|
||||
listener = { callback?.onRoomSelected(it) }
|
||||
)
|
||||
.id(it.roomId)
|
||||
.addTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onRoomSelected(room: RoomSummary)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,22 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
package im.vector.riotredesign.features.home.list
|
||||
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.widget.TextView
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
||||
import im.vector.riotredesign.core.platform.CheckableConstraintLayout
|
||||
|
||||
data class RoomItem(
|
||||
data class RoomSummaryItem(
|
||||
val title: CharSequence,
|
||||
val isSelected: Boolean,
|
||||
val listener: (() -> Unit)? = null
|
||||
) : KotlinModel(R.layout.item_room) {
|
||||
|
||||
val titleView by bind<TextView>(R.id.titleView)
|
||||
val rootView by bind<CheckableConstraintLayout>(R.id.itemRoomLayout)
|
||||
|
||||
override fun bind() {
|
||||
rootView.isChecked = isSelected
|
||||
titleView.setOnClickListener { listener?.invoke() }
|
||||
titleView.text = title
|
||||
}
|
19
app/src/main/res/drawable/bg_room_item.xml
Normal file
19
app/src/main/res/drawable/bg_room_item.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<shape>
|
||||
<solid android:color="@android:color/white"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_checked="true">
|
||||
<shape>
|
||||
<solid android:color="@android:color/white"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="@android:color/transparent"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</selector>
|
|
@ -1,15 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".features.login.LoginActivity">
|
||||
tools:openDrawer="start">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/homeFragmentContainer"
|
||||
android:id="@+id/homeDetailFragmentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/homeDrawerFragmentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginRight="24dp" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
</android.support.v4.widget.DrawerLayout>
|
20
app/src/main/res/layout/fragment_loading_room_detail.xml
Normal file
20
app/src/main/res/layout/fragment_loading_room_detail.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
|
@ -1,11 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<im.vector.riotredesign.core.platform.StateView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/stateView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/pale_grey">
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/epoxyRecyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
</im.vector.riotredesign.core.platform.StateView>
|
|
@ -1,10 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
<im.vector.riotredesign.core.platform.CheckableConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/itemRoomLayout"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_room_item"
|
||||
android:minHeight="80dp">
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/titleView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Room name" />
|
||||
|
||||
</im.vector.riotredesign.core.platform.CheckableConstraintLayout>
|
73
app/src/main/res/layout/view_state.xml
Normal file
73
app/src/main/res/layout/view_state.xml
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="40dp"
|
||||
android:padding="8dp"
|
||||
tools:parentTag="android.widget.FrameLayout">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/errorView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errorMessageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="16sp"
|
||||
tools:text="Une erreur est survenue" />
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/errorRetryView"
|
||||
android:layout_width="190dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/global_retry"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/emptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/emptyMessageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="16sp" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/emptyImageView"
|
||||
android:layout_width="190dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
|
@ -3,4 +3,16 @@
|
|||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
|
||||
|
||||
<color name="pale_grey">#f2f5f8</color>
|
||||
<color name="dark">#2e3649</color>
|
||||
<color name="pale_teal">#7ac9a1</color>
|
||||
<color name="black">#212121</color>
|
||||
<color name="deep_sky_blue">#007aff</color>
|
||||
<color name="rosy_pink">#f56679</color>
|
||||
<color name="bluey_grey">#a5a5a6</color>
|
||||
<color name="slate_grey">#5f6268</color>
|
||||
<color name="sky_blue">#7bb2ea</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<resources>
|
||||
<string name="app_name">Riot Redesign</string>
|
||||
|
||||
<string name="global_retry">Réessayer</string>
|
||||
|
||||
</resources>
|
||||
|
|
40
matrix-sdk-android-rx/build.gradle
Normal file
40
matrix-sdk-android-rx/build.gradle
Normal file
|
@ -0,0 +1,40 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(":matrix-sdk-android")
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
|
||||
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
}
|
21
matrix-sdk-android-rx/proguard-rules.pro
vendored
Normal file
21
matrix-sdk-android-rx/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,26 @@
|
|||
package im.vector.matrix.rx;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("im.vector.matrix.rx.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
2
matrix-sdk-android-rx/src/main/AndroidManifest.xml
Normal file
2
matrix-sdk-android-rx/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="im.vector.matrix.rx" />
|
|
@ -0,0 +1,45 @@
|
|||
package im.vector.matrix.rx
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
import android.arch.lifecycle.Observer
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.MainThreadDisposable
|
||||
|
||||
private class LiveDataObservable<T>(
|
||||
private val liveData: LiveData<T>,
|
||||
private val valueIfNull: T? = null
|
||||
) : Observable<T>() {
|
||||
|
||||
override fun subscribeActual(observer: io.reactivex.Observer<in T>) {
|
||||
val relay = RemoveObserverInMainThread(observer)
|
||||
observer.onSubscribe(relay)
|
||||
liveData.observeForever(relay)
|
||||
}
|
||||
|
||||
private inner class RemoveObserverInMainThread(private val observer: io.reactivex.Observer<in T>)
|
||||
: MainThreadDisposable(), Observer<T> {
|
||||
|
||||
override fun onChanged(t: T?) {
|
||||
if (!isDisposed) {
|
||||
if (t == null) {
|
||||
if (valueIfNull != null) {
|
||||
observer.onNext(valueIfNull)
|
||||
} else {
|
||||
observer.onError(NullPointerException(
|
||||
"convert liveData value t to RxJava onNext(t), t cannot be null"))
|
||||
}
|
||||
} else {
|
||||
observer.onNext(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDispose() {
|
||||
liveData.removeObserver(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.asObservable(): Observable<T> {
|
||||
return LiveDataObservable(this)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package im.vector.matrix.rx
|
||||
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import io.reactivex.Observable
|
||||
|
||||
class RxSession(private val session: Session) {
|
||||
|
||||
fun liveRoomSummaries(): Observable<List<RoomSummary>> {
|
||||
return session.liveRoomSummaries().asObservable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Session.rx(): RxSession {
|
||||
return RxSession(this)
|
||||
}
|
3
matrix-sdk-android-rx/src/main/res/values/strings.xml
Normal file
3
matrix-sdk-android-rx/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">matrix-sdk-android-rx</string>
|
||||
</resources>
|
|
@ -0,0 +1,17 @@
|
|||
package im.vector.matrix.rx;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -2,22 +2,12 @@ package im.vector.matrix.android.api.failure
|
|||
|
||||
import java.io.IOException
|
||||
|
||||
sealed class Failure {
|
||||
sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
|
||||
|
||||
data class Unknown(val exception: Exception? = null) : Failure()
|
||||
data class NetworkConnection(val ioException: IOException) : Failure()
|
||||
data class ServerError(val error: MatrixError) : Failure()
|
||||
data class Unknown(val throwable: Throwable? = null) : Failure(throwable)
|
||||
data class NetworkConnection(val ioException: IOException) : Failure(ioException)
|
||||
data class ServerError(val error: MatrixError) : Failure(RuntimeException(error.toString()))
|
||||
|
||||
abstract class FeatureFailure : Failure()
|
||||
|
||||
fun toException(): Exception {
|
||||
return when (this) {
|
||||
is Unknown -> this.exception ?: RuntimeException("Unknown error")
|
||||
is NetworkConnection -> this.ioException
|
||||
is ServerError -> RuntimeException(this.error.toString())
|
||||
is FeatureFailure -> RuntimeException("Feature error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -13,5 +13,9 @@ interface RoomService {
|
|||
|
||||
fun liveRoomSummaries(): LiveData<List<RoomSummary>>
|
||||
|
||||
fun lastSelectedRoom(): RoomSummary?
|
||||
|
||||
fun saveLastSelectedRoom(roomSummary: RoomSummary)
|
||||
|
||||
|
||||
}
|
|
@ -13,8 +13,20 @@ object RoomSummaryMapper {
|
|||
roomSummaryEntity.topic ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
internal fun map(roomSummary: RoomSummary): RoomSummaryEntity {
|
||||
return RoomSummaryEntity(
|
||||
roomSummary.roomId,
|
||||
roomSummary.displayName,
|
||||
roomSummary.topic
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun RoomSummaryEntity.asDomain(): RoomSummary {
|
||||
return RoomSummaryMapper.map(this)
|
||||
}
|
||||
|
||||
fun RoomSummaryEntity.asEntity(): RoomSummary {
|
||||
return RoomSummaryMapper.map(this)
|
||||
}
|
|
@ -11,7 +11,8 @@ open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
|||
var lastMessage: EventEntity? = null,
|
||||
var heroes: RealmList<String> = RealmList(),
|
||||
var joinedMembersCount: Int? = 0,
|
||||
var invitedMembersCount: Int? = 0
|
||||
var invitedMembersCount: Int? = 0,
|
||||
var isLatestSelected: Boolean = false
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
|
|
|
@ -13,3 +13,9 @@ fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): Rea
|
|||
}
|
||||
return query
|
||||
}
|
||||
|
||||
fun RoomSummaryEntity.Companion.lastSelected(realm: Realm): RoomSummaryEntity? {
|
||||
return realm.where<RoomSummaryEntity>()
|
||||
.equalTo(RoomSummaryEntityFields.IS_LATEST_SELECTED, true)
|
||||
.findFirst()
|
||||
}
|
||||
|
|
|
@ -75,6 +75,14 @@ class DefaultSession(override val sessionParams: SessionParams) : Session, KoinC
|
|||
return roomService.liveRoomSummaries()
|
||||
}
|
||||
|
||||
override fun lastSelectedRoom(): RoomSummary? {
|
||||
return roomService.lastSelectedRoom()
|
||||
}
|
||||
|
||||
override fun saveLastSelectedRoom(roomSummary: RoomSummary) {
|
||||
roomService.saveLastSelectedRoom(roomSummary)
|
||||
}
|
||||
|
||||
// Private methods *****************************************************************************
|
||||
|
||||
private fun checkIsMainThread() {
|
||||
|
|
|
@ -8,6 +8,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
|
|||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.lastSelected
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
|
||||
class DefaultRoomService(private val monarchy: Monarchy) : RoomService {
|
||||
|
@ -42,5 +43,20 @@ class DefaultRoomService(private val monarchy: Monarchy) : RoomService {
|
|||
)
|
||||
}
|
||||
|
||||
override fun lastSelectedRoom(): RoomSummary? {
|
||||
var lastSelected: RoomSummary? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
lastSelected = RoomSummaryEntity.lastSelected(realm)?.asDomain()
|
||||
}
|
||||
return lastSelected
|
||||
}
|
||||
|
||||
override fun saveLastSelectedRoom(roomSummary: RoomSummary) {
|
||||
monarchy.writeAsync { realm ->
|
||||
val lastSelected = RoomSummaryEntity.lastSelected(realm)
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomSummary.roomId).findFirst()
|
||||
lastSelected?.isLatestSelected = false
|
||||
roomSummaryEntity?.isLatestSelected = true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ class TimelineBoundaryCallback(private val roomId: String,
|
|||
}
|
||||
|
||||
override fun onFailure(failure: Failure) {
|
||||
pagingRequestCallback.recordFailure(failure.toException())
|
||||
pagingRequestCallback.recordFailure(failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
apply plugin: 'java-library'
|
||||
apply plugin: "kotlin"
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
package im.vector.matrix.rx
|
||||
|
||||
class MatrixRx
|
|
@ -1 +1 @@
|
|||
include ':app', ':matrix-sdk-rx', ':matrix-sdk-android'
|
||||
include ':app', ':matrix-sdk-android', ':matrix-sdk-android-rx'
|
||||
|
|
Loading…
Reference in a new issue