Skip to content
Snippets Groups Projects
Commit f751b98a authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Improved message view

- fixed scroll behaviour
- use Paging’s BoundaryCallback for loadMore detection
parent 6a544bd8
No related branches found
No related tags found
No related merge requests found
...@@ -106,9 +106,9 @@ dependencies { ...@@ -106,9 +106,9 @@ dependencies {
implementation(appArch("lifecycle", "reactivestreams")) implementation(appArch("lifecycle", "reactivestreams"))
kapt(appArch("lifecycle", "compiler")) kapt(appArch("lifecycle", "compiler"))
implementation(appArch("persistence.room", "runtime", "1.0.0")) implementation(appArch("persistence.room", "runtime", "1.1.0-alpha2"))
implementation(appArch("persistence.room", "rxjava2", "1.0.0")) implementation(appArch("persistence.room", "rxjava2", "1.1.0-alpha2"))
kapt(appArch("persistence.room", "compiler", "1.0.0")) kapt(appArch("persistence.room", "compiler", "1.1.0-alpha2"))
implementation(appArch("paging", "runtime", version = "1.0.0-alpha5")) { implementation(appArch("paging", "runtime", version = "1.0.0-alpha5")) {
exclude(group = "junit", module = "junit") exclude(group = "junit", module = "junit")
......
package de.kuschku.quasseldroid_ng.persistence package de.kuschku.quasseldroid_ng.persistence
import android.arch.paging.LivePagedListProvider import android.arch.paging.DataSource
import android.arch.persistence.room.* import android.arch.persistence.room.*
import android.content.Context import android.content.Context
...@@ -32,7 +32,7 @@ abstract class AccountDatabase : RoomDatabase() { ...@@ -32,7 +32,7 @@ abstract class AccountDatabase : RoomDatabase() {
fun findById(id: Long): AccountDatabase.Account? fun findById(id: Long): AccountDatabase.Account?
@Query("SELECT * FROM account ORDER BY lastUsed DESC") @Query("SELECT * FROM account ORDER BY lastUsed DESC")
fun all(): LivePagedListProvider<Int, Account> fun all(): DataSource.Factory<Int, Account>
@Delete @Delete
fun delete(account: AccountDatabase.Account) fun delete(account: AccountDatabase.Account)
......
package de.kuschku.quasseldroid_ng.persistence package de.kuschku.quasseldroid_ng.persistence
import android.arch.paging.LivePagedListProvider import android.arch.paging.DataSource
import android.arch.persistence.room.* import android.arch.persistence.room.*
import android.content.Context import android.content.Context
import android.support.annotation.IntRange import android.support.annotation.IntRange
...@@ -60,8 +60,8 @@ abstract class QuasselDatabase : RoomDatabase() { ...@@ -60,8 +60,8 @@ abstract class QuasselDatabase : RoomDatabase() {
@Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC") @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC")
fun findByBufferId(bufferId: Int): List<DatabaseMessage> fun findByBufferId(bufferId: Int): List<DatabaseMessage>
@Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC") @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC")
fun findByBufferIdPaged(bufferId: Int): LivePagedListProvider<Int, DatabaseMessage> fun findByBufferIdPaged(bufferId: Int): DataSource.Factory<Int, DatabaseMessage>
@Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1") @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1")
fun findLastByBufferId(bufferId: Int): DatabaseMessage? fun findLastByBufferId(bufferId: Int): DatabaseMessage?
......
...@@ -21,10 +21,6 @@ class MessageAdapter(context: Context) : ...@@ -21,10 +21,6 @@ class MessageAdapter(context: Context) :
private val messageCache = LruCache<Int, FormattedMessage>(512) private val messageCache = LruCache<Int, FormattedMessage>(512)
init {
setHasStableIds(true)
}
override fun onBindViewHolder(holder: QuasselMessageViewHolder, position: Int) { override fun onBindViewHolder(holder: QuasselMessageViewHolder, position: Int) {
getItem(position)?.let { getItem(position)?.let {
messageRenderer.bind( messageRenderer.bind(
......
...@@ -3,6 +3,7 @@ package de.kuschku.quasseldroid_ng.ui.chat ...@@ -3,6 +3,7 @@ package de.kuschku.quasseldroid_ng.ui.chat
import android.arch.lifecycle.LiveData import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.Observer import android.arch.lifecycle.Observer
import android.arch.paging.LivePagedListBuilder
import android.arch.paging.PagedList import android.arch.paging.PagedList
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.FloatingActionButton import android.support.design.widget.FloatingActionButton
...@@ -14,13 +15,10 @@ import android.view.ViewGroup ...@@ -14,13 +15,10 @@ import android.view.ViewGroup
import butterknife.BindView import butterknife.BindView
import butterknife.ButterKnife import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.BufferId import de.kuschku.libquassel.protocol.BufferId
import de.kuschku.libquassel.session.Backend
import de.kuschku.libquassel.session.SessionManager
import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.R
import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
import de.kuschku.quasseldroid_ng.util.helper.invoke import de.kuschku.quasseldroid_ng.util.helper.invoke
import de.kuschku.quasseldroid_ng.util.helper.map
import de.kuschku.quasseldroid_ng.util.helper.switchMap import de.kuschku.quasseldroid_ng.util.helper.switchMap
import de.kuschku.quasseldroid_ng.util.helper.toggle import de.kuschku.quasseldroid_ng.util.helper.toggle
import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment
...@@ -39,37 +37,70 @@ class MessageListFragment : ServiceBoundFragment() { ...@@ -39,37 +37,70 @@ class MessageListFragment : ServiceBoundFragment() {
@BindView(R.id.scrollDown) @BindView(R.id.scrollDown)
lateinit var scrollDown: FloatingActionButton lateinit var scrollDown: FloatingActionButton
private val sessionManager: LiveData<SessionManager?> = backend.map(Backend::sessionManager)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
handler.onCreate() handler.onCreate()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setHasOptionsMenu(true) setHasOptionsMenu(true)
} }
private val boundaryCallback = object :
PagedList.BoundaryCallback<QuasselDatabase.DatabaseMessage>() {
override fun onItemAtFrontLoaded(itemAtFront: QuasselDatabase.DatabaseMessage)
= Unit
override fun onItemAtEndLoaded(itemAtEnd: QuasselDatabase.DatabaseMessage)
= loadMore()
}
override fun onCreateView(inflater: LayoutInflater, override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_messages, container, false) val view = inflater.inflate(R.layout.fragment_messages, container, false)
ButterKnife.bind(this, view) ButterKnife.bind(this, view)
val adapter = MessageAdapter(context!!)
messageList.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context)
linearLayoutManager.reverseLayout = true
messageList.layoutManager = linearLayoutManager
messageList.addOnScrollListener(
object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val canScrollDown = recyclerView.canScrollVertically(1)
val isScrollingDown = dy > 0
scrollDown.visibility = View.VISIBLE
scrollDown.toggle(canScrollDown && isScrollingDown)
}
}
)
database = QuasselDatabase.Creator.init(context!!.applicationContext) database = QuasselDatabase.Creator.init(context!!.applicationContext)
val data = buffer.switchMap { val data = buffer.switchMap {
database.message().findByBufferIdPaged(it).create( LivePagedListBuilder(database.message().findByBufferIdPaged(it), 20)
Int.MAX_VALUE, .setBoundaryCallback(boundaryCallback)
PagedList.Config.Builder() .setInitialLoadKey(null)
.setPageSize(50)
.setEnablePlaceholders(false)
.setPrefetchDistance(50)
.build() .build()
)
} }
val adapter = MessageAdapter(context!!)
data.observe( data.observe(
this, Observer { list -> this, Observer { list ->
val findFirstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition()
adapter.setList(list) adapter.setList(list)
if (findFirstVisibleItemPosition < 2) {
activity?.runOnUiThread {
messageList.smoothScrollToPosition(0)
}
handler.postDelayed(
{
activity?.runOnUiThread {
messageList.smoothScrollToPosition(0)
}
}, 16
)
}
} }
) )
...@@ -77,35 +108,22 @@ class MessageListFragment : ServiceBoundFragment() { ...@@ -77,35 +108,22 @@ class MessageListFragment : ServiceBoundFragment() {
this, Observer { this, Observer {
handler.post { handler.post {
// Try loading messages when switching to isEmpty buffer // Try loading messages when switching to isEmpty buffer
if (it != null && database.message().bufferSize(it) == 0) { if (it != null) {
if (database.message().bufferSize(it) == 0) {
loadMore() loadMore()
} }
activity?.runOnUiThread {
messageList.scrollToPosition(0)
} }
} }
)
var recyclerViewMeasuredHeight = 0
val scrollDownListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (!recyclerView.canScrollVertically(-1)) {
loadMore()
}
if (recyclerViewMeasuredHeight == 0)
recyclerViewMeasuredHeight = recyclerView.measuredHeight
val canScrollDown = recyclerView.canScrollVertically(1)
val isScrollingDown = dy > 0
val scrollOffsetFromBottom = recyclerView.computeVerticalScrollRange() - recyclerView.computeVerticalScrollOffset() - recyclerViewMeasuredHeight
val isMoreThanOneScreenFromBottom = scrollOffsetFromBottom > recyclerViewMeasuredHeight
val smartVisibility = scrollDown.visibility == View.VISIBLE || isMoreThanOneScreenFromBottom
scrollDown.toggle(canScrollDown && isScrollingDown && smartVisibility)
} }
} }
)
messageList.adapter = adapter scrollDown.hide()
messageList.layoutManager = LinearLayoutManager(context) scrollDown.setOnClickListener {
messageList.addOnScrollListener(scrollDownListener) messageList.scrollToPosition(0)
}
scrollDown.setOnClickListener { messageList.scrollToPosition(adapter.itemCount) }
return view return view
} }
......
...@@ -3,6 +3,7 @@ package de.kuschku.quasseldroid_ng.ui.setup.accounts ...@@ -3,6 +3,7 @@ package de.kuschku.quasseldroid_ng.ui.setup.accounts
import android.app.Application import android.app.Application
import android.arch.lifecycle.AndroidViewModel import android.arch.lifecycle.AndroidViewModel
import android.arch.lifecycle.LiveData import android.arch.lifecycle.LiveData
import android.arch.paging.LivePagedListBuilder
import android.arch.paging.PagedList import android.arch.paging.PagedList
import de.kuschku.quasseldroid_ng.persistence.AccountDatabase import de.kuschku.quasseldroid_ng.persistence.AccountDatabase
...@@ -10,11 +11,6 @@ class AccountViewModel(application: Application) : AndroidViewModel(application) ...@@ -10,11 +11,6 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
private val database: AccountDatabase = AccountDatabase.Creator.init( private val database: AccountDatabase = AccountDatabase.Creator.init(
getApplication() getApplication()
) )
val accounts: LiveData<PagedList<AccountDatabase.Account>> = database.accounts().all().create( val accounts: LiveData<PagedList<AccountDatabase.Account>>
0, = LivePagedListBuilder(database.accounts().all(), 20).build()
PagedList.Config.Builder()
.setPageSize(50)
.setPrefetchDistance(50)
.build()
)
} }
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
android:layout_marginEnd="12dp" android:layout_marginEnd="12dp"
android:layout_marginRight="12dp" android:layout_marginRight="12dp"
android:tint="@color/colorFillDark" android:tint="@color/colorFillDark"
android:visibility="gone"
app:backgroundTint="#8A808080" app:backgroundTint="#8A808080"
app:elevation="0dip" app:elevation="0dip"
app:fabSize="mini" app:fabSize="mini"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment