Merge pull request #1479 from vector-im/feature/memory_leaks
Feature/memory leaks
This commit is contained in:
commit
ade1f1b911
@ -396,6 +396,9 @@ dependencies {
|
|||||||
// Plant Timber tree for test
|
// Plant Timber tree for test
|
||||||
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
|
||||||
|
|
||||||
|
// Activate when you want to check for leaks, from time to time.
|
||||||
|
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test:core:1.2.0'
|
androidTestImplementation 'androidx.test:core:1.2.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||||
|
@ -25,12 +25,21 @@ import java.util.concurrent.atomic.AtomicReference
|
|||||||
|
|
||||||
private const val LAYOUT_MANAGER_STATE = "LAYOUT_MANAGER_STATE"
|
private const val LAYOUT_MANAGER_STATE = "LAYOUT_MANAGER_STATE"
|
||||||
|
|
||||||
class LayoutManagerStateRestorer(private val layoutManager: RecyclerView.LayoutManager) : Restorable, DefaultListUpdateCallback {
|
class LayoutManagerStateRestorer(layoutManager: RecyclerView.LayoutManager) : Restorable, DefaultListUpdateCallback {
|
||||||
|
|
||||||
|
private var layoutManager: RecyclerView.LayoutManager? = null
|
||||||
private var layoutManagerState = AtomicReference<Parcelable?>()
|
private var layoutManagerState = AtomicReference<Parcelable?>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.layoutManager = layoutManager
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
layoutManager = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
val layoutManagerState = layoutManager.onSaveInstanceState()
|
val layoutManagerState = layoutManager?.onSaveInstanceState()
|
||||||
outState.putParcelable(LAYOUT_MANAGER_STATE, layoutManagerState)
|
outState.putParcelable(LAYOUT_MANAGER_STATE, layoutManagerState)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +50,7 @@ class LayoutManagerStateRestorer(private val layoutManager: RecyclerView.LayoutM
|
|||||||
|
|
||||||
override fun onInserted(position: Int, count: Int) {
|
override fun onInserted(position: Int, count: Int) {
|
||||||
layoutManagerState.getAndSet(null)?.also {
|
layoutManagerState.getAndSet(null)?.also {
|
||||||
layoutManager.onRestoreInstanceState(it)
|
layoutManager?.onRestoreInstanceState(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.riotx.features.autocomplete
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.database.DataSetObserver
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.annotation.CallSuper
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.otaliastudios.autocomplete.AutocompletePresenter
|
||||||
|
|
||||||
|
abstract class RecyclerViewPresenter<T>(context: Context?) : AutocompletePresenter<T>(context) {
|
||||||
|
|
||||||
|
private var recyclerView: RecyclerView? = null
|
||||||
|
private var clicks: ClickProvider<T>? = null
|
||||||
|
private var observer: RecyclerView.AdapterDataObserver? = null
|
||||||
|
|
||||||
|
override fun registerClickProvider(provider: ClickProvider<T>) {
|
||||||
|
clicks = provider
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun registerDataSetObserver(observer: DataSetObserver) {
|
||||||
|
this.observer = Observer(observer)
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
override fun getView(): ViewGroup {
|
||||||
|
val adapter = instantiateAdapter()
|
||||||
|
observer?.also {
|
||||||
|
adapter.registerAdapterDataObserver(it)
|
||||||
|
}
|
||||||
|
return RecyclerView(context).apply {
|
||||||
|
this.adapter = adapter
|
||||||
|
this.layoutManager = instantiateLayoutManager()
|
||||||
|
this.itemAnimator = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewShown() {}
|
||||||
|
@CallSuper
|
||||||
|
override fun onViewHidden() {
|
||||||
|
observer?.also {
|
||||||
|
recyclerView?.adapter?.unregisterAdapterDataObserver(it)
|
||||||
|
}
|
||||||
|
recyclerView = null
|
||||||
|
observer = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch click event to Autocomplete.Callback.
|
||||||
|
* Should be called when items are clicked.
|
||||||
|
*
|
||||||
|
* @param item the clicked item.
|
||||||
|
*/
|
||||||
|
protected fun dispatchClick(item: T) {
|
||||||
|
if (clicks != null) clicks?.click(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that the popup should recompute its dimensions based on a recent change in
|
||||||
|
* the view being displayed.
|
||||||
|
*
|
||||||
|
* This is already managed internally for [RecyclerView] events.
|
||||||
|
* Only use it for changes in other views that you have added to the popup,
|
||||||
|
* and only if one of the dimensions for the popup is WRAP_CONTENT .
|
||||||
|
*/
|
||||||
|
protected fun dispatchLayoutChange() {
|
||||||
|
if (observer != null) observer!!.onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide an adapter for the recycler.
|
||||||
|
* This should be a fresh instance every time this is called.
|
||||||
|
*
|
||||||
|
* @return a new adapter.
|
||||||
|
*/
|
||||||
|
protected abstract fun instantiateAdapter(): RecyclerView.Adapter<*>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a layout manager for the recycler.
|
||||||
|
* This should be a fresh instance every time this is called.
|
||||||
|
* Defaults to a vertical LinearLayoutManager, which is guaranteed to work well.
|
||||||
|
*
|
||||||
|
* @return a new layout manager.
|
||||||
|
*/
|
||||||
|
protected fun instantiateLayoutManager(): RecyclerView.LayoutManager {
|
||||||
|
return LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Observer internal constructor(private val root: DataSetObserver) : RecyclerView.AdapterDataObserver() {
|
||||||
|
override fun onChanged() {
|
||||||
|
root.onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
|
||||||
|
root.onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
|
||||||
|
root.onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||||
|
root.onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||||
|
root.onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,8 +18,8 @@ package im.vector.riotx.features.autocomplete.command
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.otaliastudios.autocomplete.RecyclerViewPresenter
|
|
||||||
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
||||||
|
import im.vector.riotx.features.autocomplete.RecyclerViewPresenter
|
||||||
import im.vector.riotx.features.command.Command
|
import im.vector.riotx.features.command.Command
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -32,8 +32,6 @@ class AutocompleteCommandPresenter @Inject constructor(context: Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
||||||
// Also remove animation
|
|
||||||
recyclerView?.itemAnimator = null
|
|
||||||
return controller.adapter
|
return controller.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,4 +49,8 @@ class AutocompleteCommandPresenter @Inject constructor(context: Context,
|
|||||||
}
|
}
|
||||||
controller.setData(data)
|
controller.setData(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
controller.listener = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ package im.vector.riotx.features.autocomplete.emoji
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.otaliastudios.autocomplete.RecyclerViewPresenter
|
|
||||||
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
||||||
|
import im.vector.riotx.features.autocomplete.RecyclerViewPresenter
|
||||||
import im.vector.riotx.features.reactions.data.EmojiDataSource
|
import im.vector.riotx.features.reactions.data.EmojiDataSource
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -32,9 +32,11 @@ class AutocompleteEmojiPresenter @Inject constructor(context: Context,
|
|||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
controller.listener = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
||||||
// Also remove animation
|
|
||||||
recyclerView?.itemAnimator = null
|
|
||||||
return controller.adapter
|
return controller.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,12 +18,12 @@ package im.vector.riotx.features.autocomplete.group
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.otaliastudios.autocomplete.RecyclerViewPresenter
|
|
||||||
import im.vector.matrix.android.api.query.QueryStringValue
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.group.groupSummaryQueryParams
|
import im.vector.matrix.android.api.session.group.groupSummaryQueryParams
|
||||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||||
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
||||||
|
import im.vector.riotx.features.autocomplete.RecyclerViewPresenter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AutocompleteGroupPresenter @Inject constructor(context: Context,
|
class AutocompleteGroupPresenter @Inject constructor(context: Context,
|
||||||
@ -35,9 +35,11 @@ class AutocompleteGroupPresenter @Inject constructor(context: Context,
|
|||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
controller.listener = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
||||||
// Also remove animation
|
|
||||||
recyclerView?.itemAnimator = null
|
|
||||||
return controller.adapter
|
return controller.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ package im.vector.riotx.features.autocomplete.member
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.otaliastudios.autocomplete.RecyclerViewPresenter
|
|
||||||
import com.squareup.inject.assisted.Assisted
|
import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.matrix.android.api.query.QueryStringValue
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
@ -27,6 +26,7 @@ import im.vector.matrix.android.api.session.room.members.roomMemberQueryParams
|
|||||||
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.RoomMemberSummary
|
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
|
||||||
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
||||||
|
import im.vector.riotx.features.autocomplete.RecyclerViewPresenter
|
||||||
|
|
||||||
class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
|
class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
|
||||||
@Assisted val roomId: String,
|
@Assisted val roomId: String,
|
||||||
@ -40,14 +40,16 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
|
|||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
controller.listener = null
|
||||||
|
}
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(roomId: String): AutocompleteMemberPresenter
|
fun create(roomId: String): AutocompleteMemberPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
||||||
// Also remove animation
|
|
||||||
recyclerView?.itemAnimator = null
|
|
||||||
return controller.adapter
|
return controller.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,12 +18,12 @@ package im.vector.riotx.features.autocomplete.room
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.otaliastudios.autocomplete.RecyclerViewPresenter
|
|
||||||
import im.vector.matrix.android.api.query.QueryStringValue
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.session.room.roomSummaryQueryParams
|
import im.vector.matrix.android.api.session.room.roomSummaryQueryParams
|
||||||
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
import im.vector.riotx.features.autocomplete.AutocompleteClickListener
|
||||||
|
import im.vector.riotx.features.autocomplete.RecyclerViewPresenter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AutocompleteRoomPresenter @Inject constructor(context: Context,
|
class AutocompleteRoomPresenter @Inject constructor(context: Context,
|
||||||
@ -36,8 +36,6 @@ class AutocompleteRoomPresenter @Inject constructor(context: Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
override fun instantiateAdapter(): RecyclerView.Adapter<*> {
|
||||||
// Also remove animation
|
|
||||||
recyclerView?.itemAnimator = null
|
|
||||||
return controller.adapter
|
return controller.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,4 +56,8 @@ class AutocompleteRoomPresenter @Inject constructor(context: Context,
|
|||||||
.sortedBy { it.displayName }
|
.sortedBy { it.displayName }
|
||||||
controller.setData(rooms.toList())
|
controller.setData(rooms.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
controller.listener = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory {
|
||||||
|
|
||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||||
|
|
||||||
@ -66,6 +66,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||||
@Inject lateinit var popupAlertManager: PopupAlertManager
|
@Inject lateinit var popupAlertManager: PopupAlertManager
|
||||||
@Inject lateinit var shortcutsHandler: ShortcutsHandler
|
@Inject lateinit var shortcutsHandler: ShortcutsHandler
|
||||||
|
@Inject lateinit var unknownDeviceViewModelFactory: UnknownDeviceDetectorSharedViewModel.Factory
|
||||||
|
|
||||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
||||||
override fun onDrawerStateChanged(newState: Int) {
|
override fun onDrawerStateChanged(newState: Int) {
|
||||||
@ -79,6 +80,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
injector.inject(this)
|
injector.inject(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel {
|
||||||
|
return unknownDeviceViewModelFactory.create(initialState)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
||||||
|
@ -16,12 +16,16 @@
|
|||||||
|
|
||||||
package im.vector.riotx.features.home
|
package im.vector.riotx.features.home
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.ActivityViewModelContext
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import com.squareup.inject.assisted.Assisted
|
||||||
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.matrix.android.api.NoOpMatrixCallback
|
import im.vector.matrix.android.api.NoOpMatrixCallback
|
||||||
import im.vector.matrix.android.api.extensions.orFalse
|
import im.vector.matrix.android.api.extensions.orFalse
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
@ -32,7 +36,6 @@ import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
|
|||||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.store.PrivateKeysInfo
|
import im.vector.matrix.android.internal.crypto.store.PrivateKeysInfo
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotx.core.di.HasScreenInjector
|
|
||||||
import im.vector.riotx.core.platform.EmptyViewEvents
|
import im.vector.riotx.core.platform.EmptyViewEvents
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
@ -53,16 +56,32 @@ data class DeviceDetectionInfo(
|
|||||||
val currentSessionTrust: Boolean
|
val currentSessionTrust: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
class UnknownDeviceDetectorSharedViewModel(
|
class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted initialState: UnknownDevicesState,
|
||||||
session: Session,
|
session: Session,
|
||||||
private val vectorPreferences: VectorPreferences,
|
private val vectorPreferences: VectorPreferences)
|
||||||
initialState: UnknownDevicesState)
|
|
||||||
: VectorViewModel<UnknownDevicesState, UnknownDeviceDetectorSharedViewModel.Action, EmptyViewEvents>(initialState) {
|
: VectorViewModel<UnknownDevicesState, UnknownDeviceDetectorSharedViewModel.Action, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
sealed class Action : VectorViewModelAction {
|
sealed class Action : VectorViewModelAction {
|
||||||
data class IgnoreDevice(val deviceIds: List<String>) : Action()
|
data class IgnoreDevice(val deviceIds: List<String>) : Action()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AssistedInject.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel? {
|
||||||
|
val factory = when (viewModelContext) {
|
||||||
|
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
||||||
|
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
||||||
|
}
|
||||||
|
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val ignoredDeviceList = ArrayList<String>()
|
private val ignoredDeviceList = ArrayList<String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -146,12 +165,4 @@ class UnknownDeviceDetectorSharedViewModel(
|
|||||||
vectorPreferences.storeUnknownDeviceDismissedList(ignoredDeviceList)
|
vectorPreferences.storeUnknownDeviceDismissedList(ignoredDeviceList)
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : MvRxViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> {
|
|
||||||
|
|
||||||
override fun create(viewModelContext: ViewModelContext, state: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel? {
|
|
||||||
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
|
|
||||||
return UnknownDeviceDetectorSharedViewModel(session, VectorPreferences(viewModelContext.activity()), state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import im.vector.matrix.android.api.util.toMatrixItem
|
|||||||
import im.vector.matrix.android.api.util.toRoomAliasMatrixItem
|
import im.vector.matrix.android.api.util.toRoomAliasMatrixItem
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.glide.GlideApp
|
import im.vector.riotx.core.glide.GlideApp
|
||||||
|
import im.vector.riotx.core.glide.GlideRequests
|
||||||
import im.vector.riotx.features.autocomplete.command.AutocompleteCommandPresenter
|
import im.vector.riotx.features.autocomplete.command.AutocompleteCommandPresenter
|
||||||
import im.vector.riotx.features.autocomplete.command.CommandAutocompletePolicy
|
import im.vector.riotx.features.autocomplete.command.CommandAutocompletePolicy
|
||||||
import im.vector.riotx.features.autocomplete.emoji.AutocompleteEmojiPresenter
|
import im.vector.riotx.features.autocomplete.emoji.AutocompleteEmojiPresenter
|
||||||
@ -56,12 +57,14 @@ class AutoCompleter @AssistedInject constructor(
|
|||||||
private val autocompleteEmojiPresenter: AutocompleteEmojiPresenter
|
private val autocompleteEmojiPresenter: AutocompleteEmojiPresenter
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private lateinit var autocompleteMemberPresenter: AutocompleteMemberPresenter
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(roomId: String): AutoCompleter
|
fun create(roomId: String): AutoCompleter
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var editText: EditText
|
private var editText: EditText? = null
|
||||||
|
|
||||||
fun enterSpecialMode() {
|
fun enterSpecialMode() {
|
||||||
commandAutocompletePolicy.enabled = false
|
commandAutocompletePolicy.enabled = false
|
||||||
@ -71,12 +74,11 @@ class AutoCompleter @AssistedInject constructor(
|
|||||||
commandAutocompletePolicy.enabled = true
|
commandAutocompletePolicy.enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private val glideRequests by lazy {
|
private lateinit var glideRequests: GlideRequests
|
||||||
GlideApp.with(editText)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setup(editText: EditText) {
|
fun setup(editText: EditText) {
|
||||||
this.editText = editText
|
this.editText = editText
|
||||||
|
glideRequests = GlideApp.with(editText)
|
||||||
val backgroundDrawable = ColorDrawable(ThemeUtils.getColor(editText.context, R.attr.riotx_background))
|
val backgroundDrawable = ColorDrawable(ThemeUtils.getColor(editText.context, R.attr.riotx_background))
|
||||||
setupCommands(backgroundDrawable, editText)
|
setupCommands(backgroundDrawable, editText)
|
||||||
setupMembers(backgroundDrawable, editText)
|
setupMembers(backgroundDrawable, editText)
|
||||||
@ -85,6 +87,15 @@ class AutoCompleter @AssistedInject constructor(
|
|||||||
setupRooms(backgroundDrawable, editText)
|
setupRooms(backgroundDrawable, editText)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
this.editText = null
|
||||||
|
autocompleteEmojiPresenter.clear()
|
||||||
|
autocompleteGroupPresenter.clear()
|
||||||
|
autocompleteRoomPresenter.clear()
|
||||||
|
autocompleteCommandPresenter.clear()
|
||||||
|
autocompleteMemberPresenter.clear()
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupCommands(backgroundDrawable: Drawable, editText: EditText) {
|
private fun setupCommands(backgroundDrawable: Drawable, editText: EditText) {
|
||||||
Autocomplete.on<Command>(editText)
|
Autocomplete.on<Command>(editText)
|
||||||
.with(commandAutocompletePolicy)
|
.with(commandAutocompletePolicy)
|
||||||
@ -107,7 +118,7 @@ class AutoCompleter @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupMembers(backgroundDrawable: ColorDrawable, editText: EditText) {
|
private fun setupMembers(backgroundDrawable: ColorDrawable, editText: EditText) {
|
||||||
val autocompleteMemberPresenter = autocompleteMemberPresenterFactory.create(roomId)
|
autocompleteMemberPresenter = autocompleteMemberPresenterFactory.create(roomId)
|
||||||
Autocomplete.on<RoomMemberSummary>(editText)
|
Autocomplete.on<RoomMemberSummary>(editText)
|
||||||
.with(CharPolicy('@', true))
|
.with(CharPolicy('@', true))
|
||||||
.with(autocompleteMemberPresenter)
|
.with(autocompleteMemberPresenter)
|
||||||
|
@ -372,6 +372,7 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
timelineEventController.callback = null
|
timelineEventController.callback = null
|
||||||
timelineEventController.removeModelBuildListener(modelBuildListener)
|
timelineEventController.removeModelBuildListener(modelBuildListener)
|
||||||
modelBuildListener = null
|
modelBuildListener = null
|
||||||
|
autoCompleter.clear()
|
||||||
debouncer.cancelAll()
|
debouncer.cancelAll()
|
||||||
recyclerView.cleanup()
|
recyclerView.cleanup()
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
||||||
private val roomListParams: RoomListParams by args()
|
private val roomListParams: RoomListParams by args()
|
||||||
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
|
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
|
||||||
|
private lateinit var stateRestorer: LayoutManagerStateRestorer
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_room_list
|
override fun getLayoutResId() = R.layout.fragment_room_list
|
||||||
|
|
||||||
@ -126,6 +127,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
modelBuildListener = null
|
modelBuildListener = null
|
||||||
roomListView.cleanup()
|
roomListView.cleanup()
|
||||||
roomController.listener = null
|
roomController.listener = null
|
||||||
|
stateRestorer.clear()
|
||||||
createChatFabMenu.listener = null
|
createChatFabMenu.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
@ -190,7 +192,7 @@ class RoomListFragment @Inject constructor(
|
|||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
val layoutManager = LinearLayoutManager(context)
|
val layoutManager = LinearLayoutManager(context)
|
||||||
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||||
roomListView.layoutManager = layoutManager
|
roomListView.layoutManager = layoutManager
|
||||||
roomListView.itemAnimator = RoomListAnimator()
|
roomListView.itemAnimator = RoomListAnimator()
|
||||||
roomListView.setRecycledViewPool(sharedViewPool)
|
roomListView.setRecycledViewPool(sharedViewPool)
|
||||||
|
@ -66,7 +66,7 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||||||
private val fragmentArgs: RoomMemberProfileArgs by args()
|
private val fragmentArgs: RoomMemberProfileArgs by args()
|
||||||
private val viewModel: RoomMemberProfileViewModel by fragmentViewModel()
|
private val viewModel: RoomMemberProfileViewModel by fragmentViewModel()
|
||||||
|
|
||||||
private lateinit var appBarStateChangeListener: AppBarStateChangeListener
|
private var appBarStateChangeListener: AppBarStateChangeListener? = null
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_matrix_profile
|
override fun getLayoutResId() = R.layout.fragment_matrix_profile
|
||||||
|
|
||||||
@ -156,6 +156,7 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
roomMemberProfileController.callback = null
|
roomMemberProfileController.callback = null
|
||||||
|
appBarStateChangeListener = null
|
||||||
matrixProfileRecyclerView.cleanup()
|
matrixProfileRecyclerView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ class RoomProfileFragment @Inject constructor(
|
|||||||
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
||||||
private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel()
|
private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel()
|
||||||
|
|
||||||
private lateinit var appBarStateChangeListener: AppBarStateChangeListener
|
private var appBarStateChangeListener: AppBarStateChangeListener? = null
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_matrix_profile
|
override fun getLayoutResId() = R.layout.fragment_matrix_profile
|
||||||
|
|
||||||
@ -147,6 +147,7 @@ class RoomProfileFragment @Inject constructor(
|
|||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
matrixProfileRecyclerView.cleanup()
|
matrixProfileRecyclerView.cleanup()
|
||||||
|
appBarStateChangeListener = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(roomProfileViewModel) { state ->
|
override fun invalidate() = withState(roomProfileViewModel) { state ->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user