diff --git a/app/src/main/kotlin/com/cyder/android/syncpod/util/CustomBinder.kt b/app/src/main/kotlin/com/cyder/android/syncpod/util/CustomBinder.kt index 75b74192..6967eb52 100644 --- a/app/src/main/kotlin/com/cyder/android/syncpod/util/CustomBinder.kt +++ b/app/src/main/kotlin/com/cyder/android/syncpod/util/CustomBinder.kt @@ -1,6 +1,8 @@ package com.cyder.android.syncpod.util import android.databinding.BindingAdapter +import android.databinding.InverseBindingAdapter +import android.databinding.InverseBindingListener import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.support.v7.widget.SwitchCompat @@ -39,10 +41,11 @@ fun TextView.setLinksNavigable(flag: Boolean) { @BindingAdapter("onEnterClick") fun EditText.setKeyboardClick(listener: TextView.OnEditorActionListener) = setOnEditorActionListener(listener) -@BindingAdapter(value = ["onScrolled", "onScrollStateChanged"], requireAll = false) +@BindingAdapter(value = ["onScrolled", "onScrollStateChanged", "scrollAttrChanged"], requireAll = false) fun RecyclerView.setOnScrollChangedListeners( onScrolled: OnScrolledListener?, - onScrollStateChanged: OnScrollStateChangedListener? + onScrollStateChanged: OnScrollStateChangedListener?, + scrollAttrChanged: InverseBindingListener? ) { val OFFSET = 5 val listener = object : RecyclerView.OnScrollListener() { @@ -57,6 +60,7 @@ fun RecyclerView.setOnScrollChangedListeners( val nowHeadPos = layoutManager.findFirstVisibleItemPosition() val lastPos = layoutManager.findLastCompletelyVisibleItemPosition() onScrolled?.onScrolled(totalCount <= childCount + nowHeadPos + OFFSET) + scrollAttrChanged?.onChange() } } @@ -71,6 +75,21 @@ interface OnScrollStateChangedListener { fun onScrollStateChanged(recycler: RecyclerView, newState: Int) } +@BindingAdapter("scrollToEnd") +fun RecyclerView.setScrollToEnd(flag: Boolean) { + if (flag && !isScrollToEnd()) { + smoothScrollToPosition(adapter.itemCount) + } +} + +@InverseBindingAdapter(attribute = "scrollToEnd", event = "scrollAttrChanged") +fun RecyclerView.isScrollToEnd(): Boolean { + val manager = layoutManager as LinearLayoutManager + val lastVisiblePosition = manager.findLastVisibleItemPosition() + val lastListPosition = adapter.itemCount - 1 + return lastListPosition == lastVisiblePosition +} + @BindingAdapter(value = ["animatedVisibility", "originalHeight", "animationDuration"]) fun View.setAnimatedVisibility( visibility: Int, diff --git a/app/src/main/kotlin/com/cyder/android/syncpod/view/fragment/ChatFragment.kt b/app/src/main/kotlin/com/cyder/android/syncpod/view/fragment/ChatFragment.kt index 4ccded41..31beeb73 100644 --- a/app/src/main/kotlin/com/cyder/android/syncpod/view/fragment/ChatFragment.kt +++ b/app/src/main/kotlin/com/cyder/android/syncpod/view/fragment/ChatFragment.kt @@ -44,8 +44,6 @@ class ChatFragment : BaseFragment() { val manager = LinearLayoutManager(activity) manager.stackFromEnd = true val adapter = ChatAdapter(viewModel.chatViewModels) - val dataObserver = AutoScrollDataObserver(manager, adapter) - adapter.registerAdapterDataObserver(dataObserver) binding.chatList.adapter = adapter binding.chatList.layoutManager = manager binding.chatList.addItemDecoration(DividerItemDecoration(binding.chatList.context, manager.orientation)) @@ -61,20 +59,6 @@ class ChatFragment : BaseFragment() { } } - inner class AutoScrollDataObserver( - private val manager: LinearLayoutManager, - private val adapter: ChatAdapter - ) : RecyclerView.AdapterDataObserver() { - override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { - super.onItemRangeInserted(positionStart, itemCount) - val lastVisiblePosition = manager.findLastVisibleItemPosition() - val lastListPosition = adapter.itemCount - 1 - if (lastListPosition - 1 == lastVisiblePosition) { - binding.chatList.smoothScrollToPosition(lastListPosition + 1) - } - } - } - companion object { fun createInstance() = ChatFragment() } diff --git a/app/src/main/kotlin/com/cyder/android/syncpod/viewmodel/ChatFragmentViewModel.kt b/app/src/main/kotlin/com/cyder/android/syncpod/viewmodel/ChatFragmentViewModel.kt index 0d793822..4542c445 100644 --- a/app/src/main/kotlin/com/cyder/android/syncpod/viewmodel/ChatFragmentViewModel.kt +++ b/app/src/main/kotlin/com/cyder/android/syncpod/viewmodel/ChatFragmentViewModel.kt @@ -1,6 +1,7 @@ package com.cyder.android.syncpod.viewmodel import android.databinding.ObservableArrayList +import android.databinding.ObservableBoolean import android.databinding.ObservableField import android.databinding.ObservableList import com.cyder.android.syncpod.model.Chat @@ -22,6 +23,7 @@ class ChatFragmentViewModel @Inject constructor( private val repository: ChatRepository ) : FragmentViewModel() { var chatViewModels: ObservableList = ObservableArrayList() + var scrolledToEnd = ObservableBoolean() private val onPauseSubject = PublishSubject.create() override fun onStart() { @@ -45,7 +47,7 @@ class ChatFragmentViewModel @Inject constructor( ChatViewModel(ObservableField(it)) } .subscribe { - chatViewModels.add(it) + addChat(it) } } @@ -60,6 +62,15 @@ class ChatFragmentViewModel @Inject constructor( return chats.map { ChatViewModel(ObservableField(it)) } } + private fun addChat(chatViewModel: ChatViewModel) { + val isScrolledToEnd = scrolledToEnd.get() + scrolledToEnd.set(false) + chatViewModels.add(chatViewModel) + if (isScrolledToEnd) { + scrolledToEnd.set(true) + } + } + companion object { val INVOCATION = Unit } diff --git a/app/src/main/res/layout/fragment_chat.xml b/app/src/main/res/layout/fragment_chat.xml index 7c9fc00c..89467a87 100644 --- a/app/src/main/res/layout/fragment_chat.xml +++ b/app/src/main/res/layout/fragment_chat.xml @@ -1,5 +1,6 @@ - + @@ -15,6 +16,7 @@ + android:layout_height="match_parent" + app:scrollToEnd="@={viewModel.scrolledToEnd}" /> \ No newline at end of file