mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Migrate settings search view to Compose
This commit is contained in:
		@@ -0,0 +1,85 @@
 | 
			
		||||
package eu.kanade.presentation.more.settings
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.WindowInsets
 | 
			
		||||
import androidx.compose.foundation.layout.asPaddingValues
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.navigationBars
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.foundation.lazy.rememberLazyListState
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 | 
			
		||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
 | 
			
		||||
import eu.kanade.presentation.util.horizontalPadding
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchHelper
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchPresenter
 | 
			
		||||
import kotlin.reflect.full.createInstance
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun SettingsSearchScreen(
 | 
			
		||||
    nestedScroll: NestedScrollConnection,
 | 
			
		||||
    presenter: SettingsSearchPresenter,
 | 
			
		||||
    onClickResult: (SettingsController) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    val results by presenter.state.collectAsState()
 | 
			
		||||
 | 
			
		||||
    val scrollState = rememberLazyListState()
 | 
			
		||||
    ScrollbarLazyColumn(
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .nestedScroll(nestedScroll),
 | 
			
		||||
        contentPadding = WindowInsets.navigationBars.asPaddingValues(),
 | 
			
		||||
        state = scrollState,
 | 
			
		||||
    ) {
 | 
			
		||||
        items(
 | 
			
		||||
            items = results,
 | 
			
		||||
            key = { it.key.toString() },
 | 
			
		||||
        ) { result ->
 | 
			
		||||
            SearchResult(result, onClickResult)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
private fun SearchResult(
 | 
			
		||||
    result: SettingsSearchHelper.SettingsSearchResult,
 | 
			
		||||
    onClickResult: (SettingsController) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    Column(
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .fillMaxWidth()
 | 
			
		||||
            .padding(horizontal = horizontalPadding, vertical = 8.dp)
 | 
			
		||||
            .clickable {
 | 
			
		||||
                // Must pass a new Controller instance to avoid this error
 | 
			
		||||
                // https://github.com/bluelinelabs/Conductor/issues/446
 | 
			
		||||
                val controller = result.searchController::class.createInstance()
 | 
			
		||||
                controller.preferenceKey = result.key
 | 
			
		||||
                onClickResult(controller)
 | 
			
		||||
            },
 | 
			
		||||
    ) {
 | 
			
		||||
        Text(
 | 
			
		||||
            text = result.title,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        Text(
 | 
			
		||||
            text = result.summary,
 | 
			
		||||
            style = MaterialTheme.typography.bodySmall.copy(
 | 
			
		||||
                color = MaterialTheme.colorScheme.outline,
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        Text(
 | 
			
		||||
            text = result.breadcrumb,
 | 
			
		||||
            style = MaterialTheme.typography.bodySmall,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,82 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting.search
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.os.Parcelable
 | 
			
		||||
import android.util.SparseArray
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adapter that holds the search cards.
 | 
			
		||||
 *
 | 
			
		||||
 * @param controller instance of [SettingsSearchController].
 | 
			
		||||
 */
 | 
			
		||||
class SettingsSearchAdapter(val controller: SettingsSearchController) :
 | 
			
		||||
    FlexibleAdapter<SettingsSearchItem>(null, controller, true) {
 | 
			
		||||
 | 
			
		||||
    val titleClickListener: OnTitleClickListener = controller
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Bundle where the view state of the holders is saved.
 | 
			
		||||
     */
 | 
			
		||||
    private var bundle = Bundle()
 | 
			
		||||
 | 
			
		||||
    override fun onBindViewHolder(
 | 
			
		||||
        holder: RecyclerView.ViewHolder,
 | 
			
		||||
        position: Int,
 | 
			
		||||
        payloads: List<Any?>,
 | 
			
		||||
    ) {
 | 
			
		||||
        super.onBindViewHolder(holder, position, payloads)
 | 
			
		||||
        restoreHolderState(holder)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
 | 
			
		||||
        super.onViewRecycled(holder)
 | 
			
		||||
        saveHolderState(holder, bundle)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSaveInstanceState(outState: Bundle) {
 | 
			
		||||
        val holdersBundle = Bundle()
 | 
			
		||||
        allBoundViewHolders.forEach { saveHolderState(it, holdersBundle) }
 | 
			
		||||
        outState.putBundle(HOLDER_BUNDLE_KEY, holdersBundle)
 | 
			
		||||
        super.onSaveInstanceState(outState)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
 | 
			
		||||
        super.onRestoreInstanceState(savedInstanceState)
 | 
			
		||||
        bundle = savedInstanceState.getBundle(HOLDER_BUNDLE_KEY)!!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves the view state of the given holder.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holder The holder to save.
 | 
			
		||||
     * @param outState The bundle where the state is saved.
 | 
			
		||||
     */
 | 
			
		||||
    private fun saveHolderState(holder: RecyclerView.ViewHolder, outState: Bundle) {
 | 
			
		||||
        val key = "holder_${holder.bindingAdapterPosition}"
 | 
			
		||||
        val holderState = SparseArray<Parcelable>()
 | 
			
		||||
        holder.itemView.saveHierarchyState(holderState)
 | 
			
		||||
        outState.putSparseParcelableArray(key, holderState)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Restores the view state of the given holder.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holder The holder to restore.
 | 
			
		||||
     */
 | 
			
		||||
    private fun restoreHolderState(holder: RecyclerView.ViewHolder) {
 | 
			
		||||
        val key = "holder_${holder.bindingAdapterPosition}"
 | 
			
		||||
        bundle.getSparseParcelableArray<Parcelable>(key)?.let {
 | 
			
		||||
            holder.itemView.restoreHierarchyState(it)
 | 
			
		||||
            bundle.remove(key)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface OnTitleClickListener {
 | 
			
		||||
        fun onTitleClick(ctrl: SettingsController)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private const val HOLDER_BUNDLE_KEY = "holder_bundle"
 | 
			
		||||
@@ -1,68 +1,45 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting.search
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.Menu
 | 
			
		||||
import android.view.MenuInflater
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import android.view.View
 | 
			
		||||
import androidx.appcompat.widget.SearchView
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import dev.chrisbanes.insetter.applyInsetter
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 | 
			
		||||
import eu.kanade.presentation.more.settings.SettingsSearchScreen
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.SettingsSearchControllerBinding
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.ComposeController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This controller shows and manages the different search result in settings search.
 | 
			
		||||
 * [SettingsSearchAdapter.OnTitleClickListener] called when preference is clicked in settings search
 | 
			
		||||
 */
 | 
			
		||||
class SettingsSearchController :
 | 
			
		||||
    NucleusController<SettingsSearchControllerBinding, SettingsSearchPresenter>(),
 | 
			
		||||
    SettingsSearchAdapter.OnTitleClickListener {
 | 
			
		||||
class SettingsSearchController : ComposeController<SettingsSearchPresenter>() {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adapter containing search results grouped by lang.
 | 
			
		||||
     */
 | 
			
		||||
    private var adapter: SettingsSearchAdapter? = null
 | 
			
		||||
    private lateinit var searchView: SearchView
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        setHasOptionsMenu(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createBinding(inflater: LayoutInflater) = SettingsSearchControllerBinding.inflate(inflater)
 | 
			
		||||
    override fun getTitle() = presenter.query
 | 
			
		||||
 | 
			
		||||
    override fun getTitle(): String? {
 | 
			
		||||
        return presenter.query
 | 
			
		||||
    override fun createPresenter() = SettingsSearchPresenter()
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) {
 | 
			
		||||
        SettingsSearchScreen(
 | 
			
		||||
            nestedScroll = nestedScrollInterop,
 | 
			
		||||
            presenter = presenter,
 | 
			
		||||
            onClickResult = { controller ->
 | 
			
		||||
                searchView.query.let {
 | 
			
		||||
                    presenter.setLastSearchQuerySearchSettings(it.toString())
 | 
			
		||||
                }
 | 
			
		||||
                router.pushController(controller)
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create the [SettingsSearchPresenter] used in controller.
 | 
			
		||||
     *
 | 
			
		||||
     * @return instance of [SettingsSearchPresenter]
 | 
			
		||||
     */
 | 
			
		||||
    override fun createPresenter(): SettingsSearchPresenter {
 | 
			
		||||
        return SettingsSearchPresenter()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds items to the options menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param menu menu containing options.
 | 
			
		||||
     * @param inflater used to load the menu xml.
 | 
			
		||||
     */
 | 
			
		||||
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
 | 
			
		||||
        inflater.inflate(R.menu.settings_main, menu)
 | 
			
		||||
 | 
			
		||||
        binding.recycler.applyInsetter {
 | 
			
		||||
            type(navigationBars = true) {
 | 
			
		||||
                padding()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Initialize search menu
 | 
			
		||||
        val searchItem = menu.findItem(R.id.action_search)
 | 
			
		||||
        searchView = searchItem.actionView as SearchView
 | 
			
		||||
@@ -70,7 +47,6 @@ class SettingsSearchController :
 | 
			
		||||
        searchView.queryHint = applicationContext?.getString(R.string.action_search_settings)
 | 
			
		||||
 | 
			
		||||
        searchItem.expandActionView()
 | 
			
		||||
        setItems(getResultSet())
 | 
			
		||||
 | 
			
		||||
        searchItem.setOnActionExpandListener(
 | 
			
		||||
            object : MenuItem.OnActionExpandListener {
 | 
			
		||||
@@ -88,76 +64,17 @@ class SettingsSearchController :
 | 
			
		||||
        searchView.setOnQueryTextListener(
 | 
			
		||||
            object : SearchView.OnQueryTextListener {
 | 
			
		||||
                override fun onQueryTextSubmit(query: String?): Boolean {
 | 
			
		||||
                    setItems(getResultSet(query))
 | 
			
		||||
                    presenter.searchSettings(query)
 | 
			
		||||
                    return false
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                override fun onQueryTextChange(newText: String?): Boolean {
 | 
			
		||||
                    setItems(getResultSet(newText))
 | 
			
		||||
                    presenter.searchSettings(newText)
 | 
			
		||||
                    return false
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        searchView.setQuery(presenter.preferences.lastSearchQuerySearchSettings().get(), true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View) {
 | 
			
		||||
        super.onViewCreated(view)
 | 
			
		||||
 | 
			
		||||
        adapter = SettingsSearchAdapter(this)
 | 
			
		||||
        binding.recycler.layoutManager = LinearLayoutManager(view.context)
 | 
			
		||||
        binding.recycler.adapter = adapter
 | 
			
		||||
 | 
			
		||||
        // load all search results
 | 
			
		||||
        SettingsSearchHelper.initPreferenceSearchResultCollection(presenter.preferences.context)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView(view: View) {
 | 
			
		||||
        adapter = null
 | 
			
		||||
        super.onDestroyView(view)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSaveViewState(view: View, outState: Bundle) {
 | 
			
		||||
        super.onSaveViewState(view, outState)
 | 
			
		||||
        adapter?.onSaveInstanceState(outState)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onRestoreViewState(view: View, savedViewState: Bundle) {
 | 
			
		||||
        super.onRestoreViewState(view, savedViewState)
 | 
			
		||||
        adapter?.onRestoreInstanceState(savedViewState)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * returns a list of `SettingsSearchItem` to be shown as search results
 | 
			
		||||
     * Future update: should we add a minimum length to the query before displaying results? Consider other languages.
 | 
			
		||||
     */
 | 
			
		||||
    fun getResultSet(query: String? = null): List<SettingsSearchItem> {
 | 
			
		||||
        if (!query.isNullOrBlank()) {
 | 
			
		||||
            return SettingsSearchHelper.getFilteredResults(query)
 | 
			
		||||
                .map { SettingsSearchItem(it, null) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return mutableListOf()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add search result to adapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param searchResult result of search.
 | 
			
		||||
     */
 | 
			
		||||
    fun setItems(searchResult: List<SettingsSearchItem>) {
 | 
			
		||||
        adapter?.updateDataSet(searchResult)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens a catalogue with the given search.
 | 
			
		||||
     */
 | 
			
		||||
    override fun onTitleClick(ctrl: SettingsController) {
 | 
			
		||||
        searchView.query.let {
 | 
			
		||||
            presenter.preferences.lastSearchQuerySearchSettings().set(it.toString())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        router.pushController(ctrl)
 | 
			
		||||
        searchView.setQuery(presenter.getLastSearchQuerySearchSettings(), true)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ object SettingsSearchHelper {
 | 
			
		||||
     * Must be called to populate `prefSearchResultList`
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressLint("RestrictedApi")
 | 
			
		||||
    fun initPreferenceSearchResultCollection(context: Context) {
 | 
			
		||||
    fun initPreferenceSearchResults(context: Context) {
 | 
			
		||||
        val preferenceManager = PreferenceManager(context)
 | 
			
		||||
        prefSearchResultList.clear()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting.search
 | 
			
		||||
 | 
			
		||||
import android.view.View
 | 
			
		||||
import eu.davidea.viewholders.FlexibleViewHolder
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.SettingsSearchControllerCardBinding
 | 
			
		||||
import kotlin.reflect.full.createInstance
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Holder that binds the [SettingsSearchItem] containing catalogue cards.
 | 
			
		||||
 *
 | 
			
		||||
 * @param view view of [SettingsSearchItem]
 | 
			
		||||
 * @param adapter instance of [SettingsSearchAdapter]
 | 
			
		||||
 */
 | 
			
		||||
class SettingsSearchHolder(view: View, val adapter: SettingsSearchAdapter) :
 | 
			
		||||
    FlexibleViewHolder(view, adapter) {
 | 
			
		||||
 | 
			
		||||
    private val binding = SettingsSearchControllerCardBinding.bind(view)
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        binding.titleWrapper.setOnClickListener {
 | 
			
		||||
            adapter.getItem(bindingAdapterPosition)?.let {
 | 
			
		||||
                val ctrl = it.settingsSearchResult.searchController::class.createInstance()
 | 
			
		||||
                ctrl.preferenceKey = it.settingsSearchResult.key
 | 
			
		||||
 | 
			
		||||
                // must pass a new Controller instance to avoid this error https://github.com/bluelinelabs/Conductor/issues/446
 | 
			
		||||
                adapter.titleClickListener.onTitleClick(ctrl)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the loading of source search result.
 | 
			
		||||
     *
 | 
			
		||||
     * @param item item of card.
 | 
			
		||||
     */
 | 
			
		||||
    fun bind(item: SettingsSearchItem) {
 | 
			
		||||
        binding.searchResultPrefTitle.text = item.settingsSearchResult.title
 | 
			
		||||
        binding.searchResultPrefSummary.text = item.settingsSearchResult.summary
 | 
			
		||||
        binding.searchResultPrefBreadcrumb.text = item.settingsSearchResult.breadcrumb
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,57 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting.search
 | 
			
		||||
 | 
			
		||||
import android.view.View
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 | 
			
		||||
import eu.davidea.flexibleadapter.items.IFlexible
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Item that contains search result information.
 | 
			
		||||
 *
 | 
			
		||||
 * @param pref the source for the search results.
 | 
			
		||||
 * @param results the search results.
 | 
			
		||||
 */
 | 
			
		||||
class SettingsSearchItem(
 | 
			
		||||
    val settingsSearchResult: SettingsSearchHelper.SettingsSearchResult,
 | 
			
		||||
    val results: List<SettingsSearchItem>?,
 | 
			
		||||
) :
 | 
			
		||||
    AbstractFlexibleItem<SettingsSearchHolder>() {
 | 
			
		||||
 | 
			
		||||
    override fun getLayoutRes(): Int {
 | 
			
		||||
        return R.layout.settings_search_controller_card
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create view holder (see [SettingsSearchAdapter].
 | 
			
		||||
     *
 | 
			
		||||
     * @return holder of view.
 | 
			
		||||
     */
 | 
			
		||||
    override fun createViewHolder(
 | 
			
		||||
        view: View,
 | 
			
		||||
        adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
 | 
			
		||||
    ): SettingsSearchHolder {
 | 
			
		||||
        return SettingsSearchHolder(view, adapter as SettingsSearchAdapter)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun bindViewHolder(
 | 
			
		||||
        adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
 | 
			
		||||
        holder: SettingsSearchHolder,
 | 
			
		||||
        position: Int,
 | 
			
		||||
        payloads: List<Any?>?,
 | 
			
		||||
    ) {
 | 
			
		||||
        holder.bind(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun equals(other: Any?): Boolean {
 | 
			
		||||
        if (other is SettingsSearchItem) {
 | 
			
		||||
            return settingsSearchResult == settingsSearchResult
 | 
			
		||||
        }
 | 
			
		||||
        return false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun hashCode(): Int {
 | 
			
		||||
        return settingsSearchResult.hashCode()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,20 +3,39 @@ package eu.kanade.tachiyomi.ui.setting.search
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 | 
			
		||||
import kotlinx.coroutines.flow.MutableStateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.StateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.asStateFlow
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class SettingsSearchPresenter : BasePresenter<SettingsSearchController>() {
 | 
			
		||||
class SettingsSearchPresenter(
 | 
			
		||||
    private val preferences: PreferencesHelper = Injekt.get(),
 | 
			
		||||
) : BasePresenter<SettingsSearchController>() {
 | 
			
		||||
 | 
			
		||||
    val preferences: PreferencesHelper = Injekt.get()
 | 
			
		||||
    private val _state: MutableStateFlow<List<SettingsSearchHelper.SettingsSearchResult>> =
 | 
			
		||||
        MutableStateFlow(emptyList())
 | 
			
		||||
    val state: StateFlow<List<SettingsSearchHelper.SettingsSearchResult>> = _state.asStateFlow()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedState)
 | 
			
		||||
        query = savedState?.getString(SettingsSearchPresenter::query.name) ?: "" // TODO - Some way to restore previous query?
 | 
			
		||||
 | 
			
		||||
        SettingsSearchHelper.initPreferenceSearchResults(preferences.context)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSave(state: Bundle) {
 | 
			
		||||
        state.putString(SettingsSearchPresenter::query.name, query)
 | 
			
		||||
        super.onSave(state)
 | 
			
		||||
    fun getLastSearchQuerySearchSettings(): String {
 | 
			
		||||
        return preferences.lastSearchQuerySearchSettings().get()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setLastSearchQuerySearchSettings(query: String) {
 | 
			
		||||
        preferences.lastSearchQuerySearchSettings().set(query)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun searchSettings(query: String?) {
 | 
			
		||||
        _state.value = if (!query.isNullOrBlank()) {
 | 
			
		||||
            SettingsSearchHelper.getFilteredResults(query)
 | 
			
		||||
        } else {
 | 
			
		||||
            emptyList()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/recycler"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:clipToPadding="false"
 | 
			
		||||
        android:paddingTop="4dp"
 | 
			
		||||
        android:paddingBottom="4dp"
 | 
			
		||||
        tools:listitem="@layout/settings_search_controller_card" />
 | 
			
		||||
 | 
			
		||||
    <FrameLayout
 | 
			
		||||
        android:id="@+id/progress"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        android:visibility="gone">
 | 
			
		||||
 | 
			
		||||
        <FrameLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:alpha="0.75"
 | 
			
		||||
            android:background="?attr/colorSurface" />
 | 
			
		||||
 | 
			
		||||
        <com.google.android.material.progressindicator.CircularProgressIndicator
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:layout_gravity="center"
 | 
			
		||||
            android:indeterminate="true" />
 | 
			
		||||
 | 
			
		||||
    </FrameLayout>
 | 
			
		||||
 | 
			
		||||
</FrameLayout>
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:id="@+id/title_wrapper"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="wrap_content"
 | 
			
		||||
    android:background="?attr/selectableItemBackground"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    android:padding="16dp">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/search_result_pref_title"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:textAppearance="?android:attr/textAppearanceListItem"
 | 
			
		||||
        tools:text="Title" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/search_result_pref_summary"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:textAppearance="?attr/textAppearanceListItemSecondary"
 | 
			
		||||
        android:textColor="?android:attr/textColorSecondary"
 | 
			
		||||
        tools:text="Summary" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/search_result_pref_breadcrumb"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:ellipsize="end"
 | 
			
		||||
        android:maxLines="1"
 | 
			
		||||
        android:textAppearance="?attr/textAppearanceBodySmall"
 | 
			
		||||
        android:textColor="?android:attr/textColorPrimary"
 | 
			
		||||
        tools:text="Location" />
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user