mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 02:45:53 +03:00
Merge branch 'feature/epoxy' into develop
This commit is contained in:
commit
abb44839af
32 changed files with 349 additions and 321 deletions
|
@ -76,6 +76,7 @@ dependencies {
|
||||||
|
|
||||||
implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1'
|
implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1'
|
||||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||||
|
implementation 'com.facebook.stetho:stetho:1.5.0'
|
||||||
|
|
||||||
// rx
|
// rx
|
||||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.riotredesign
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
|
import com.facebook.stetho.Stetho
|
||||||
import com.jakewharton.threetenabp.AndroidThreeTen
|
import com.jakewharton.threetenabp.AndroidThreeTen
|
||||||
import im.vector.matrix.android.BuildConfig
|
import im.vector.matrix.android.BuildConfig
|
||||||
import im.vector.riotredesign.core.di.AppModule
|
import im.vector.riotredesign.core.di.AppModule
|
||||||
|
@ -33,6 +34,7 @@ class Riot : Application() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Timber.plant(Timber.DebugTree())
|
Timber.plant(Timber.DebugTree())
|
||||||
|
Stetho.initializeWithDefaults(this)
|
||||||
}
|
}
|
||||||
AndroidThreeTen.init(this)
|
AndroidThreeTen.init(this)
|
||||||
startKoin(listOf(AppModule(this).definition), logger = EmptyLogger())
|
startKoin(listOf(AppModule(this).definition), logger = EmptyLogger())
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.epoxy
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.annotation.IdRes
|
|
||||||
import androidx.annotation.LayoutRes
|
|
||||||
import com.airbnb.epoxy.EpoxyModel
|
|
||||||
import com.airbnb.epoxy.OnModelVisibilityStateChangedListener
|
|
||||||
import kotlin.properties.ReadOnlyProperty
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
abstract class KotlinModel(
|
|
||||||
@LayoutRes private val layoutRes: Int
|
|
||||||
) : EpoxyModel<View>() {
|
|
||||||
|
|
||||||
private var view: View? = null
|
|
||||||
private var onBindCallback: (() -> Unit)? = null
|
|
||||||
private var onModelVisibilityStateChangedListener: OnModelVisibilityStateChangedListener<KotlinModel, View>? = null
|
|
||||||
|
|
||||||
abstract fun bind()
|
|
||||||
|
|
||||||
override fun bind(view: View) {
|
|
||||||
this.view = view
|
|
||||||
onBindCallback?.invoke()
|
|
||||||
bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun unbind(view: View) {
|
|
||||||
this.view = null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onBind(lambda: (() -> Unit)?): KotlinModel {
|
|
||||||
onBindCallback = lambda
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onVisibilityStateChanged(visibilityState: Int, view: View) {
|
|
||||||
onModelVisibilityStateChangedListener?.onVisibilityStateChanged(this, view, visibilityState)
|
|
||||||
super.onVisibilityStateChanged(visibilityState, view)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOnVisibilityStateChanged(listener: OnModelVisibilityStateChangedListener<KotlinModel, View>): KotlinModel {
|
|
||||||
this.onModelVisibilityStateChangedListener = listener
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getDefaultLayout() = layoutRes
|
|
||||||
|
|
||||||
protected fun <V : View> bind(@IdRes id: Int) = object : ReadOnlyProperty<KotlinModel, V> {
|
|
||||||
override fun getValue(thisRef: KotlinModel, property: KProperty<*>): V {
|
|
||||||
// This is not efficient because it looks up the view by id every time (it loses
|
|
||||||
// the pattern of a "holder" to cache that look up). But it is simple to use and could
|
|
||||||
// be optimized with a map
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return view?.findViewById(id) as V?
|
|
||||||
?: throw IllegalStateException("View ID $id for '${property.name}' not found.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -26,15 +26,15 @@ import kotlin.reflect.KProperty
|
||||||
*
|
*
|
||||||
* See [SampleKotlinModelWithHolder] for a usage example.
|
* See [SampleKotlinModelWithHolder] for a usage example.
|
||||||
*/
|
*/
|
||||||
abstract class KotlinEpoxyHolder : EpoxyHolder() {
|
abstract class RiotEpoxyHolder : EpoxyHolder() {
|
||||||
private lateinit var view: View
|
private lateinit var view: View
|
||||||
|
|
||||||
override fun bindView(itemView: View) {
|
override fun bindView(itemView: View) {
|
||||||
view = itemView
|
view = itemView
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun <V : View> bind(id: Int): ReadOnlyProperty<KotlinEpoxyHolder, V> =
|
protected fun <V : View> bind(id: Int): ReadOnlyProperty<RiotEpoxyHolder, V> =
|
||||||
Lazy { holder: KotlinEpoxyHolder, prop ->
|
Lazy { holder: RiotEpoxyHolder, prop ->
|
||||||
holder.view.findViewById(id) as V?
|
holder.view.findViewById(id) as V?
|
||||||
?: throw IllegalStateException("View ID $id for '${prop.name}' not found.")
|
?: throw IllegalStateException("View ID $id for '${prop.name}' not found.")
|
||||||
}
|
}
|
||||||
|
@ -44,13 +44,13 @@ abstract class KotlinEpoxyHolder : EpoxyHolder() {
|
||||||
* https://github.com/JakeWharton/kotterknife
|
* https://github.com/JakeWharton/kotterknife
|
||||||
*/
|
*/
|
||||||
private class Lazy<V>(
|
private class Lazy<V>(
|
||||||
private val initializer: (KotlinEpoxyHolder, KProperty<*>) -> V
|
private val initializer: (RiotEpoxyHolder, KProperty<*>) -> V
|
||||||
) : ReadOnlyProperty<KotlinEpoxyHolder, V> {
|
) : ReadOnlyProperty<RiotEpoxyHolder, V> {
|
||||||
private object EMPTY
|
private object EMPTY
|
||||||
|
|
||||||
private var value: Any? = EMPTY
|
private var value: Any? = EMPTY
|
||||||
|
|
||||||
override fun getValue(thisRef: KotlinEpoxyHolder, property: KProperty<*>): V {
|
override fun getValue(thisRef: RiotEpoxyHolder, property: KProperty<*>): V {
|
||||||
if (value == EMPTY) {
|
if (value == EMPTY) {
|
||||||
value = initializer(thisRef, property)
|
value = initializer(thisRef, property)
|
||||||
}
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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.epoxy
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||||
|
import com.airbnb.epoxy.VisibilityState
|
||||||
|
|
||||||
|
abstract class RiotEpoxyModel<H : RiotEpoxyHolder> : EpoxyModelWithHolder<H>() {
|
||||||
|
|
||||||
|
private var onModelVisibilityStateChangedListener: OnVisibilityStateChangedListener? = null
|
||||||
|
|
||||||
|
override fun onVisibilityStateChanged(visibilityState: Int, view: H) {
|
||||||
|
onModelVisibilityStateChangedListener?.onVisibilityStateChanged(visibilityState)
|
||||||
|
super.onVisibilityStateChanged(visibilityState, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnVisibilityStateChanged(listener: OnVisibilityStateChangedListener): RiotEpoxyModel<H> {
|
||||||
|
this.onModelVisibilityStateChangedListener = listener
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnVisibilityStateChangedListener {
|
||||||
|
fun onVisibilityStateChanged(@VisibilityState.Visibility visibilityState: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -14,25 +14,24 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.group
|
package im.vector.riotredesign.core.utils
|
||||||
|
|
||||||
import arrow.core.Option
|
|
||||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
|
|
||||||
class SelectedGroupHolder {
|
open class RxStore<T>(defaultValue: T? = null) {
|
||||||
|
|
||||||
private val selectedGroupStream = BehaviorRelay.createDefault<Option<GroupSummary>>(Option.empty())
|
private val storeSubject: BehaviorRelay<T> = if (defaultValue == null) {
|
||||||
|
BehaviorRelay.create<T>()
|
||||||
fun setSelectedGroup(group: GroupSummary?) {
|
} else {
|
||||||
val optionValue = Option.fromNullable(group)
|
BehaviorRelay.createDefault(defaultValue)
|
||||||
selectedGroupStream.accept(optionValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectedGroup(): Observable<Option<GroupSummary>> {
|
fun observe(): Observable<T> {
|
||||||
return selectedGroupStream.hide()
|
return storeSubject.hide().distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun post(value: T) {
|
||||||
|
storeSubject.accept(value)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home
|
package im.vector.riotredesign.features.home
|
||||||
|
|
||||||
import im.vector.riotredesign.features.home.group.SelectedGroupHolder
|
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomHolder
|
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.DefaultItemFactory
|
import im.vector.riotredesign.features.home.room.detail.timeline.DefaultItemFactory
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.MessageItemFactory
|
import im.vector.riotredesign.features.home.room.detail.timeline.MessageItemFactory
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.RoomMemberItemFactory
|
import im.vector.riotredesign.features.home.room.detail.timeline.RoomMemberItemFactory
|
||||||
|
@ -80,11 +80,11 @@ class HomeModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
SelectedGroupHolder()
|
SelectedGroupStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
VisibleRoomHolder()
|
VisibleRoomStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.group
|
package im.vector.riotredesign.features.home.group
|
||||||
|
|
||||||
|
import arrow.core.Option
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
|
@ -25,7 +26,7 @@ import im.vector.riotredesign.core.platform.RiotViewModel
|
||||||
import org.koin.android.ext.android.get
|
import org.koin.android.ext.android.get
|
||||||
|
|
||||||
class GroupListViewModel(initialState: GroupListViewState,
|
class GroupListViewModel(initialState: GroupListViewState,
|
||||||
private val selectedGroupHolder: SelectedGroupHolder,
|
private val selectedGroupHolder: SelectedGroupStore,
|
||||||
private val session: Session
|
private val session: Session
|
||||||
) : RiotViewModel<GroupListViewState>(initialState) {
|
) : RiotViewModel<GroupListViewState>(initialState) {
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ class GroupListViewModel(initialState: GroupListViewState,
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
override fun create(viewModelContext: ViewModelContext, state: GroupListViewState): GroupListViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: GroupListViewState): GroupListViewModel? {
|
||||||
val currentSession = Matrix.getInstance().currentSession
|
val currentSession = Matrix.getInstance().currentSession
|
||||||
val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupHolder>()
|
val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupStore>()
|
||||||
return GroupListViewModel(state, selectedGroupHolder, currentSession)
|
return GroupListViewModel(state, selectedGroupHolder, currentSession)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +47,8 @@ class GroupListViewModel(initialState: GroupListViewState,
|
||||||
|
|
||||||
private fun observeState() {
|
private fun observeState() {
|
||||||
subscribe {
|
subscribe {
|
||||||
selectedGroupHolder.setSelectedGroup(it.selectedGroup)
|
val selectedGroup = Option.fromNullable(it.selectedGroup)
|
||||||
|
selectedGroupHolder.post(selectedGroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,13 @@ class GroupSummaryController(private val callback: Callback? = null
|
||||||
}
|
}
|
||||||
summaries.forEach { groupSummary ->
|
summaries.forEach { groupSummary ->
|
||||||
val isSelected = groupSummary.groupId == selected?.groupId
|
val isSelected = groupSummary.groupId == selected?.groupId
|
||||||
GroupSummaryItem(
|
groupSummaryItem {
|
||||||
groupName = groupSummary.displayName,
|
id(groupSummary.groupId)
|
||||||
avatarUrl = groupSummary.avatarUrl,
|
groupName(groupSummary.displayName)
|
||||||
isSelected = isSelected,
|
selected(isSelected)
|
||||||
listener = { callback?.onGroupSelected(groupSummary) }
|
avatarUrl(groupSummary.avatarUrl)
|
||||||
)
|
listener { callback?.onGroupSelected(groupSummary) }
|
||||||
.id(groupSummary.groupId)
|
}
|
||||||
.addTo(this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,25 +17,32 @@
|
||||||
package im.vector.riotredesign.features.home.group
|
package im.vector.riotredesign.features.home.group
|
||||||
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyHolder
|
||||||
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
import im.vector.riotredesign.core.platform.CheckableFrameLayout
|
import im.vector.riotredesign.core.platform.CheckableFrameLayout
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_group)
|
||||||
|
abstract class GroupSummaryItem : RiotEpoxyModel<GroupSummaryItem.Holder>() {
|
||||||
|
|
||||||
data class GroupSummaryItem(
|
@EpoxyAttribute lateinit var groupName: CharSequence
|
||||||
val groupName: CharSequence,
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
val avatarUrl: String?,
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
val isSelected: Boolean,
|
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||||
val listener: (() -> Unit)? = null
|
|
||||||
) : KotlinModel(R.layout.item_group) {
|
|
||||||
|
|
||||||
private val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
override fun bind(holder: Holder) {
|
||||||
private val rootView by bind<CheckableFrameLayout>(R.id.itemGroupLayout)
|
super.bind(holder)
|
||||||
|
holder.rootView.isSelected = selected
|
||||||
override fun bind() {
|
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||||
rootView.isSelected = isSelected
|
AvatarRenderer.render(avatarUrl, groupName.toString(), holder.avatarImageView)
|
||||||
rootView.setOnClickListener { listener?.invoke() }
|
|
||||||
AvatarRenderer.render(avatarUrl, groupName.toString(), avatarImageView)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Holder : RiotEpoxyHolder() {
|
||||||
|
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
||||||
|
val rootView by bind<CheckableFrameLayout>(R.id.itemGroupLayout)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,16 +14,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.room.detail.timeline
|
package im.vector.riotredesign.features.home.group
|
||||||
|
|
||||||
import im.vector.riotredesign.R
|
import arrow.core.Option
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||||
|
import im.vector.riotredesign.core.utils.RxStore
|
||||||
|
|
||||||
class BlankItem
|
class SelectedGroupStore : RxStore<Option<GroupSummary>>(Option.empty())
|
||||||
: KotlinModel(R.layout.item_timeline_event_blank) {
|
|
||||||
|
|
||||||
override fun bind() {
|
|
||||||
//no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,21 +16,6 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.room
|
package im.vector.riotredesign.features.home.room
|
||||||
|
|
||||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
import im.vector.riotredesign.core.utils.RxStore
|
||||||
import io.reactivex.Observable
|
|
||||||
import io.reactivex.subjects.BehaviorSubject
|
|
||||||
|
|
||||||
class VisibleRoomHolder {
|
class VisibleRoomStore : RxStore<String>()
|
||||||
|
|
||||||
private val visibleRoomStream = BehaviorRelay.create<String>()
|
|
||||||
|
|
||||||
fun setVisibleRoom(roomId: String) {
|
|
||||||
visibleRoomStream.accept(roomId)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun visibleRoom(): Observable<String> {
|
|
||||||
return visibleRoomStream.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -26,14 +26,14 @@ import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotredesign.core.extensions.lastMinBy
|
import im.vector.riotredesign.core.extensions.lastMinBy
|
||||||
import im.vector.riotredesign.core.platform.RiotViewModel
|
import im.vector.riotredesign.core.platform.RiotViewModel
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomHolder
|
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
import org.koin.android.ext.android.get
|
import org.koin.android.ext.android.get
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class RoomDetailViewModel(initialState: RoomDetailViewState,
|
class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val visibleRoomHolder: VisibleRoomHolder
|
private val visibleRoomHolder: VisibleRoomStore
|
||||||
) : RiotViewModel<RoomDetailViewState>(initialState) {
|
) : RiotViewModel<RoomDetailViewState>(initialState) {
|
||||||
|
|
||||||
private val room = session.getRoom(initialState.roomId)!!
|
private val room = session.getRoom(initialState.roomId)!!
|
||||||
|
@ -47,7 +47,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? {
|
||||||
val currentSession = Matrix.getInstance().currentSession
|
val currentSession = Matrix.getInstance().currentSession
|
||||||
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomHolder>()
|
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
|
||||||
return RoomDetailViewModel(state, currentSession, visibleRoomHolder)
|
return RoomDetailViewModel(state, currentSession, visibleRoomHolder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleIsDisplayed() {
|
private fun handleIsDisplayed() {
|
||||||
visibleRoomHolder.setVisibleRoom(roomId)
|
visibleRoomHolder.post(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeDisplayedEvents() {
|
private fun observeDisplayedEvents() {
|
||||||
|
|
|
@ -19,31 +19,33 @@ package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.LayoutRes
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyHolder
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
abstract class AbsMessageItem(private val informationData: MessageInformationData,
|
abstract class AbsMessageItem<H : AbsMessageItem.Holder> : RiotEpoxyModel<H>() {
|
||||||
@LayoutRes layoutRes: Int
|
|
||||||
) : KotlinModel(layoutRes) {
|
|
||||||
|
|
||||||
protected abstract val avatarImageView: ImageView
|
abstract val informationData: MessageInformationData
|
||||||
protected abstract val memberNameView: TextView
|
|
||||||
protected abstract val timeView: TextView
|
|
||||||
|
|
||||||
override fun bind() {
|
override fun bind(holder: H) {
|
||||||
if (informationData.showInformation) {
|
if (informationData.showInformation) {
|
||||||
avatarImageView.visibility = View.VISIBLE
|
holder.avatarImageView.visibility = View.VISIBLE
|
||||||
memberNameView.visibility = View.VISIBLE
|
holder.memberNameView.visibility = View.VISIBLE
|
||||||
timeView.visibility = View.VISIBLE
|
holder.timeView.visibility = View.VISIBLE
|
||||||
timeView.text = informationData.time
|
holder.timeView.text = informationData.time
|
||||||
memberNameView.text = informationData.memberName
|
holder.memberNameView.text = informationData.memberName
|
||||||
AvatarRenderer.render(informationData.avatarUrl, informationData.memberName?.toString(), avatarImageView)
|
AvatarRenderer.render(informationData.avatarUrl, informationData.memberName?.toString(), holder.avatarImageView)
|
||||||
} else {
|
} else {
|
||||||
avatarImageView.visibility = View.GONE
|
holder.avatarImageView.visibility = View.GONE
|
||||||
memberNameView.visibility = View.GONE
|
holder.memberNameView.visibility = View.GONE
|
||||||
timeView.visibility = View.GONE
|
holder.timeView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class Holder : RiotEpoxyHolder() {
|
||||||
|
abstract val avatarImageView: ImageView
|
||||||
|
abstract val memberNameView: TextView
|
||||||
|
abstract val timeView: TextView
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,16 +17,22 @@
|
||||||
package im.vector.riotredesign.features.home.room.detail.timeline
|
package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyHolder
|
||||||
|
|
||||||
data class DaySeparatorItem(
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_day_separator)
|
||||||
val formattedDay: CharSequence
|
abstract class DaySeparatorItem : EpoxyModelWithHolder<DaySeparatorItem.Holder>() {
|
||||||
) : KotlinModel(R.layout.item_timeline_event_day_separator) {
|
|
||||||
|
|
||||||
private val dayTextView by bind<TextView>(R.id.itemDayTextView)
|
@EpoxyAttribute lateinit var formattedDay: CharSequence
|
||||||
|
|
||||||
override fun bind() {
|
override fun bind(holder: Holder) {
|
||||||
dayTextView.text = formattedDay
|
holder.dayTextView.text = formattedDay
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : RiotEpoxyHolder() {
|
||||||
|
val dayTextView by bind<TextView>(R.id.itemDayTextView)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,16 +17,22 @@
|
||||||
package im.vector.riotredesign.features.home.room.detail.timeline
|
package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyHolder
|
||||||
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
|
|
||||||
class DefaultItem(
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_default)
|
||||||
val text: CharSequence? = null
|
abstract class DefaultItem : RiotEpoxyModel<DefaultItem.Holder>() {
|
||||||
) : KotlinModel(R.layout.item_timeline_event_default) {
|
|
||||||
|
|
||||||
private val messageView by bind<TextView>(R.id.stateMessageView)
|
@EpoxyAttribute var text: CharSequence? = null
|
||||||
|
|
||||||
override fun bind() {
|
override fun bind(holder: Holder) {
|
||||||
messageView.text = text
|
holder.messageView.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : RiotEpoxyHolder() {
|
||||||
|
val messageView by bind<TextView>(R.id.stateMessageView)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,7 +26,7 @@ class DefaultItemFactory {
|
||||||
} else {
|
} else {
|
||||||
"an exception occurred when rendering the event ${event.root.eventId}"
|
"an exception occurred when rendering the event ${event.root.eventId}"
|
||||||
}
|
}
|
||||||
return DefaultItem(text = text)
|
return DefaultItem_().text(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,23 +18,27 @@ package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.MediaContentRenderer
|
||||||
|
|
||||||
class MessageImageItem(
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_image_message)
|
||||||
private val mediaData: MediaContentRenderer.Data,
|
abstract class MessageImageItem : AbsMessageItem<MessageImageItem.Holder>() {
|
||||||
informationData: MessageInformationData
|
|
||||||
) : AbsMessageItem(informationData, R.layout.item_timeline_event_image_message) {
|
|
||||||
|
|
||||||
|
@EpoxyAttribute lateinit var mediaData: MediaContentRenderer.Data
|
||||||
|
@EpoxyAttribute override lateinit var informationData: MessageInformationData
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
MediaContentRenderer.render(mediaData, MediaContentRenderer.Mode.THUMBNAIL, holder.imageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : AbsMessageItem.Holder() {
|
||||||
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
|
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
|
||||||
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
||||||
override val timeView by bind<TextView>(R.id.messageTimeView)
|
override val timeView by bind<TextView>(R.id.messageTimeView)
|
||||||
private val imageView by bind<ImageView>(R.id.messageImageView)
|
val imageView by bind<ImageView>(R.id.messageImageView)
|
||||||
|
|
||||||
override fun bind() {
|
|
||||||
super.bind()
|
|
||||||
MediaContentRenderer.render(mediaData, MediaContentRenderer.Mode.THUMBNAIL, imageView)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -26,7 +26,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
import im.vector.riotredesign.core.extensions.localDateTime
|
import im.vector.riotredesign.core.extensions.localDateTime
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.MediaContentRenderer
|
||||||
|
@ -39,7 +39,7 @@ class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSiz
|
||||||
fun create(event: TimelineEvent,
|
fun create(event: TimelineEvent,
|
||||||
nextEvent: TimelineEvent?,
|
nextEvent: TimelineEvent?,
|
||||||
callback: TimelineEventController.Callback?
|
callback: TimelineEventController.Callback?
|
||||||
): KotlinModel? {
|
): RiotEpoxyModel<*>? {
|
||||||
|
|
||||||
val roomMember = event.roomMember
|
val roomMember = event.roomMember
|
||||||
val nextRoomMember = nextEvent?.roomMember
|
val nextRoomMember = nextEvent?.roomMember
|
||||||
|
@ -71,9 +71,9 @@ class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSiz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildNotHandledMessageItem(messageContent: MessageContent): KotlinModel? {
|
private fun buildNotHandledMessageItem(messageContent: MessageContent): DefaultItem? {
|
||||||
val text = "${messageContent.type} message events are not yet handled"
|
val text = "${messageContent.type} message events are not yet handled"
|
||||||
return DefaultItem(text = text)
|
return DefaultItem_().text(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildImageMessageItem(messageContent: MessageImageContent,
|
private fun buildImageMessageItem(messageContent: MessageImageContent,
|
||||||
|
@ -89,7 +89,9 @@ class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSiz
|
||||||
rotation = messageContent.info?.rotation,
|
rotation = messageContent.info?.rotation,
|
||||||
orientation = messageContent.info?.orientation
|
orientation = messageContent.info?.orientation
|
||||||
)
|
)
|
||||||
return MessageImageItem(data, informationData)
|
return MessageImageItem_()
|
||||||
|
.informationData(informationData)
|
||||||
|
.mediaData(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildTextMessageItem(messageContent: MessageTextContent,
|
private fun buildTextMessageItem(messageContent: MessageTextContent,
|
||||||
|
@ -106,10 +108,9 @@ class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSiz
|
||||||
Linkify.addLinks(spannable, Linkify.ALL)
|
Linkify.addLinks(spannable, Linkify.ALL)
|
||||||
spannable
|
spannable
|
||||||
}
|
}
|
||||||
return MessageTextItem(
|
return MessageTextItem_()
|
||||||
message = message,
|
.message(message)
|
||||||
informationData = informationData
|
.informationData(informationData)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,22 +18,29 @@ package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.matrix.android.api.permalinks.MatrixLinkify
|
import im.vector.matrix.android.api.permalinks.MatrixLinkify
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
|
|
||||||
class MessageTextItem(
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_text_message)
|
||||||
val message: CharSequence? = null,
|
abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
|
||||||
informationData: MessageInformationData
|
|
||||||
) : AbsMessageItem(informationData, R.layout.item_timeline_event_text_message) {
|
|
||||||
|
|
||||||
|
@EpoxyAttribute var message: CharSequence? = null
|
||||||
|
@EpoxyAttribute override lateinit var informationData: MessageInformationData
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.messageView.text = message
|
||||||
|
MatrixLinkify.addLinkMovementMethod(holder.messageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : AbsMessageItem.Holder() {
|
||||||
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
|
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
|
||||||
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
||||||
override val timeView by bind<TextView>(R.id.messageTimeView)
|
override val timeView by bind<TextView>(R.id.messageTimeView)
|
||||||
private val messageView by bind<TextView>(R.id.messageTextView)
|
val messageView by bind<TextView>(R.id.messageTextView)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun bind() {
|
|
||||||
super.bind()
|
|
||||||
messageView.text = message
|
|
||||||
MatrixLinkify.addLinkMovementMethod(messageView)
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -18,20 +18,27 @@ package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyHolder
|
||||||
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
class NoticeItem(private val noticeText: CharSequence? = null,
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_notice)
|
||||||
private val avatarUrl: String?,
|
abstract class NoticeItem : RiotEpoxyModel<NoticeItem.Holder>() {
|
||||||
private val memberName: CharSequence? = null)
|
|
||||||
: KotlinModel(R.layout.item_timeline_event_notice) {
|
|
||||||
|
|
||||||
private val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
|
@EpoxyAttribute var noticeText: CharSequence? = null
|
||||||
private val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
|
@EpoxyAttribute var memberName: CharSequence? = null
|
||||||
|
|
||||||
override fun bind() {
|
override fun bind(holder: Holder) {
|
||||||
noticeTextView.text = noticeText
|
holder.noticeTextView.text = noticeText
|
||||||
AvatarRenderer.render(avatarUrl, memberName?.toString(), avatarImageView)
|
AvatarRenderer.render(avatarUrl, memberName?.toString(), holder.avatarImageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : RiotEpoxyHolder() {
|
||||||
|
val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
|
||||||
|
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,10 +17,10 @@
|
||||||
package im.vector.riotredesign.features.home.room.detail.timeline
|
package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||||
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
|
|
||||||
|
@ -31,7 +31,10 @@ class RoomMemberItemFactory(private val stringProvider: StringProvider) {
|
||||||
fun create(event: TimelineEvent): NoticeItem? {
|
fun create(event: TimelineEvent): NoticeItem? {
|
||||||
val roomMember = event.roomMember ?: return null
|
val roomMember = event.roomMember ?: return null
|
||||||
val noticeText = buildRoomMemberNotice(event) ?: return null
|
val noticeText = buildRoomMemberNotice(event) ?: return null
|
||||||
return NoticeItem(noticeText, roomMember.avatarUrl, roomMember.displayName)
|
return NoticeItem_()
|
||||||
|
.noticeText(noticeText)
|
||||||
|
.avatarUrl(roomMember.avatarUrl)
|
||||||
|
.memberName(roomMember.displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildRoomMemberNotice(event: TimelineEvent): String? {
|
private fun buildRoomMemberNotice(event: TimelineEvent): String? {
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
package im.vector.riotredesign.features.home.room.detail.timeline
|
package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomNameContent
|
import im.vector.matrix.android.api.session.room.model.RoomNameContent
|
||||||
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
|
|
||||||
|
@ -37,7 +37,10 @@ class RoomNameItemFactory(private val stringProvider: StringProvider) {
|
||||||
} else {
|
} else {
|
||||||
stringProvider.getString(R.string.notice_room_name_removed, roomMember.displayName)
|
stringProvider.getString(R.string.notice_room_name_removed, roomMember.displayName)
|
||||||
}
|
}
|
||||||
return NoticeItem(text, roomMember.avatarUrl, roomMember.displayName)
|
return NoticeItem_()
|
||||||
|
.noticeText(text)
|
||||||
|
.avatarUrl(roomMember.avatarUrl)
|
||||||
|
.memberName(roomMember.displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,10 @@ class RoomTopicItemFactory(private val stringProvider: StringProvider) {
|
||||||
} else {
|
} else {
|
||||||
stringProvider.getString(R.string.notice_room_topic_changed, roomMember.displayName, content.topic)
|
stringProvider.getString(R.string.notice_room_topic_changed, roomMember.displayName, content.topic)
|
||||||
}
|
}
|
||||||
return NoticeItem(text, roomMember.avatarUrl, roomMember.displayName)
|
return NoticeItem_()
|
||||||
|
.noticeText(text)
|
||||||
|
.avatarUrl(roomMember.avatarUrl)
|
||||||
|
.memberName(roomMember.displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,14 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.room.detail.timeline
|
package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.airbnb.epoxy.EpoxyAsyncUtil
|
import com.airbnb.epoxy.EpoxyAsyncUtil
|
||||||
import com.airbnb.epoxy.EpoxyModel
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
import com.airbnb.epoxy.OnModelVisibilityStateChangedListener
|
|
||||||
import com.airbnb.epoxy.VisibilityState
|
import com.airbnb.epoxy.VisibilityState
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
import im.vector.riotredesign.core.extensions.localDateTime
|
import im.vector.riotredesign.core.extensions.localDateTime
|
||||||
import im.vector.riotredesign.features.home.LoadingItemModel_
|
import im.vector.riotredesign.features.home.LoadingItemModel_
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
|
@ -78,16 +76,12 @@ class TimelineEventController(private val roomId: String,
|
||||||
|
|
||||||
timelineItemFactory.create(event, nextEvent, callback)?.also {
|
timelineItemFactory.create(event, nextEvent, callback)?.also {
|
||||||
it.id(event.localId)
|
it.id(event.localId)
|
||||||
it.setOnVisibilityStateChanged(OnModelVisibilityStateChangedListener<KotlinModel, View> { model, view, visibilityState ->
|
it.setOnVisibilityStateChanged(TimelineEventVisibilityStateChangedListener(callback, event, currentPosition))
|
||||||
if (visibilityState == VisibilityState.VISIBLE) {
|
|
||||||
callback?.onEventVisible(event, currentPosition)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
epoxyModels.add(it)
|
epoxyModels.add(it)
|
||||||
}
|
}
|
||||||
if (addDaySeparator) {
|
if (addDaySeparator) {
|
||||||
val formattedDay = dateFormatter.formatMessageDay(date)
|
val formattedDay = dateFormatter.formatMessageDay(date)
|
||||||
val daySeparatorItem = DaySeparatorItem(formattedDay).id(roomId + formattedDay)
|
val daySeparatorItem = DaySeparatorItem_().formattedDay(formattedDay).id(roomId + formattedDay)
|
||||||
epoxyModels.add(daySeparatorItem)
|
epoxyModels.add(daySeparatorItem)
|
||||||
}
|
}
|
||||||
return epoxyModels
|
return epoxyModels
|
||||||
|
@ -112,3 +106,17 @@ class TimelineEventController(private val roomId: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TimelineEventVisibilityStateChangedListener(private val callback: TimelineEventController.Callback?,
|
||||||
|
private val event: TimelineEvent,
|
||||||
|
private val currentPosition: Int)
|
||||||
|
: RiotEpoxyModel.OnVisibilityStateChangedListener {
|
||||||
|
|
||||||
|
override fun onVisibilityStateChanged(visibilityState: Int) {
|
||||||
|
if (visibilityState == VisibilityState.VISIBLE) {
|
||||||
|
callback?.onEventVisible(event, currentPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
|
|
||||||
class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
||||||
private val roomNameItemFactory: RoomNameItemFactory,
|
private val roomNameItemFactory: RoomNameItemFactory,
|
||||||
|
@ -28,7 +28,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
||||||
|
|
||||||
fun create(event: TimelineEvent,
|
fun create(event: TimelineEvent,
|
||||||
nextEvent: TimelineEvent?,
|
nextEvent: TimelineEvent?,
|
||||||
callback: TimelineEventController.Callback?): KotlinModel? {
|
callback: TimelineEventController.Callback?): RiotEpoxyModel<*>? {
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
when (event.root.type) {
|
when (event.root.type) {
|
||||||
|
|
|
@ -20,33 +20,39 @@ import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.graphics.drawable.DrawableCompat
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyHolder
|
||||||
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
|
|
||||||
data class RoomCategoryItem(
|
@EpoxyModelClass(layout = R.layout.item_room_category)
|
||||||
val title: CharSequence,
|
abstract class RoomCategoryItem : RiotEpoxyModel<RoomCategoryItem.Holder>() {
|
||||||
val isExpanded: Boolean,
|
|
||||||
val unreadCount: Int,
|
|
||||||
val showHighlighted: Boolean,
|
|
||||||
val listener: (() -> Unit)? = null
|
|
||||||
) : KotlinModel(R.layout.item_room_category) {
|
|
||||||
|
|
||||||
private val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomCategoryUnreadCounterBadgeView)
|
@EpoxyAttribute lateinit var title: CharSequence
|
||||||
private val titleView by bind<TextView>(R.id.roomCategoryTitleView)
|
@EpoxyAttribute var expanded: Boolean = false
|
||||||
private val rootView by bind<ViewGroup>(R.id.roomCategoryRootView)
|
@EpoxyAttribute var unreadCount: Int = 0
|
||||||
|
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||||
|
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||||
|
|
||||||
private val tintColor by lazy {
|
override fun bind(holder: Holder) {
|
||||||
ContextCompat.getColor(rootView.context, R.color.bluey_grey_two)
|
val tintColor = ContextCompat.getColor(holder.rootView.context, R.color.bluey_grey_two)
|
||||||
}
|
val expandedArrowDrawableRes = if (expanded) R.drawable.ic_expand_more_white else R.drawable.ic_expand_less_white
|
||||||
|
val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also {
|
||||||
override fun bind() {
|
|
||||||
val expandedArrowDrawableRes = if (isExpanded) R.drawable.ic_expand_more_white else R.drawable.ic_expand_less_white
|
|
||||||
val expandedArrowDrawable = ContextCompat.getDrawable(rootView.context, expandedArrowDrawableRes)?.also {
|
|
||||||
DrawableCompat.setTint(it, tintColor)
|
DrawableCompat.setTint(it, tintColor)
|
||||||
}
|
}
|
||||||
unreadCounterBadgeView.render(unreadCount, showHighlighted)
|
holder.unreadCounterBadgeView.render(unreadCount, showHighlighted)
|
||||||
titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null)
|
holder.titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null)
|
||||||
titleView.text = title
|
holder.titleView.text = title
|
||||||
rootView.setOnClickListener { listener?.invoke() }
|
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Holder : RiotEpoxyHolder() {
|
||||||
|
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomCategoryUnreadCounterBadgeView)
|
||||||
|
val titleView by bind<TextView>(R.id.roomCategoryTitleView)
|
||||||
|
val rootView by bind<ViewGroup>(R.id.roomCategoryRootView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotredesign.core.platform.RiotViewModel
|
import im.vector.riotredesign.core.platform.RiotViewModel
|
||||||
import im.vector.riotredesign.features.home.group.SelectedGroupHolder
|
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomHolder
|
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.functions.Function3
|
import io.reactivex.functions.Function3
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
|
@ -39,8 +39,8 @@ typealias RoomListFilterName = CharSequence
|
||||||
|
|
||||||
class RoomListViewModel(initialState: RoomListViewState,
|
class RoomListViewModel(initialState: RoomListViewState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val selectedGroupHolder: SelectedGroupHolder,
|
private val selectedGroupHolder: SelectedGroupStore,
|
||||||
private val visibleRoomHolder: VisibleRoomHolder,
|
private val visibleRoomHolder: VisibleRoomStore,
|
||||||
private val roomSelectionRepository: RoomSelectionRepository,
|
private val roomSelectionRepository: RoomSelectionRepository,
|
||||||
private val roomSummaryComparator: RoomSummaryComparator)
|
private val roomSummaryComparator: RoomSummaryComparator)
|
||||||
: RiotViewModel<RoomListViewState>(initialState) {
|
: RiotViewModel<RoomListViewState>(initialState) {
|
||||||
|
@ -51,8 +51,8 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||||
override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? {
|
||||||
val currentSession = Matrix.getInstance().currentSession
|
val currentSession = Matrix.getInstance().currentSession
|
||||||
val roomSelectionRepository = viewModelContext.activity.get<RoomSelectionRepository>()
|
val roomSelectionRepository = viewModelContext.activity.get<RoomSelectionRepository>()
|
||||||
val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupHolder>()
|
val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupStore>()
|
||||||
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomHolder>()
|
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
|
||||||
val roomSummaryComparator = viewModelContext.activity.get<RoomSummaryComparator>()
|
val roomSummaryComparator = viewModelContext.activity.get<RoomSummaryComparator>()
|
||||||
return RoomListViewModel(state, currentSession, selectedGroupHolder, visibleRoomHolder, roomSelectionRepository, roomSummaryComparator)
|
return RoomListViewModel(state, currentSession, selectedGroupHolder, visibleRoomHolder, roomSelectionRepository, roomSummaryComparator)
|
||||||
}
|
}
|
||||||
|
@ -87,17 +87,18 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeVisibleRoom() {
|
private fun observeVisibleRoom() {
|
||||||
visibleRoomHolder.visibleRoom()
|
visibleRoomHolder.observe()
|
||||||
.subscribeBy {
|
.doOnNext {
|
||||||
setState { copy(selectedRoomId = it) }
|
setState { copy(selectedRoomId = it) }
|
||||||
}
|
}
|
||||||
|
.subscribe()
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeRoomSummaries() {
|
private fun observeRoomSummaries() {
|
||||||
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, Option<RoomListFilterName>, RoomSummaries>(
|
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, Option<RoomListFilterName>, RoomSummaries>(
|
||||||
session.rx().liveRoomSummaries().throttleLast(300, TimeUnit.MILLISECONDS),
|
session.rx().liveRoomSummaries().throttleLast(300, TimeUnit.MILLISECONDS),
|
||||||
selectedGroupHolder.selectedGroup(),
|
selectedGroupHolder.observe(),
|
||||||
roomListFilter.throttleLast(300, TimeUnit.MILLISECONDS),
|
roomListFilter.throttleLast(300, TimeUnit.MILLISECONDS),
|
||||||
Function3 { rooms, selectedGroupOption, filterRoomOption ->
|
Function3 { rooms, selectedGroupOption, filterRoomOption ->
|
||||||
val filteredRooms = filterRooms(rooms, filterRoomOption)
|
val filteredRooms = filterRooms(rooms, filterRoomOption)
|
||||||
|
|
|
@ -85,18 +85,17 @@ class RoomSummaryController(private val stringProvider: StringProvider
|
||||||
summaries.map { it.notificationCount }.reduce { acc, i -> acc + i }
|
summaries.map { it.notificationCount }.reduce { acc, i -> acc + i }
|
||||||
}
|
}
|
||||||
val showHighlighted = summaries.any { it.highlightCount > 0 }
|
val showHighlighted = summaries.any { it.highlightCount > 0 }
|
||||||
RoomCategoryItem(
|
roomCategoryItem {
|
||||||
title = stringProvider.getString(titleRes).toUpperCase(),
|
id(titleRes)
|
||||||
isExpanded = isExpanded,
|
title(stringProvider.getString(titleRes).toUpperCase())
|
||||||
unreadCount = unreadCount,
|
expanded(isExpanded)
|
||||||
showHighlighted = showHighlighted,
|
unreadCount(unreadCount)
|
||||||
listener = {
|
showHighlighted(showHighlighted)
|
||||||
|
listener {
|
||||||
mutateExpandedState()
|
mutateExpandedState()
|
||||||
setData(viewState)
|
setData(viewState)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
.id(titleRes)
|
|
||||||
.addTo(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildRoomModels(summaries: List<RoomSummary>, selectedRoomId: String?) {
|
private fun buildRoomModels(summaries: List<RoomSummary>, selectedRoomId: String?) {
|
||||||
|
@ -104,16 +103,16 @@ class RoomSummaryController(private val stringProvider: StringProvider
|
||||||
val unreadCount = roomSummary.notificationCount
|
val unreadCount = roomSummary.notificationCount
|
||||||
val showHighlighted = roomSummary.highlightCount > 0
|
val showHighlighted = roomSummary.highlightCount > 0
|
||||||
val isSelected = roomSummary.roomId == selectedRoomId
|
val isSelected = roomSummary.roomId == selectedRoomId
|
||||||
RoomSummaryItem(
|
|
||||||
roomName = roomSummary.displayName,
|
roomSummaryItem {
|
||||||
avatarUrl = roomSummary.avatarUrl,
|
id(roomSummary.roomId)
|
||||||
isSelected = isSelected,
|
roomName(roomSummary.displayName)
|
||||||
showHighlighted = showHighlighted,
|
avatarUrl(roomSummary.avatarUrl)
|
||||||
unreadCount = unreadCount,
|
selected(isSelected)
|
||||||
listener = { callback?.onRoomSelected(roomSummary) }
|
showHighlighted(showHighlighted)
|
||||||
)
|
unreadCount(unreadCount)
|
||||||
.id(roomSummary.roomId)
|
listener { callback?.onRoomSelected(roomSummary) }
|
||||||
.addTo(this)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,31 +18,40 @@ package im.vector.riotredesign.features.home.room.list
|
||||||
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyHolder
|
||||||
|
import im.vector.riotredesign.core.epoxy.RiotEpoxyModel
|
||||||
import im.vector.riotredesign.core.platform.CheckableFrameLayout
|
import im.vector.riotredesign.core.platform.CheckableFrameLayout
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
|
|
||||||
data class RoomSummaryItem(
|
@EpoxyModelClass(layout = R.layout.item_room)
|
||||||
val roomName: CharSequence,
|
abstract class RoomSummaryItem : RiotEpoxyModel<RoomSummaryItem.Holder>() {
|
||||||
val avatarUrl: String?,
|
|
||||||
val isSelected: Boolean,
|
|
||||||
val unreadCount: Int,
|
|
||||||
val showHighlighted: Boolean,
|
|
||||||
val listener: (() -> Unit)? = null
|
|
||||||
) : KotlinModel(R.layout.item_room) {
|
|
||||||
|
|
||||||
private val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
@EpoxyAttribute lateinit var roomName: CharSequence
|
||||||
private val titleView by bind<TextView>(R.id.roomNameView)
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
private val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
private val rootView by bind<CheckableFrameLayout>(R.id.itemRoomLayout)
|
@EpoxyAttribute var unreadCount: Int = 0
|
||||||
|
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||||
|
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||||
|
|
||||||
override fun bind() {
|
|
||||||
unreadCounterBadgeView.render(unreadCount, showHighlighted)
|
override fun bind(holder: Holder) {
|
||||||
rootView.isChecked = isSelected
|
super.bind(holder)
|
||||||
rootView.setOnClickListener { listener?.invoke() }
|
holder.unreadCounterBadgeView.render(unreadCount, showHighlighted)
|
||||||
titleView.text = roomName
|
holder.rootView.isChecked = selected
|
||||||
AvatarRenderer.render(avatarUrl, roomName.toString(), avatarImageView)
|
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||||
|
holder.titleView.text = roomName
|
||||||
|
AvatarRenderer.render(avatarUrl, roomName.toString(), holder.avatarImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Holder : RiotEpoxyHolder() {
|
||||||
|
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
||||||
|
val titleView by bind<TextView>(R.id.roomNameView)
|
||||||
|
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
||||||
|
val rootView by bind<CheckableFrameLayout>(R.id.itemRoomLayout)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -95,6 +95,7 @@ dependencies {
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||||
|
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'
|
||||||
|
|
||||||
debugImplementation 'com.airbnb.okreplay:okreplay:1.4.0'
|
debugImplementation 'com.airbnb.okreplay:okreplay:1.4.0'
|
||||||
releaseImplementation 'com.airbnb.okreplay:noop:1.4.0'
|
releaseImplementation 'com.airbnb.okreplay:noop:1.4.0'
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.di
|
package im.vector.matrix.android.internal.di
|
||||||
|
|
||||||
|
import com.facebook.stetho.okhttp3.StethoInterceptor
|
||||||
import im.vector.matrix.android.internal.network.AccessTokenInterceptor
|
import im.vector.matrix.android.internal.network.AccessTokenInterceptor
|
||||||
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
||||||
import im.vector.matrix.android.internal.network.UnitConverterFactory
|
import im.vector.matrix.android.internal.network.UnitConverterFactory
|
||||||
|
@ -47,11 +48,16 @@ class NetworkModule {
|
||||||
OkReplayInterceptor()
|
OkReplayInterceptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single {
|
||||||
|
StethoInterceptor()
|
||||||
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
OkHttpClient.Builder()
|
OkHttpClient.Builder()
|
||||||
.connectTimeout(30, TimeUnit.SECONDS)
|
.connectTimeout(30, TimeUnit.SECONDS)
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
.writeTimeout(30, TimeUnit.SECONDS)
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
|
.addNetworkInterceptor(get<StethoInterceptor>())
|
||||||
.addInterceptor(get<AccessTokenInterceptor>())
|
.addInterceptor(get<AccessTokenInterceptor>())
|
||||||
.addInterceptor(get<HttpLoggingInterceptor>())
|
.addInterceptor(get<HttpLoggingInterceptor>())
|
||||||
.addInterceptor(get<OkReplayInterceptor>())
|
.addInterceptor(get<OkReplayInterceptor>())
|
||||||
|
|
Loading…
Reference in a new issue