Add search for DataList

feature/players
Aurelien Hubert 6 years ago
parent 1aef1c9745
commit eef60124ed
  1. 10
      app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt
  2. 113
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  3. 27
      app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt
  4. 9
      app/src/main/res/drawable/ic_outline_search.xml
  5. 13
      app/src/main/res/menu/toolbar_data_list.xml

@ -7,9 +7,11 @@ import android.content.res.Resources
import android.net.Uri import android.net.Uri
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.LinearLayout
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
import androidx.appcompat.widget.SearchView
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
@ -161,3 +163,11 @@ fun View.addCircleRipple() = with(TypedValue()) {
context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, this, true) context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, this, true)
setBackgroundResource(resourceId) setBackgroundResource(resourceId)
} }
fun SearchView.removeMargins() {
val searchEditFrame = findViewById<LinearLayout?>(R.id.search_edit_frame)
val layoutParams = searchEditFrame?.layoutParams as LinearLayout.LayoutParams?
layoutParams?.leftMargin = 0
layoutParams?.rightMargin = 0
searchEditFrame?.layoutParams = layoutParams
}

@ -3,9 +3,8 @@ package net.pokeranalytics.android.ui.fragment
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.*
import android.view.View import androidx.appcompat.widget.SearchView
import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -23,13 +22,17 @@ import net.pokeranalytics.android.ui.activity.FiltersActivity
import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.extensions.removeMargins
import net.pokeranalytics.android.ui.fragment.components.DeletableItemFragment import net.pokeranalytics.android.ui.fragment.components.DeletableItemFragment
import net.pokeranalytics.android.ui.helpers.SwipeToDeleteCallback import net.pokeranalytics.android.ui.helpers.SwipeToDeleteCallback
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.extensions.find
import net.pokeranalytics.android.util.extensions.sorted import net.pokeranalytics.android.util.extensions.sorted
open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource, RowRepresentableDelegate { open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource, RowRepresentableDelegate {
companion object { companion object {
@ -40,6 +43,14 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
private lateinit var dataType: LiveData private lateinit var dataType: LiveData
private lateinit var items: RealmResults<out Deletable> private lateinit var items: RealmResults<out Deletable>
private var dataListMenu: Menu? = null
var isSearchable: Boolean = false
set(value) {
field = value
val searchMenuItem = dataListMenu?.findItem(R.id.action_search)
searchMenuItem?.isVisible = value
}
/** /**
* Set fragment data * Set fragment data
@ -51,6 +62,11 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
setToolbarTitle(this.dataType.pluralLocalizedTitle(requireContext())) setToolbarTitle(this.dataType.pluralLocalizedTitle(requireContext()))
this.items = this.retrieveItems(getRealm()) this.items = this.retrieveItems(getRealm())
isSearchable = when(this.dataType) {
LiveData.PLAYER, LiveData.LOCATION -> true
else -> false
}
} }
open fun retrieveItems(realm: Realm): RealmResults<out Deletable> { open fun retrieveItems(realm: Realm): RealmResults<out Deletable> {
@ -71,43 +87,30 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
initUI() initUI()
} }
/** override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
* Init UI
*/
private fun initUI() {
setDisplayHomeAsUpEnabled(true) menu.clear()
inflater.inflate(R.menu.toolbar_data_list, menu)
this.dataListMenu = menu
val viewManager = LinearLayoutManager(requireContext()) val searchMenuItem = menu.findItem(R.id.action_search)
dataListAdapter = RowRepresentableAdapter(this, this) searchMenuItem.isVisible = isSearchable
val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position -> val searchView = searchMenuItem.actionView as SearchView
val item = this.items[position] searchView.removeMargins()
if (item != null) { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
val itemId = item.id override fun onQueryTextSubmit(query: String?): Boolean {
deleteItem(dataListAdapter, items, itemId) return false
} else {
throw PAIllegalStateException("Item with position $position not found")
} }
override fun onQueryTextChange(newText: String?): Boolean {
filterItemsWithSearch(newText)
return false
} }
})
val itemTouchHelper = ItemTouchHelper(swipeToDelete) super.onCreateOptionsMenu(menu, inflater)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataListAdapter
itemTouchHelper.attachToRecyclerView(this)
} }
this.addButton.setOnClickListener {
EditableDataActivity.newInstance(
requireContext(),
dataType = this.dataType.ordinal,
primaryKey = null
)
}
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
@ -143,6 +146,52 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
} }
} }
/**
* Init UI
*/
private fun initUI() {
setDisplayHomeAsUpEnabled(true)
val viewManager = LinearLayoutManager(requireContext())
dataListAdapter = RowRepresentableAdapter(this, this)
val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position ->
val item = this.items[position]
if (item != null) {
val itemId = item.id
deleteItem(dataListAdapter, items, itemId)
} else {
throw PAIllegalStateException("Item with position $position not found")
}
}
val itemTouchHelper = ItemTouchHelper(swipeToDelete)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataListAdapter
itemTouchHelper.attachToRecyclerView(this)
}
this.addButton.setOnClickListener {
EditableDataActivity.newInstance(
requireContext(),
dataType = this.dataType.ordinal,
primaryKey = null
)
}
}
/**
* Filter the items list with the given search content
*/
private fun filterItemsWithSearch(searchContent: String?) {
this.items = getRealm().find(this.identifiableClass, searchContent)
dataListAdapter.notifyDataSetChanged()
}
/** /**
* Update UI * Update UI
*/ */

@ -1,16 +1,10 @@
package net.pokeranalytics.android.util.extensions package net.pokeranalytics.android.util.extensions
import io.realm.Realm import io.realm.*
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.Sort
import net.pokeranalytics.android.model.interfaces.CountableUsage import net.pokeranalytics.android.model.interfaces.CountableUsage
import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.realm.TournamentFeature
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
fun <T : RealmModel>Realm.count(clazz: Class<T>) : Long { fun <T : RealmModel>Realm.count(clazz: Class<T>) : Long {
return this.where(clazz).count() return this.where(clazz).count()
@ -106,5 +100,22 @@ fun <T : RealmModel>Realm.updateUsageCount(clazz: Class<T>) {
countable.useCount = count countable.useCount = count
} }
} }
}
/**
* Returns all entities of the [clazz] which contain the given search content
*/
fun < T : RealmModel> Realm.find(clazz: Class<T>, searchContent: String?) : RealmResults<T> {
val query = this.where(clazz)
when (clazz.kotlin) {
Player::class -> {
query.contains("name", searchContent ?: "", Case.INSENSITIVE).or()
query.contains("summary", searchContent ?: "", Case.INSENSITIVE)
}
}
val items = query.findAll()
val sortField = arrayOf("name")
val resultSort = arrayOf(Sort.ASCENDING)
return items.sort(sortField, resultSort)
} }

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
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>

@ -0,0 +1,13 @@
<?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_outline_search"
app:showAsAction="always|collapseActionView"
app:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@android:string/search_go"
android:visible="false"/>
</menu>
Loading…
Cancel
Save