From 2228dc2bc666e97b987f3973e0d737bb172f893d Mon Sep 17 00:00:00 2001 From: Moez Bhatti Date: Tue, 27 Mar 2018 18:43:57 -0400 Subject: [PATCH] Don't keep references to conversations and archivedConversations realmResults in MainViewModel --- .../ConversationItemTouchCallback.kt | 4 +- .../conversations/ConversationsAdapter.kt | 17 +++++++ .../main/java/feature/main/MainActivity.kt | 10 ++-- .../src/main/java/feature/main/MainState.kt | 5 +- .../src/main/java/feature/main/MainView.kt | 4 +- .../main/java/feature/main/MainViewModel.kt | 51 ++++--------------- .../src/main/res/layout/main_activity.xml | 2 +- 7 files changed, 39 insertions(+), 54 deletions(-) diff --git a/presentation/src/main/java/feature/conversations/ConversationItemTouchCallback.kt b/presentation/src/main/java/feature/conversations/ConversationItemTouchCallback.kt index 364375c0..7de68c78 100644 --- a/presentation/src/main/java/feature/conversations/ConversationItemTouchCallback.kt +++ b/presentation/src/main/java/feature/conversations/ConversationItemTouchCallback.kt @@ -26,14 +26,14 @@ import javax.inject.Inject class ConversationItemTouchCallback @Inject constructor() : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { - val swipes: Subject = PublishSubject.create() + val swipes: Subject = PublishSubject.create() override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?, target: RecyclerView.ViewHolder?): Boolean { return false } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - swipes.onNext(viewHolder.adapterPosition) + swipes.onNext(viewHolder.itemId) } } \ No newline at end of file diff --git a/presentation/src/main/java/feature/conversations/ConversationsAdapter.kt b/presentation/src/main/java/feature/conversations/ConversationsAdapter.kt index 747f08d4..95970855 100644 --- a/presentation/src/main/java/feature/conversations/ConversationsAdapter.kt +++ b/presentation/src/main/java/feature/conversations/ConversationsAdapter.kt @@ -49,6 +49,11 @@ class ConversationsAdapter @Inject constructor( val longClicks: Subject = PublishSubject.create() private val disposables = CompositeDisposable() + private var attachedRecyclerViews = 0 + + init { + setHasStableIds(true) + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QkViewHolder { val layoutRes = when (viewType) { @@ -67,8 +72,16 @@ class ConversationsAdapter @Inject constructor( return QkViewHolder(view) } + fun isAttachedToRecyclerView() = attachedRecyclerViews > 0 + + override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { + super.onAttachedToRecyclerView(recyclerView) + attachedRecyclerViews++ + } + override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { super.onDetachedFromRecyclerView(recyclerView) + attachedRecyclerViews-- disposables.clear() } @@ -88,6 +101,10 @@ class ConversationsAdapter @Inject constructor( view.snippet.text = if (message.isMe()) "You: ${message.getSummary()}" else message.getSummary() } + override fun getItemId(index: Int): Long { + return getItem(index)!!.conversation!!.id + } + override fun getItemViewType(position: Int): Int { return if (getItem(position)!!.read) 0 else 1 } diff --git a/presentation/src/main/java/feature/main/MainActivity.kt b/presentation/src/main/java/feature/main/MainActivity.kt index b80f0f1a..92ecbfe4 100644 --- a/presentation/src/main/java/feature/main/MainActivity.kt +++ b/presentation/src/main/java/feature/main/MainActivity.kt @@ -31,6 +31,7 @@ import android.support.v7.widget.helper.ItemTouchHelper import android.view.Gravity import android.view.Menu import android.view.MenuItem +import android.view.View import com.jakewharton.rxbinding2.support.v4.widget.drawerOpen import com.jakewharton.rxbinding2.view.clicks import com.jakewharton.rxbinding2.widget.textChanges @@ -181,6 +182,12 @@ class MainActivity : QkThemedActivity(), MainView { override fun onItemRangeChanged(positionStart: Int, itemCount: Int) { onItemRangeInserted(positionStart, itemCount) } + + override fun onChanged() { + if (conversationsAdapter.isAttachedToRecyclerView()) { + empty.setVisible(conversationsAdapter.itemCount == 0, View.INVISIBLE) + } + } }) } @@ -203,7 +210,6 @@ class MainActivity : QkThemedActivity(), MainView { itemTouchHelper.attachToRecyclerView(recyclerView) menuItemAdapter.data = state.page.menu empty.setText(R.string.inbox_empty_text) - empty.setVisible(state.page.empty && !state.syncing) compose.setVisible(true) } @@ -214,7 +220,6 @@ class MainActivity : QkThemedActivity(), MainView { itemTouchHelper.attachToRecyclerView(null) menuItemAdapter.data = state.page.menu empty.setText(R.string.archived_empty_text) - empty.setVisible(state.page.empty && !state.syncing) compose.setVisible(true) } @@ -224,7 +229,6 @@ class MainActivity : QkThemedActivity(), MainView { itemTouchHelper.attachToRecyclerView(null) menuItemAdapter.data = ArrayList() empty.setText(R.string.scheduled_empty_text) - empty.setVisible(state.page.empty && !state.syncing) compose.setVisible(false) } } diff --git a/presentation/src/main/java/feature/main/MainState.kt b/presentation/src/main/java/feature/main/MainState.kt index 210664ed..bffa1d2b 100644 --- a/presentation/src/main/java/feature/main/MainState.kt +++ b/presentation/src/main/java/feature/main/MainState.kt @@ -33,15 +33,12 @@ sealed class MainPage data class Inbox( val showClearButton: Boolean = false, val data: RealmResults? = null, - val empty: Boolean = false, val menu: List = ArrayList(), val showArchivedSnackbar: Boolean = false) : MainPage() data class Archived( val data: RealmResults? = null, - val empty: Boolean = false, val menu: List = ArrayList()) : MainPage() data class Scheduled( - val data: Any? = null, - val empty: Boolean = false) : MainPage() \ No newline at end of file + val data: Any? = null) : MainPage() \ No newline at end of file diff --git a/presentation/src/main/java/feature/main/MainView.kt b/presentation/src/main/java/feature/main/MainView.kt index 565140ed..0c2598c8 100644 --- a/presentation/src/main/java/feature/main/MainView.kt +++ b/presentation/src/main/java/feature/main/MainView.kt @@ -18,8 +18,8 @@ */ package feature.main -import io.reactivex.Observable import common.base.QkView +import io.reactivex.Observable interface MainView : QkView { @@ -32,7 +32,7 @@ interface MainView : QkView { val conversationLongClickIntent: Observable val conversationMenuItemIntent: Observable val confirmDeleteIntent: Observable - val swipeConversationIntent: Observable + val swipeConversationIntent: Observable val undoSwipeConversationIntent: Observable fun clearSearch() diff --git a/presentation/src/main/java/feature/main/MainViewModel.kt b/presentation/src/main/java/feature/main/MainViewModel.kt index 5c0c198f..d88c74fb 100644 --- a/presentation/src/main/java/feature/main/MainViewModel.kt +++ b/presentation/src/main/java/feature/main/MainViewModel.kt @@ -44,9 +44,6 @@ import io.realm.Realm import model.SyncLog import repository.MessageRepository import util.Preferences -import util.extensions.asObservable -import util.extensions.mapNotNull -import util.extensions.toFlowable import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -64,30 +61,6 @@ class MainViewModel : QkViewModel(MainState()) { @Inject lateinit var partialSync: PartialSync @Inject lateinit var prefs: Preferences - private val conversations by lazy { - messageRepo.getConversations().also { - it.asFlowable() - .withLatestFrom(state.toFlowable(), { conversations, state -> - (state.page as? Inbox)?.let { page -> - newState { it.copy(page = page.copy(empty = conversations.isEmpty())) } - } - conversations - }) - } - } - - private val archivedConversations by lazy { - messageRepo.getConversations(true).also { - it.asFlowable() - .withLatestFrom(state.toFlowable(), { conversations, state -> - (state.page as? Archived)?.let { page -> - newState { it.copy(page = page.copy(empty = conversations.isEmpty())) } - } - conversations - }) - } - } - private val menuArchive by lazy { MenuItem(context.getString(R.string.menu_archive), 0) } private val menuUnarchive by lazy { MenuItem(context.getString(R.string.menu_unarchive), 1) } private val menuDelete by lazy { MenuItem(context.getString(R.string.menu_delete), 2) } @@ -113,7 +86,7 @@ class MainViewModel : QkViewModel(MainState()) { .distinctUntilChanged() .subscribe { syncing -> newState { it.copy(syncing = syncing) } } - newState { it.copy(page = Inbox(data = conversations)) } + newState { it.copy(page = Inbox(data = messageRepo.getConversations())) } // Migrate the preferences from 2.7.3 if necessary migratePreferences.execute(Unit) @@ -141,13 +114,11 @@ class MainViewModel : QkViewModel(MainState()) { .debounce(200, TimeUnit.MILLISECONDS) .withLatestFrom(state, { query, state -> if (state.page is Inbox) { - val conversations = when { - query.isEmpty() -> conversations - else -> conversations.filter { conversationFilter.filter(it, query) } - } + /*val conversations = messageRepo.getConversationsSnapshot() + .filter { conversationFilter.filter(it, query) } - //val page = state.page.copy(showClearButton = query.isNotEmpty(), data = conversations) - //newState { it.copy(page = page) } + val page = state.page.copy(showClearButton = query.isNotEmpty(), data = conversations) + newState { it.copy(page = page) }*/ } }) .autoDisposable(view.scope()) @@ -173,8 +144,8 @@ class MainViewModel : QkViewModel(MainState()) { .distinctUntilChanged() .doOnNext { when (it) { - DrawerItem.INBOX -> newState { it.copy(page = Inbox(data = conversations)) } - DrawerItem.ARCHIVED -> newState { it.copy(page = Archived(archivedConversations)) } + DrawerItem.INBOX -> newState { it.copy(page = Inbox(data = messageRepo.getConversations())) } + DrawerItem.ARCHIVED -> newState { it.copy(page = Archived(messageRepo.getConversations(true))) } DrawerItem.SCHEDULED -> newState { it.copy(page = Scheduled()) } else -> { } // Do nothing @@ -235,11 +206,7 @@ class MainViewModel : QkViewModel(MainState()) { .autoDisposable(view.scope()) .subscribe { threadId -> deleteConversation.execute(threadId) } - val swipedConversation = view.swipeConversationIntent - .withLatestFrom(conversations.asObservable(), { position, conversations -> conversations[position] }) - .mapNotNull { message -> message?.conversation?.id } - - swipedConversation + view.swipeConversationIntent .withLatestFrom(state, { threadId, state -> markArchived.execute(threadId) { if (state.page is Inbox) { @@ -261,7 +228,7 @@ class MainViewModel : QkViewModel(MainState()) { .subscribe() view.undoSwipeConversationIntent - .withLatestFrom(swipedConversation, { _, threadId -> threadId }) + .withLatestFrom(view.swipeConversationIntent, { _, threadId -> threadId }) .autoDisposable(view.scope()) .subscribe { threadId -> markUnarchived.execute(threadId) } } diff --git a/presentation/src/main/res/layout/main_activity.xml b/presentation/src/main/res/layout/main_activity.xml index 6a16a5ed..574a95cb 100644 --- a/presentation/src/main/res/layout/main_activity.xml +++ b/presentation/src/main/res/layout/main_activity.xml @@ -96,7 +96,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbar" tools:text="Your conversations will appear here" - tools:visibility="gone" /> + tools:visibility="invisible" />