Better modularization + move image loading to view model

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2019-10-17 12:54:15 +02:00
parent 06ed99f3ad
commit ead2ca24c9
12 changed files with 174 additions and 115 deletions

View File

@ -28,7 +28,10 @@ import com.nextcloud.talk.utils.ApiUtils
class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : NextcloudTalkRepository { class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : NextcloudTalkRepository {
override suspend fun getConversationsForUser(user: UserEntity): List<Conversation> { override suspend fun getConversationsForUser(user: UserEntity): List<Conversation> {
return apiService.getConversations(ApiUtils.getCredentials(user.username, user.token), return apiService.getConversations(
ApiUtils.getUrlForGetRooms(user.baseUrl)).ocs.data ApiUtils.getCredentials(user.username, user.token),
ApiUtils.getUrlForGetRooms(user.baseUrl)
)
.ocs.data
} }
} }

View File

@ -64,7 +64,9 @@ class ApiErrorHandler {
else -> null else -> null
} }
return errorModel ?: ErrorModel( return errorModel ?: ErrorModel(
NextcloudTalkApplication.sharedApplication?.resources!!.getString(R.string.nc_not_defined_error), 0, ErrorModel.ErrorStatus.BAD_RESPONSE NextcloudTalkApplication.sharedApplication?.resources!!.getString(
R.string.nc_not_defined_error
), 0, ErrorModel.ErrorStatus.BAD_RESPONSE
) )
} }

View File

@ -27,6 +27,6 @@ val CommunicationModule = module {
single { createEventBus() } single { createEventBus() }
} }
fun createEventBus() : EventBus { fun createEventBus(): EventBus {
return EventBus.getDefault() return EventBus.getDefault()
} }

View File

@ -174,8 +174,11 @@ fun createTrustManager(): MagicTrustManager {
return MagicTrustManager() return MagicTrustManager()
} }
fun createSslSocketFactory(magicKeyManager: MagicKeyManager, magicTrustManager: fun createSslSocketFactory(
MagicTrustManager) : SSLSocketFactoryCompat { magicKeyManager: MagicKeyManager,
magicTrustManager:
MagicTrustManager
): SSLSocketFactoryCompat {
return SSLSocketFactoryCompat(magicKeyManager, magicTrustManager) return SSLSocketFactoryCompat(magicKeyManager, magicTrustManager)
} }
@ -227,14 +230,14 @@ fun createProxy(appPreferences: AppPreferences): Proxy {
} }
fun createDispatcher() : Dispatcher { fun createDispatcher(): Dispatcher {
val dispatcher = Dispatcher() val dispatcher = Dispatcher()
dispatcher.maxRequestsPerHost = 100 dispatcher.maxRequestsPerHost = 100
dispatcher.maxRequests = 100 dispatcher.maxRequests = 100
return dispatcher return dispatcher
} }
fun createCache(androidApplication: NextcloudTalkApplication) : Cache { fun createCache(androidApplication: NextcloudTalkApplication): Cache {
val cacheSize = 128 * 1024 * 1024 // 128 MB val cacheSize = 128 * 1024 * 1024 // 128 MB
return Cache(androidApplication.cacheDir, cacheSize.toLong()) return Cache(androidApplication.cacheDir, cacheSize.toLong())
} }

View File

@ -57,6 +57,6 @@ fun createDataStore(sqlCipherDatabaseSource: SqlCipherDatabaseSource): ReactiveE
return ReactiveSupport.toReactiveStore(EntityDataStore(configuration)) return ReactiveSupport.toReactiveStore(EntityDataStore(configuration))
} }
fun createUserUtils(dataStore : ReactiveEntityStore<Persistable>) : UserUtils { fun createUserUtils(dataStore: ReactiveEntityStore<Persistable>): UserUtils {
return UserUtils(dataStore) return UserUtils(dataStore)
} }

View File

@ -20,17 +20,19 @@
package com.nextcloud.talk.newarch.features.conversationsList package com.nextcloud.talk.newarch.features.conversationsList
import android.app.Application
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.nextcloud.talk.newarch.domain.usecases.GetConversationsUseCase import com.nextcloud.talk.newarch.domain.usecases.GetConversationsUseCase
import com.nextcloud.talk.utils.database.user.UserUtils import com.nextcloud.talk.utils.database.user.UserUtils
class ConversationListViewModelFactory constructor( class ConversationListViewModelFactory constructor(
private val application: Application,
private val conversationsUseCase: GetConversationsUseCase, private val conversationsUseCase: GetConversationsUseCase,
private val userUtils: UserUtils private val userUtils: UserUtils
): ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T { override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ConversationsListViewModel(conversationsUseCase, userUtils) as T return ConversationsListViewModel(application, conversationsUseCase, userUtils) as T
} }
} }

View File

@ -22,8 +22,6 @@ package com.nextcloud.talk.newarch.features.conversationsList
import android.app.SearchManager import android.app.SearchManager
import android.content.Context import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.InputType import android.text.InputType
@ -36,7 +34,6 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.SearchView.OnQueryTextListener import androidx.appcompat.widget.SearchView.OnQueryTextListener
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.core.view.MenuItemCompat import androidx.core.view.MenuItemCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.recyclerview.widget.RecyclerView.ViewHolder
@ -45,12 +42,6 @@ import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.bluelinelabs.conductor.changehandler.TransitionChangeHandlerCompat import com.bluelinelabs.conductor.changehandler.TransitionChangeHandlerCompat
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
import com.facebook.common.executors.UiThreadImmediateExecutorService
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.CloseableImage
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.adapters.items.ConversationItem import com.nextcloud.talk.adapters.items.ConversationItem
import com.nextcloud.talk.controllers.ContactsController import com.nextcloud.talk.controllers.ContactsController
@ -64,7 +55,6 @@ import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED
import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED_EMPTY import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED_EMPTY
import com.nextcloud.talk.newarch.mvvm.ViewState.LOADING import com.nextcloud.talk.newarch.mvvm.ViewState.LOADING
import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.ConductorRemapping import com.nextcloud.talk.utils.ConductorRemapping
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.animations.SharedElementTransition import com.nextcloud.talk.utils.animations.SharedElementTransition
@ -77,6 +67,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
import kotlinx.android.synthetic.main.controller_conversations_rv.view.dataStateView import kotlinx.android.synthetic.main.controller_conversations_rv.view.dataStateView
import kotlinx.android.synthetic.main.controller_conversations_rv.view.floatingActionButton import kotlinx.android.synthetic.main.controller_conversations_rv.view.floatingActionButton
import kotlinx.android.synthetic.main.controller_conversations_rv.view.recyclerView import kotlinx.android.synthetic.main.controller_conversations_rv.view.recyclerView
import kotlinx.android.synthetic.main.controller_conversations_rv.view.swipeRefreshLayoutView
import kotlinx.android.synthetic.main.fast_scroller.view.fast_scroller import kotlinx.android.synthetic.main.fast_scroller.view.fast_scroller
import kotlinx.android.synthetic.main.view_states.view.errorStateImageView import kotlinx.android.synthetic.main.view_states.view.errorStateImageView
import kotlinx.android.synthetic.main.view_states.view.errorStateTextView import kotlinx.android.synthetic.main.view_states.view.errorStateTextView
@ -95,6 +86,7 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
private val recyclerViewAdapter = FlexibleAdapter(mutableListOf()) private val recyclerViewAdapter = FlexibleAdapter(mutableListOf())
private var searchItem: MenuItem? = null private var searchItem: MenuItem? = null
private var settingsItem: MenuItem? = null
private var searchView: SearchView? = null private var searchView: SearchView? = null
override fun onCreateOptionsMenu( override fun onCreateOptionsMenu(
@ -115,7 +107,17 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
recyclerViewAdapter.filterItems() recyclerViewAdapter.filterItems()
} }
loadUserAvatar(menu.findItem(R.id.action_settings)) settingsItem = menu.findItem(R.id.action_settings)
val iconSize = settingsItem?.icon?.intrinsicHeight?.toFloat()
?.let {
DisplayUtils.convertDpToPixel(
it,
activity
)
.toInt()
}
iconSize?.let { viewModel.loadAvatar(it) }
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -182,6 +184,7 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
viewState.observe(this@ConversationsListView, Observer { value -> viewState.observe(this@ConversationsListView, Observer { value ->
when (value) { when (value) {
LOADING -> { LOADING -> {
view?.swipeRefreshLayoutView?.isEnabled = false
view?.loadingStateView?.visibility = View.VISIBLE view?.loadingStateView?.visibility = View.VISIBLE
view?.stateWithMessageView?.visibility = View.GONE view?.stateWithMessageView?.visibility = View.GONE
view?.dataStateView?.visibility = View.GONE view?.dataStateView?.visibility = View.GONE
@ -189,6 +192,10 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
searchItem?.isVisible = false searchItem?.isVisible = false
} }
LOADED -> { LOADED -> {
view?.swipeRefreshLayoutView?.isEnabled = true
view?.swipeRefreshLayoutView?.post {
view?.swipeRefreshLayoutView?.isRefreshing = false
}
view?.loadingStateView?.visibility = View.GONE view?.loadingStateView?.visibility = View.GONE
view?.stateWithMessageView?.visibility = View.GONE view?.stateWithMessageView?.visibility = View.GONE
view?.dataStateView?.visibility = View.VISIBLE view?.dataStateView?.visibility = View.VISIBLE
@ -196,6 +203,10 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
searchItem?.isVisible = true searchItem?.isVisible = true
} }
LOADED_EMPTY, FAILED -> { LOADED_EMPTY, FAILED -> {
view?.swipeRefreshLayoutView?.post {
view?.swipeRefreshLayoutView?.isRefreshing = false
}
view?.swipeRefreshLayoutView?.isEnabled = true
view?.loadingStateView?.visibility = View.GONE view?.loadingStateView?.visibility = View.GONE
view?.dataStateView?.visibility = View.GONE view?.dataStateView?.visibility = View.GONE
view?.floatingActionButton?.visibility = View.GONE view?.floatingActionButton?.visibility = View.GONE
@ -218,10 +229,6 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
// We should not be here // We should not be here
} }
} }
searchQuery.observe(this@ConversationsListView, Observer {
recyclerViewAdapter.setFilter(it)
recyclerViewAdapter.filterItems(500)
}) })
conversationsListData.observe(this@ConversationsListView, Observer { conversationsListData.observe(this@ConversationsListView, Observer {
@ -233,46 +240,20 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
recyclerViewAdapter.updateDataSet(newConversations as List<IFlexible<ViewHolder>>?) recyclerViewAdapter.updateDataSet(newConversations as List<IFlexible<ViewHolder>>?)
}) })
searchQuery.observe(this@ConversationsListView, Observer {
recyclerViewAdapter.setFilter(it)
recyclerViewAdapter.filterItems(500)
})
currentUserAvatar.observe(this@ConversationsListView, Observer {
settingsItem?.icon = it
}) })
} }
return super.onCreateView(inflater, container) return super.onCreateView(inflater, container)
} }
private fun loadUserAvatar(menuItem: MenuItem) {
if (activity != null) {
val avatarSize =
DisplayUtils.convertDpToPixel(menuItem.icon.intrinsicHeight.toFloat(), activity!!)
.toInt()
val imageRequest = DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithNameAndPixels(
viewModel.currentUser.baseUrl,
viewModel.currentUser.userId, avatarSize
), null
)
val imagePipeline = Fresco.getImagePipeline()
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
dataSource.subscribe(object : BaseBitmapDataSubscriber() {
override fun onNewResultImpl(bitmap: Bitmap?) {
if (bitmap != null && resources != null) {
val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(
resources as Resources,
bitmap
)
roundedBitmapDrawable.isCircular = true
roundedBitmapDrawable.setAntiAlias(true)
menuItem.icon = roundedBitmapDrawable
}
}
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
menuItem.setIcon(R.drawable.ic_settings_white_24dp)
}
}, UiThreadImmediateExecutorService.getInstance())
}
}
override fun getLayoutId(): Int { override fun getLayoutId(): Int {
return R.layout.controller_conversations_rv return R.layout.controller_conversations_rv
} }
@ -309,6 +290,9 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
SmoothScrollLinearLayoutManager(view.context), recyclerViewAdapter SmoothScrollLinearLayoutManager(view.context), recyclerViewAdapter
) )
view.swipeRefreshLayoutView.setOnRefreshListener { viewModel.loadConversations() }
view.swipeRefreshLayoutView.setColorSchemeResources(R.color.colorPrimary)
recyclerViewAdapter.fastScroller = view.fast_scroller recyclerViewAdapter.fastScroller = view.fast_scroller
recyclerViewAdapter.mItemClickListener = this recyclerViewAdapter.mItemClickListener = this
recyclerViewAdapter.mItemLongClickListener = this recyclerViewAdapter.mItemLongClickListener = this

View File

@ -20,8 +20,20 @@
package com.nextcloud.talk.newarch.features.conversationsList package com.nextcloud.talk.newarch.features.conversationsList
import android.app.Application
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.facebook.common.executors.UiThreadImmediateExecutorService
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.CloseableImage
import com.nextcloud.talk.R
import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.newarch.conversationsList.mvp.BaseViewModel import com.nextcloud.talk.newarch.conversationsList.mvp.BaseViewModel
@ -33,19 +45,30 @@ import com.nextcloud.talk.newarch.mvvm.ViewState.FAILED
import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED
import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED_EMPTY import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED_EMPTY
import com.nextcloud.talk.newarch.mvvm.ViewState.LOADING import com.nextcloud.talk.newarch.mvvm.ViewState.LOADING
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.database.user.UserUtils import com.nextcloud.talk.utils.database.user.UserUtils
import org.apache.commons.lang3.builder.CompareToBuilder import org.apache.commons.lang3.builder.CompareToBuilder
class ConversationsListViewModel constructor( class ConversationsListViewModel constructor(
application: Application,
private val conversationsUseCase: GetConversationsUseCase, private val conversationsUseCase: GetConversationsUseCase,
private val userUtils: UserUtils private val userUtils: UserUtils
) : BaseViewModel<ConversationsListView>() { ) : BaseViewModel<ConversationsListView>(application) {
val conversationsListData = MutableLiveData<List<Conversation>>() val conversationsListData = MutableLiveData<List<Conversation>>()
val viewState = MutableLiveData<ViewState>(LOADING) val viewState = MutableLiveData<ViewState>(LOADING)
var messageData: String? = null var messageData: String? = null
val searchQuery = MutableLiveData<String>() val searchQuery = MutableLiveData<String>()
var currentUser: UserEntity = userUtils.currentUser var currentUser: UserEntity = userUtils.currentUser
var currentUserAvatar: MutableLiveData<Drawable> = MutableLiveData()
get() {
if (field.value == null) {
field.value = context.resources.getDrawable(R.drawable.ic_settings_white_24dp)
}
return field
}
fun loadConversations() { fun loadConversations() {
currentUser = userUtils.currentUser currentUser = userUtils.currentUser
@ -81,4 +104,34 @@ class ConversationsListViewModel constructor(
}) })
} }
fun loadAvatar(avatarSize: Int) {
val imageRequest = DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithNameAndPixels(
currentUser.baseUrl,
currentUser.userId, avatarSize
), null
)
val imagePipeline = Fresco.getImagePipeline()
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, viewModelScope)
dataSource.subscribe(object : BaseBitmapDataSubscriber() {
override fun onNewResultImpl(bitmap: Bitmap?) {
if (bitmap != null) {
val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(
context.resources as Resources,
bitmap
)
roundedBitmapDrawable.isCircular = true
roundedBitmapDrawable.setAntiAlias(true)
currentUserAvatar.value = roundedBitmapDrawable
}
}
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
currentUserAvatar.value = context.getDrawable(R.drawable.ic_settings_white_24dp)
}
}, UiThreadImmediateExecutorService.getInstance())
}
} }

View File

@ -20,18 +20,20 @@
package com.nextcloud.talk.newarch.features.conversationsList.di.module package com.nextcloud.talk.newarch.features.conversationsList.di.module
import android.app.Application
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
import com.nextcloud.talk.newarch.di.module.createApiErrorHandler import com.nextcloud.talk.newarch.di.module.createApiErrorHandler
import com.nextcloud.talk.newarch.domain.repository.NextcloudTalkRepository import com.nextcloud.talk.newarch.domain.repository.NextcloudTalkRepository
import com.nextcloud.talk.newarch.domain.usecases.GetConversationsUseCase import com.nextcloud.talk.newarch.domain.usecases.GetConversationsUseCase
import com.nextcloud.talk.newarch.features.conversationsList.ConversationListViewModelFactory import com.nextcloud.talk.newarch.features.conversationsList.ConversationListViewModelFactory
import com.nextcloud.talk.utils.database.user.UserUtils import com.nextcloud.talk.utils.database.user.UserUtils
import org.koin.android.ext.koin.androidApplication
import org.koin.dsl.module import org.koin.dsl.module
val ConversationsListModule = module { val ConversationsListModule = module {
single { createGetConversationsUseCase(get(), createApiErrorHandler()) } single { createGetConversationsUseCase(get(), createApiErrorHandler()) }
//viewModel { ConversationsListViewModel(get(), get()) } //viewModel { ConversationsListViewModel(get(), get()) }
factory { createConversationListViewModelFactory(get(), get()) } factory { createConversationListViewModelFactory(androidApplication(), get(), get()) }
} }
fun createGetConversationsUseCase( fun createGetConversationsUseCase(
@ -41,7 +43,11 @@ fun createGetConversationsUseCase(
return GetConversationsUseCase(nextcloudTalkRepository, apiErrorHandler) return GetConversationsUseCase(nextcloudTalkRepository, apiErrorHandler)
} }
fun createConversationListViewModelFactory(conversationsUseCase: GetConversationsUseCase, fun createConversationListViewModelFactory(
userUtils: UserUtils): ConversationListViewModelFactory { application: Application,
return ConversationListViewModelFactory(conversationsUseCase, userUtils) conversationsUseCase:
GetConversationsUseCase,
userUtils: UserUtils
): ConversationListViewModelFactory {
return ConversationListViewModelFactory(application, conversationsUseCase, userUtils)
} }

View File

@ -22,7 +22,6 @@
package com.nextcloud.talk.newarch.features.search package com.nextcloud.talk.newarch.features.search
import android.widget.SearchView
import androidx.appcompat.widget.SearchView.OnQueryTextListener import androidx.appcompat.widget.SearchView.OnQueryTextListener
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope import androidx.lifecycle.coroutineScope

View File

@ -26,20 +26,22 @@ import android.view.ViewGroup
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import butterknife.ButterKnife import butterknife.ButterKnife
import com.bluelinelabs.conductor.archlifecycle.ControllerLifecycleOwner import com.bluelinelabs.conductor.archlifecycle.ControllerLifecycleOwner
import com.nextcloud.talk.controllers.base.BaseController import com.nextcloud.talk.controllers.base.BaseController
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.extensions.LayoutContainer
abstract class BaseView : BaseController(), LifecycleOwner, ViewModelStoreOwner { abstract class BaseView : BaseController(), LifecycleOwner, ViewModelStoreOwner {
private val viewModelStore = ViewModelStore() private val viewModelStore = ViewModelStore()
private val lifecycleOwner = ControllerLifecycleOwner(this) private val lifecycleOwner = ControllerLifecycleOwner(this)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View { override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup
): View {
val view = inflater.inflate(getLayoutId(), container, false) val view = inflater.inflate(getLayoutId(), container, false)
unbinder = ButterKnife.bind(this, view) unbinder = ButterKnife.bind(this, view)
onViewBound(view) onViewBound(view)

View File

@ -20,16 +20,21 @@
package com.nextcloud.talk.newarch.conversationsList.mvp package com.nextcloud.talk.newarch.conversationsList.mvp
import androidx.lifecycle.ViewModel import android.app.Application
import android.content.Context
import androidx.lifecycle.AndroidViewModel
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
abstract class BaseViewModel<V : BaseView> : ViewModel() { abstract class BaseViewModel<V : BaseView>(application: Application) : AndroidViewModel(
application
) {
protected val disposables: CompositeDisposable = CompositeDisposable() protected val disposables: CompositeDisposable = CompositeDisposable()
protected val context: Context = getApplication<Application>().applicationContext
val backgroundAndUIScope = CoroutineScope( val backgroundAndUIScope = CoroutineScope(
Job() + Dispatchers.Main Job() + Dispatchers.Main