Some performance improvements
This commit is contained in:
parent
9dd1b457e3
commit
1e8b71e43b
@ -166,18 +166,17 @@ class MessageDetailFragment : Fragment() {
|
||||
return true
|
||||
}
|
||||
R.id.delete -> {
|
||||
Singleton.labeler.delete(item)
|
||||
if (isInTrash(item)) {
|
||||
messageRepo.remove(item)
|
||||
} else {
|
||||
item.labels.clear()
|
||||
item.addLabels(messageRepo.getLabels(Label.Type.TRASH))
|
||||
messageRepo.save(item)
|
||||
}
|
||||
activity.onBackPressed()
|
||||
return true
|
||||
}
|
||||
R.id.mark_unread -> {
|
||||
item.addLabels(messageRepo.getLabels(Label.Type.UNREAD))
|
||||
Singleton.labeler.markAsUnread(item)
|
||||
messageRepo.save(item)
|
||||
if (activity is MainActivity) {
|
||||
(activity as MainActivity).updateUnread()
|
||||
@ -188,7 +187,7 @@ class MessageDetailFragment : Fragment() {
|
||||
if (item.isUnread() && activity is MainActivity) {
|
||||
(activity as MainActivity).updateUnread()
|
||||
}
|
||||
item.labels.clear()
|
||||
Singleton.labeler.archive(item)
|
||||
messageRepo.save(item)
|
||||
return true
|
||||
}
|
||||
|
@ -17,11 +17,14 @@
|
||||
package ch.dissem.apps.abit
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.support.v7.widget.RecyclerView.OnScrollListener
|
||||
import android.view.*
|
||||
import android.widget.Toast
|
||||
import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_BROADCAST
|
||||
@ -29,6 +32,7 @@ import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_IDENTITY
|
||||
import ch.dissem.apps.abit.adapter.SwipeableMessageAdapter
|
||||
import ch.dissem.apps.abit.listener.ListSelectionListener
|
||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository
|
||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository.Companion.LABEL_ARCHIVE
|
||||
import ch.dissem.apps.abit.service.Singleton
|
||||
import ch.dissem.apps.abit.util.FabUtils
|
||||
import ch.dissem.bitmessage.entity.Plaintext
|
||||
@ -41,9 +45,12 @@ import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
|
||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
|
||||
import kotlinx.android.synthetic.main.fragment_message_list.*
|
||||
import org.jetbrains.anko.doAsync
|
||||
import org.jetbrains.anko.support.v4.onUiThread
|
||||
import org.jetbrains.anko.uiThread
|
||||
import java.util.*
|
||||
|
||||
private const val PAGE_SIZE = 15
|
||||
|
||||
/**
|
||||
* A list fragment representing a list of Messages. This fragment
|
||||
* also supports tablet devices by allowing list items to be given an
|
||||
@ -56,12 +63,33 @@ import java.util.*
|
||||
*/
|
||||
class MessageListFragment : Fragment(), ListHolder<Label> {
|
||||
|
||||
private var layoutManager: RecyclerView.LayoutManager? = null
|
||||
private var isLoading = false
|
||||
private var isLastPage = false
|
||||
|
||||
private var layoutManager: LinearLayoutManager? = null
|
||||
private var swipeableMessageAdapter: SwipeableMessageAdapter? = null
|
||||
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
|
||||
private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
|
||||
private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
|
||||
|
||||
private val recyclerViewOnScrollListener = object : OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
|
||||
layoutManager?.let { layoutManager ->
|
||||
val visibleItemCount = layoutManager.childCount
|
||||
val totalItemCount = layoutManager.itemCount
|
||||
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
|
||||
|
||||
if (!isLoading && !isLastPage) {
|
||||
if (visibleItemCount + firstVisibleItemPosition >= totalItemCount - 5
|
||||
&& firstVisibleItemPosition >= 0
|
||||
&& totalItemCount >= PAGE_SIZE) {
|
||||
loadMoreItems()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var currentLabel: Label? = null
|
||||
|
||||
private var emptyTrashMenuItem: MenuItem? = null
|
||||
@ -70,6 +98,20 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
|
||||
|
||||
private val backStack = Stack<Label>()
|
||||
|
||||
fun loadMoreItems() {
|
||||
isLoading = true
|
||||
swipeableMessageAdapter?.let { messageAdapter ->
|
||||
doAsync {
|
||||
val messages = messageRepo.findMessages(currentLabel, messageAdapter.itemCount, PAGE_SIZE)
|
||||
onUiThread {
|
||||
messageAdapter.addAll(messages)
|
||||
isLoading = false
|
||||
isLastPage = messages.size < PAGE_SIZE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@ -82,10 +124,8 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
|
||||
initFab(activity)
|
||||
messageRepo = Singleton.getMessageRepository(activity)
|
||||
|
||||
if (backStack.isEmpty()) {
|
||||
if (backStack.isEmpty() && currentLabel == null) {
|
||||
doUpdateList(activity.selectedLabel)
|
||||
} else {
|
||||
doUpdateList(backStack.peek())
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,13 +159,7 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
|
||||
}
|
||||
}
|
||||
|
||||
doAsync {
|
||||
messageRepo.findMessageIds(label)
|
||||
.map { messageRepo.getMessage(it) }
|
||||
.forEach { message ->
|
||||
uiThread { swipeableMessageAdapter?.add(message) }
|
||||
}
|
||||
}
|
||||
loadMoreItems()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
@ -189,6 +223,7 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
|
||||
recycler_view.layoutManager = layoutManager
|
||||
recycler_view.adapter = wrappedAdapter // requires *wrapped* swipeableMessageAdapter
|
||||
recycler_view.itemAnimator = animator
|
||||
recycler_view.addOnScrollListener(recyclerViewOnScrollListener)
|
||||
|
||||
recycler_view.addItemDecoration(SimpleListDividerDecorator(
|
||||
ContextCompat.getDrawable(context, R.drawable.list_divider_h), true))
|
||||
@ -204,6 +239,17 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
|
||||
recyclerViewTouchActionGuardManager = touchActionGuardManager
|
||||
recyclerViewSwipeManager = swipeManager
|
||||
this.swipeableMessageAdapter = adapter
|
||||
|
||||
Singleton.labeler.listener = { message, added, removed ->
|
||||
if (added.contains(currentLabel)) {
|
||||
// TODO: add to current list, at correct position
|
||||
} else if (removed.contains(currentLabel)) {
|
||||
swipeableMessageAdapter?.remove(message)
|
||||
} else if (removed.any { it.type == Label.Type.UNREAD } || added.any { it.type == Label.Type.UNREAD }) {
|
||||
// TODO: update if in current list, maybe update unread badges
|
||||
swipeableMessageAdapter?.update(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initFab(context: MainActivity) {
|
||||
@ -295,4 +341,10 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun addMessage(message: Plaintext) {
|
||||
if (message.labels.contains(currentLabel) || (currentLabel == LABEL_ARCHIVE && message.labels.isEmpty())) {
|
||||
swipeableMessageAdapter?.addFirst(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +96,35 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun addFirst(item: Plaintext) {
|
||||
val index = data.size
|
||||
data.addFirst(item)
|
||||
notifyItemInserted(index)
|
||||
}
|
||||
|
||||
fun addAll(items: Collection<Plaintext>) {
|
||||
val index = data.size
|
||||
data.addAll(items)
|
||||
notifyItemRangeInserted(index, items.size)
|
||||
}
|
||||
|
||||
fun remove(item: Plaintext) {
|
||||
val index = data.indexOf(item)
|
||||
data.removeIf { it.id == item.id }
|
||||
notifyItemRemoved(index)
|
||||
}
|
||||
|
||||
fun update(item: Plaintext) {
|
||||
data.replaceAll {
|
||||
if (it.id == item.id) {
|
||||
item
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
notifyItemChanged(data.indexOf(item))
|
||||
}
|
||||
|
||||
fun clear(newLabel: Label?) {
|
||||
label = newLabel
|
||||
data.clear()
|
||||
|
@ -17,16 +17,12 @@
|
||||
package ch.dissem.apps.abit.listener
|
||||
|
||||
import android.content.Context
|
||||
|
||||
import java.util.Deque
|
||||
import java.util.LinkedList
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
import ch.dissem.apps.abit.MainActivity
|
||||
import ch.dissem.apps.abit.notification.NewMessageNotification
|
||||
import ch.dissem.bitmessage.BitmessageContext
|
||||
import ch.dissem.bitmessage.entity.Plaintext
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* Listens for decrypted Bitmessage messages. Does show a notification.
|
||||
|
@ -42,10 +42,10 @@ import java.util.*
|
||||
*/
|
||||
class AndroidMessageRepository(private val sql: SqlHelper, private val context: Context) : AbstractMessageRepository() {
|
||||
|
||||
override fun findMessages(label: Label?) = if (label === LABEL_ARCHIVE) {
|
||||
super.findMessages(null as Label?)
|
||||
override fun findMessages(label: Label?, offset: Int, limit: Int) = if (label === LABEL_ARCHIVE) {
|
||||
super.findMessages(null as Label?, offset, limit)
|
||||
} else {
|
||||
super.findMessages(label)
|
||||
super.findMessages(label, offset, limit)
|
||||
}
|
||||
|
||||
fun findMessageIds(label: Label) = if (label === LABEL_ARCHIVE) {
|
||||
@ -224,7 +224,7 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val context:
|
||||
return result
|
||||
}
|
||||
|
||||
override fun find(where: String): List<Plaintext> {
|
||||
override fun find(where: String, offset: Int, limit: Int): List<Plaintext> {
|
||||
val result = LinkedList<Plaintext>()
|
||||
|
||||
// Define a projection that specifies which columns from the database
|
||||
@ -235,7 +235,8 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val context:
|
||||
db.query(
|
||||
TABLE_NAME, projection,
|
||||
where, null, null, null,
|
||||
"$COLUMN_RECEIVED DESC, $COLUMN_SENT DESC"
|
||||
"$COLUMN_RECEIVED DESC, $COLUMN_SENT DESC",
|
||||
if (limit == 0) null else "$offset, $limit"
|
||||
).use { c ->
|
||||
while (c.moveToNext()) {
|
||||
val iv = c.getBlob(c.getColumnIndex(COLUMN_IV))
|
||||
|
@ -30,6 +30,7 @@ import ch.dissem.bitmessage.BitmessageContext
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import ch.dissem.bitmessage.entity.payload.Pubkey
|
||||
import ch.dissem.bitmessage.networking.nio.NioNetworkHandler
|
||||
import ch.dissem.bitmessage.ports.DefaultLabeler
|
||||
import ch.dissem.bitmessage.utils.ConversationService
|
||||
import ch.dissem.bitmessage.utils.TTL
|
||||
import ch.dissem.bitmessage.utils.UnixTime.DAY
|
||||
@ -40,6 +41,7 @@ import org.jetbrains.anko.uiThread
|
||||
* Provides singleton objects across the application.
|
||||
*/
|
||||
object Singleton {
|
||||
val labeler = DefaultLabeler()
|
||||
var bitmessageContext: BitmessageContext? = null
|
||||
private set
|
||||
private var conversationService: ConversationService? = null
|
||||
@ -69,6 +71,7 @@ object Singleton {
|
||||
.powRepo(powRepo)
|
||||
.networkHandler(NioNetworkHandler())
|
||||
.listener(getMessageListener(ctx))
|
||||
.labeler(labeler)
|
||||
.doNotSendPubkeyOnIdentityCreation()
|
||||
.build()
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ configurations.all {
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.1.4-2'
|
||||
ext.kotlin_version = '1.1.4-3'
|
||||
ext.anko_version = '0.10.1'
|
||||
repositories {
|
||||
jcenter()
|
||||
|
Loading…
Reference in New Issue
Block a user