forked from github/wulkanowy-mirror
Add search in messages (#804)
This commit is contained in:
parent
6cd1877af7
commit
115da64167
@ -39,7 +39,8 @@
|
||||
android:name=".ui.modules.main.MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/main_title"
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar"
|
||||
android:windowSoftInputMode="adjustPan" />
|
||||
<activity
|
||||
android:name=".ui.modules.message.send.SendMessageActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
|
@ -5,6 +5,8 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.SortedList
|
||||
import androidx.recyclerview.widget.SortedListAdapterCallback
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
||||
@ -15,11 +17,41 @@ import javax.inject.Inject
|
||||
class MessageTabAdapter @Inject constructor() :
|
||||
RecyclerView.Adapter<MessageTabAdapter.ItemViewHolder>() {
|
||||
|
||||
var items = mutableListOf<Message>()
|
||||
|
||||
var onClickListener: (Message, position: Int) -> Unit = { _, _ -> }
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
private val items = SortedList(Message::class.java, object :
|
||||
SortedListAdapterCallback<Message>(this) {
|
||||
|
||||
override fun compare(item1: Message, item2: Message): Int {
|
||||
return item2.date.compareTo(item1.date)
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: Message?, newItem: Message?): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
override fun areItemsTheSame(item1: Message, item2: Message): Boolean {
|
||||
return item1 == item2
|
||||
}
|
||||
})
|
||||
|
||||
fun replaceAll(models: List<Message>) {
|
||||
items.beginBatchedUpdates()
|
||||
for (i in items.size() - 1 downTo 0) {
|
||||
val model = items.get(i)
|
||||
if (model !in models) {
|
||||
items.remove(model)
|
||||
}
|
||||
}
|
||||
items.addAll(models)
|
||||
items.endBatchedUpdates()
|
||||
}
|
||||
|
||||
fun updateItem(position: Int, item: Message) {
|
||||
items.updateItemAt(position, item)
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||
ItemMessageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
|
@ -1,10 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.message.tab
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
@ -39,7 +42,12 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
||||
}
|
||||
|
||||
override val isViewEmpty
|
||||
get() = tabAdapter.items.isEmpty()
|
||||
get() = tabAdapter.itemCount == 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@ -65,18 +73,28 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.action_menu_message_tab, menu)
|
||||
|
||||
val searchView = menu.findItem(R.id.action_search).actionView as SearchView
|
||||
searchView.queryHint = getString(R.string.all_search_hint)
|
||||
searchView.maxWidth = Int.MAX_VALUE
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String) = false
|
||||
override fun onQueryTextChange(query: String): Boolean {
|
||||
presenter.onSearchQueryTextChange(query)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun updateData(data: List<Message>) {
|
||||
with(tabAdapter) {
|
||||
items = data.toMutableList()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
tabAdapter.replaceAll(data)
|
||||
}
|
||||
|
||||
override fun updateItem(item: Message, position: Int) {
|
||||
with(tabAdapter) {
|
||||
items[position] = item
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
tabAdapter.updateItem(position, item)
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
@ -87,6 +105,10 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
||||
binding.messageTabSwipe.isEnabled = enable
|
||||
}
|
||||
|
||||
override fun resetListPosition() {
|
||||
binding.messageTabRecycler.scrollToPosition(0)
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
binding.messageTabRecycler.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.message.tab
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
||||
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
||||
@ -9,6 +10,7 @@ import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -25,6 +27,10 @@ class MessageTabPresenter @Inject constructor(
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
||||
private var lastSearchQuery = ""
|
||||
|
||||
private var messages = emptyList<Message>()
|
||||
|
||||
fun onAttachView(view: MessageTabView, folder: MessageFolder) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
@ -89,12 +95,8 @@ class MessageTabPresenter @Inject constructor(
|
||||
}
|
||||
.subscribe({
|
||||
Timber.i("Loading $folder message result: Success")
|
||||
view?.run {
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
showErrorView(false)
|
||||
updateData(it)
|
||||
}
|
||||
messages = it
|
||||
onSearchQueryTextChange(lastSearchQuery)
|
||||
analytics.logEvent("load_messages", "items" to it.size, "folder" to folder.name)
|
||||
}) {
|
||||
Timber.i("Loading $folder message result: An exception occurred")
|
||||
@ -113,4 +115,33 @@ class MessageTabPresenter @Inject constructor(
|
||||
} else showError(message, error)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
fun onSearchQueryTextChange(query: String) {
|
||||
lastSearchQuery = query
|
||||
|
||||
val lowerCaseQuery = query.toLowerCase()
|
||||
val filteredList = mutableListOf<Message>()
|
||||
messages.forEach {
|
||||
if (lowerCaseQuery in it.subject.toLowerCase() ||
|
||||
lowerCaseQuery in it.sender.toLowerCase() ||
|
||||
lowerCaseQuery in it.recipient.toLowerCase() ||
|
||||
lowerCaseQuery in it.date.toFormattedString()
|
||||
) {
|
||||
filteredList.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
updateData(filteredList)
|
||||
}
|
||||
|
||||
private fun updateData(data: List<Message>) {
|
||||
view?.run {
|
||||
showEmpty(data.isEmpty())
|
||||
showContent(data.isNotEmpty())
|
||||
showErrorView(false)
|
||||
updateData(data)
|
||||
resetListPosition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ interface MessageTabView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun resetListPosition()
|
||||
|
||||
fun updateData(data: List<Message>)
|
||||
|
||||
fun updateItem(item: Message, position: Int)
|
||||
|
9
app/src/main/res/drawable/ic_search.xml
Normal file
9
app/src/main/res/drawable/ic_search.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
|
||||
</vector>
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/mainContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@ -8,7 +9,8 @@
|
||||
android:id="@+id/mainToolbar"
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Surface"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"
|
||||
app:contentInsetStartWithNavigation="0dp" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/mainFragmentContainer"
|
||||
|
11
app/src/main/res/menu/action_menu_message_tab.xml
Normal file
11
app/src/main/res/menu/action_menu_message_tab.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_search"
|
||||
android:icon="@drawable/ic_search"
|
||||
android:title="@string/all_search"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||
app:showAsAction="collapseActionView|ifRoom" />
|
||||
</menu>
|
@ -298,6 +298,7 @@
|
||||
<string name="all_subject">Przedmiot</string>
|
||||
<string name="all_prev">Poprzedni</string>
|
||||
<string name="all_next">Następny</string>
|
||||
<string name="all_search">Szukaj</string>
|
||||
<!--Timetable Widget-->
|
||||
<string name="widget_timetable_no_items">Brak lekcji</string>
|
||||
<string name="widget_timetable_theme_title">Wybierz motyw</string>
|
||||
|
@ -329,6 +329,8 @@
|
||||
<string name="all_subject">Subject</string>
|
||||
<string name="all_prev">Prev</string>
|
||||
<string name="all_next">Next</string>
|
||||
<string name="all_search">Search</string>
|
||||
<string name="all_search_hint">Search...</string>
|
||||
|
||||
|
||||
<!--Timetable Widget-->
|
||||
|
Loading…
x
Reference in New Issue
Block a user