Single-provider search
parent
9373bae091
commit
5f49030926
@ -1,29 +0,0 @@
|
||||
package org.koitharu.kotatsu.domain.search
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SearchRecentSuggestionsProvider
|
||||
import android.provider.SearchRecentSuggestions
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
|
||||
class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
|
||||
|
||||
init {
|
||||
setupSuggestions(AUTHORITY, MODE)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun saveQuery(context: Context, query: String) {
|
||||
SearchRecentSuggestions(context, AUTHORITY, MODE)
|
||||
.saveRecentQuery(query, null)
|
||||
}
|
||||
|
||||
fun clearHistory(context: Context) {
|
||||
SearchRecentSuggestions(context, AUTHORITY, MODE)
|
||||
.clearHistory()
|
||||
}
|
||||
|
||||
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.MangaSuggestionsProvider"
|
||||
private const val MODE = DATABASE_MODE_QUERIES
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package org.koitharu.kotatsu.ui.search
|
||||
|
||||
import android.app.SearchManager
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.SearchRecentSuggestionsProvider
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.SearchRecentSuggestions
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.cursoradapter.widget.CursorAdapter
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
|
||||
class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
|
||||
|
||||
init {
|
||||
setupSuggestions(
|
||||
AUTHORITY,
|
||||
MODE
|
||||
)
|
||||
}
|
||||
|
||||
private class SearchSuggestionAdapter(context: Context, cursor: Cursor) : CursorAdapter(
|
||||
context, cursor,
|
||||
FLAG_REGISTER_CONTENT_OBSERVER
|
||||
) {
|
||||
|
||||
override fun newView(context: Context, cursor: Cursor?, parent: ViewGroup?): View {
|
||||
return LayoutInflater.from(context)
|
||||
.inflate(R.layout.item_search_complete, parent, false)
|
||||
}
|
||||
|
||||
override fun bindView(view: View, context: Context, cursor: Cursor) {
|
||||
if (view !is TextView) return
|
||||
view.text = cursor.getString(cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY))
|
||||
}
|
||||
|
||||
override fun convertToString(cursor: Cursor?): CharSequence {
|
||||
return cursor?.getString(cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY))
|
||||
.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.MangaSuggestionsProvider"
|
||||
private const val MODE = DATABASE_MODE_QUERIES
|
||||
|
||||
private val uri = Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(AUTHORITY)
|
||||
.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY)
|
||||
.build()
|
||||
private val projection = arrayOf("_id", SearchManager.SUGGEST_COLUMN_QUERY)
|
||||
|
||||
fun saveQuery(context: Context, query: String) {
|
||||
SearchRecentSuggestions(
|
||||
context,
|
||||
AUTHORITY,
|
||||
MODE
|
||||
).saveRecentQuery(query, null)
|
||||
}
|
||||
|
||||
fun clearHistory(context: Context) {
|
||||
SearchRecentSuggestions(
|
||||
context,
|
||||
AUTHORITY,
|
||||
MODE
|
||||
).clearHistory()
|
||||
}
|
||||
|
||||
private fun getCursor(context: Context): Cursor? {
|
||||
return context.contentResolver?.query(uri, projection, null, arrayOf(""), null)
|
||||
}
|
||||
|
||||
fun getSuggestionAdapter(context: Context): CursorAdapter? = getCursor(
|
||||
context
|
||||
)?.let { cursor ->
|
||||
SearchSuggestionAdapter(context, cursor).also {
|
||||
it.setFilterQueryProvider { q ->
|
||||
context.contentResolver?.query(uri, projection, " ?", arrayOf(q.toString()), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package org.koitharu.kotatsu.ui.search
|
||||
|
||||
import android.app.SearchManager
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.view.MenuItem
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.utils.ext.safe
|
||||
|
||||
object SearchHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun setupSearchView(menuItem: MenuItem, source: MangaSource) {
|
||||
val view = menuItem.actionView as? SearchView ?: return
|
||||
val context = view.context
|
||||
view.queryHint = context.getString(R.string.search_manga)
|
||||
view.imeOptions = EditorInfo.IME_ACTION_SEARCH
|
||||
view.inputType = EditorInfo.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE
|
||||
view.suggestionsAdapter = MangaSuggestionsProvider.getSuggestionAdapter(context)
|
||||
view.setOnQueryTextListener(QueryListener(context, source))
|
||||
view.setOnSuggestionListener(SuggestionListener(view))
|
||||
}
|
||||
|
||||
private class QueryListener(private val context: Context, private val source: MangaSource) :
|
||||
SearchView.OnQueryTextListener {
|
||||
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
return if (!query.isNullOrBlank()) {
|
||||
context.startActivity(SearchActivity.newIntent(context, source, query.trim()))
|
||||
MangaSuggestionsProvider.saveQuery(context, query)
|
||||
true
|
||||
} else false
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String?) = false
|
||||
}
|
||||
|
||||
private class SuggestionListener(private val view: SearchView) :
|
||||
SearchView.OnSuggestionListener {
|
||||
|
||||
override fun onSuggestionSelect(position: Int) = false
|
||||
|
||||
override fun onSuggestionClick(position: Int): Boolean {
|
||||
val query = safe {
|
||||
val c = view.suggestionsAdapter.getItem(position) as? Cursor
|
||||
c?.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY))
|
||||
} ?: return false
|
||||
view.setQuery(query, true)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.app.SearchManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import org.koitharu.kotatsu.ui.search.SearchActivity
|
||||
|
||||
object SearchHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun setupSearchView(menuItem: MenuItem) {
|
||||
val view = menuItem.actionView as? SearchView ?: return
|
||||
val context = view.context
|
||||
val searchManager = context.applicationContext.getSystemService(Context.SEARCH_SERVICE) as SearchManager
|
||||
val info = searchManager.getSearchableInfo(ComponentName(context, SearchActivity::class.java))
|
||||
view.setSearchableInfo(info)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?listPreferredItemHeightSmall"
|
||||
android:background="?selectableItemBackground"
|
||||
android:drawableStart="@drawable/ic_history"
|
||||
android:drawablePadding="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?listPreferredItemPaddingEnd"
|
||||
android:textAppearance="?textAppearanceListItemSmall"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:theme="@style/AppPopupTheme"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
@ -0,0 +1,14 @@
|
||||
<?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:orderInCategory="1"
|
||||
android:title="@string/search"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:showAsAction="always|collapseActionView" />
|
||||
|
||||
</menu>
|
||||
@ -1,4 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppPopupTheme" parent="ThemeOverlay.MaterialComponents.Dark" />
|
||||
|
||||
<style name="AppSuggestion" parent="Widget.AppCompat.AutoCompleteTextView">
|
||||
<item name="android:popupBackground">@android:color/background_dark</item>
|
||||
</style>
|
||||
</resources>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<searchable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:hint="@string/search_manga"
|
||||
android:inputType="textPersonName"
|
||||
android:label="@string/app_name"
|
||||
android:searchSuggestAuthority="org.koitharu.kotatsu.MangaSuggestionsProvider"
|
||||
android:searchSuggestSelection=" ?"
|
||||
android:voiceLanguageModel="web_search"
|
||||
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" />
|
||||
Loading…
Reference in New Issue