From 3d285104a48ab97f0a6962cb88db0526004e4457 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 20 Oct 2024 17:01:17 +0300 Subject: [PATCH] Search through settings --- .../kotatsu/core/ui/BasePreferenceFragment.kt | 36 ++++++++ .../AdapterDelegateClickListenerAdapter.kt | 2 + .../ui/suggestion/SearchSuggestionFragment.kt | 6 ++ .../kotatsu/settings/SettingsActivity.kt | 42 ++++++++++ .../kotatsu/settings/search/SettingsItem.kt | 16 ++++ .../kotatsu/settings/search/SettingsItemAD.kt | 23 +++++ .../settings/search/SettingsSearchFragment.kt | 48 +++++++++++ .../settings/search/SettingsSearchHelper.kt | 84 +++++++++++++++++++ .../search/SettingsSearchMenuProvider.kt | 51 +++++++++++ .../search/SettingsSearchViewModel.kt | 47 +++++++++++ .../layout-w600dp-land/activity_settings.xml | 11 +++ app/src/main/res/layout/activity_settings.xml | 7 ++ app/src/main/res/layout/item_preference.xml | 31 +++++++ app/src/main/res/values-ldrtl/strings.xml | 4 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/pref_about.xml | 3 +- app/src/main/res/xml/pref_appearance.xml | 3 +- app/src/main/res/xml/pref_backup_periodic.xml | 3 +- app/src/main/res/xml/pref_downloads.xml | 1 + app/src/main/res/xml/pref_network.xml | 1 + app/src/main/res/xml/pref_notifications.xml | 5 +- app/src/main/res/xml/pref_proxy.xml | 3 +- app/src/main/res/xml/pref_reader.xml | 3 +- app/src/main/res/xml/pref_services.xml | 3 +- app/src/main/res/xml/pref_sources.xml | 3 +- app/src/main/res/xml/pref_suggestions.xml | 3 +- app/src/main/res/xml/pref_tracker.xml | 3 +- app/src/main/res/xml/pref_user_data.xml | 3 +- 28 files changed, 434 insertions(+), 12 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItem.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItemAD.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchFragment.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchHelper.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchMenuProvider.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchViewModel.kt create mode 100644 app/src/main/res/layout/item_preference.xml create mode 100644 app/src/main/res/values-ldrtl/strings.xml diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt index 357e792e4..db75d16e7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BasePreferenceFragment.kt @@ -9,7 +9,10 @@ import androidx.annotation.CallSuper import androidx.annotation.StringRes import androidx.core.graphics.Insets import androidx.core.view.updatePadding +import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceScreen +import androidx.preference.get import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint @@ -20,9 +23,11 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.core.ui.util.WindowInsetsDelegate import org.koitharu.kotatsu.core.util.ext.getThemeColor +import org.koitharu.kotatsu.core.util.ext.getThemeDrawable import org.koitharu.kotatsu.core.util.ext.parentView import org.koitharu.kotatsu.settings.SettingsActivity import javax.inject.Inject +import com.google.android.material.R as materialR @AndroidEntryPoint abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : @@ -67,6 +72,10 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : override fun onResume() { super.onResume() setTitle(if (titleId != 0) getString(titleId) else null) + arguments?.getString(SettingsActivity.ARG_PREF_KEY)?.let { + focusPreference(it) + arguments?.remove(SettingsActivity.ARG_PREF_KEY) + } } @CallSuper @@ -87,4 +96,31 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : Snackbar.make(listView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT).show() false } + + private fun focusPreference(key: String) { + val pref = findPreference(key) + if (pref == null) { + scrollToPreference(key) + return + } + scrollToPreference(pref) + val prefIndex = preferenceScreen.indexOf(key) + val view = if (prefIndex >= 0) { + listView.findViewHolderForAdapterPosition(prefIndex)?.itemView ?: return + } else { + return + } + view.context.getThemeDrawable(materialR.attr.colorTertiaryContainer)?.let { + view.background = it + } + } + + private fun PreferenceScreen.indexOf(key: String): Int { + for (i in 0 until preferenceCount) { + if (get(i).key == key) { + return i + } + } + return -1 + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/AdapterDelegateClickListenerAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/AdapterDelegateClickListenerAdapter.kt index fd8d865f8..4239c14c4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/AdapterDelegateClickListenerAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/AdapterDelegateClickListenerAdapter.kt @@ -28,6 +28,8 @@ class AdapterDelegateClickListenerAdapter( private fun mappedItem(): O = itemMapper.apply(adapterDelegate.item) + fun attach() = attach(adapterDelegate.itemView) + fun attach(itemView: View) { itemView.setOnClickListener(this) itemView.setOnLongClickListener(this) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt index 0e9e6721e..b24f2d0df 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionFragment.kt @@ -74,6 +74,12 @@ class SearchSuggestionFragment : companion object { + @Deprecated("", + ReplaceWith( + "SearchSuggestionFragment()", + "org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionFragment" + ) + ) fun newInstance() = SearchSuggestionFragment() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt index 1112924e2..c554de7b1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt @@ -6,7 +6,9 @@ import android.net.Uri import android.os.Bundle import android.provider.Settings import android.view.ViewGroup.MarginLayoutParams +import androidx.activity.viewModels import androidx.core.graphics.Insets +import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.fragment.app.Fragment @@ -23,11 +25,17 @@ import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSourceInfo import org.koitharu.kotatsu.core.parser.external.ExternalMangaSource import org.koitharu.kotatsu.core.ui.BaseActivity +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ActivitySettingsBinding import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.settings.about.AboutSettingsFragment +import org.koitharu.kotatsu.settings.search.SettingsItem +import org.koitharu.kotatsu.settings.search.SettingsSearchFragment +import org.koitharu.kotatsu.settings.search.SettingsSearchMenuProvider +import org.koitharu.kotatsu.settings.search.SettingsSearchViewModel import org.koitharu.kotatsu.settings.sources.SourceSettingsFragment import org.koitharu.kotatsu.settings.sources.SourcesSettingsFragment import org.koitharu.kotatsu.settings.sources.manage.SourcesManageFragment @@ -48,6 +56,8 @@ class SettingsActivity : private var screenPadding = 0 + private val viewModel: SettingsSearchViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivitySettingsBinding.inflate(layoutInflater)) @@ -64,6 +74,9 @@ class SettingsActivity : replace(R.id.container_master, RootSettingsFragment()) } } + viewModel.isSearchActive.observe(this, ::toggleSearchMode) + viewModel.onNavigateToPreference.observeEvent(this, ::navigateToPreference) + addMenuProvider(SettingsSearchMenuProvider(viewModel)) addMenuProvider(SettingsMenuProvider(this)) } @@ -97,6 +110,7 @@ class SettingsActivity : } fun openFragment(fragmentClass: Class, args: Bundle?, isFromRoot: Boolean) { + viewModel.discardSearch() val hasFragment = supportFragmentManager.findFragmentById(R.id.container) != null supportFragmentManager.commit { setReorderingAllowed(true) @@ -108,6 +122,27 @@ class SettingsActivity : } } + private fun toggleSearchMode(isEnabled: Boolean) { + viewBinding.containerSearch.isVisible = isEnabled + val searchFragment = supportFragmentManager.findFragmentById(R.id.container_search) + if (searchFragment != null) { + if (!isEnabled) { + invalidateOptionsMenu() + supportFragmentManager.commit { + setReorderingAllowed(true) + remove(searchFragment) + setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) + } + } + } else if (isEnabled) { + supportFragmentManager.commit { + setReorderingAllowed(true) + add(R.id.container_search, SettingsSearchFragment::class.java, null) + setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + } + } + } + private fun openDefaultFragment() { val fragment = when (intent?.action) { ACTION_READER -> ReaderSettingsFragment() @@ -138,6 +173,12 @@ class SettingsActivity : } } + private fun navigateToPreference(item: SettingsItem) { + val args = Bundle(1) + args.putString(ARG_PREF_KEY, item.key) + openFragment(item.fragmentClass, args, true) + } + companion object { private const val ACTION_READER = "${BuildConfig.APPLICATION_ID}.action.MANAGE_READER_SETTINGS" @@ -152,6 +193,7 @@ class SettingsActivity : private const val EXTRA_SOURCE = "source" private const val HOST_ABOUT = "about" private const val HOST_SYNC_SETTINGS = "sync-settings" + const val ARG_PREF_KEY = "pref_key" fun newIntent(context: Context) = Intent(context, SettingsActivity::class.java) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItem.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItem.kt new file mode 100644 index 000000000..f10c342aa --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItem.kt @@ -0,0 +1,16 @@ +package org.koitharu.kotatsu.settings.search + +import androidx.preference.PreferenceFragmentCompat +import org.koitharu.kotatsu.list.ui.model.ListModel + +data class SettingsItem( + val key: String, + val title: CharSequence, + val breadcrumbs: List, + val fragmentClass: Class, +) : ListModel { + + override fun areItemsTheSame(other: ListModel): Boolean { + return other is SettingsItem && other.key == key + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItemAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItemAD.kt new file mode 100644 index 000000000..5a35015c3 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsItemAD.kt @@ -0,0 +1,23 @@ +package org.koitharu.kotatsu.settings.search + +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter +import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.util.ext.textAndVisible +import org.koitharu.kotatsu.databinding.ItemPreferenceBinding + +fun settingsItemAD( + listener: OnListItemClickListener, +) = adapterDelegateViewBinding( + { layoutInflater, parent -> ItemPreferenceBinding.inflate(layoutInflater, parent, false) }, +) { + + AdapterDelegateClickListenerAdapter(this, listener).attach() + val breadcrumbsSeparator = getString(R.string.breadcrumbs_separator) + + bind { + binding.textViewTitle.text = item.title + binding.textViewSummary.textAndVisible = item.breadcrumbs.joinToString(breadcrumbsSeparator) + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchFragment.kt new file mode 100644 index 000000000..4b11f6d5d --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchFragment.kt @@ -0,0 +1,48 @@ +package org.koitharu.kotatsu.settings.search + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.graphics.Insets +import androidx.core.view.updatePadding +import androidx.fragment.app.activityViewModels +import dagger.hilt.android.AndroidEntryPoint +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.ui.BaseFragment +import org.koitharu.kotatsu.core.ui.BaseListAdapter +import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.databinding.FragmentSearchSuggestionBinding +import org.koitharu.kotatsu.list.ui.adapter.ListItemType + +@AndroidEntryPoint +class SettingsSearchFragment : BaseFragment(), OnListItemClickListener { + + private val viewModel: SettingsSearchViewModel by activityViewModels() + + override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSearchSuggestionBinding { + return FragmentSearchSuggestionBinding.inflate(inflater, container, false) + } + + override fun onViewBindingCreated(binding: FragmentSearchSuggestionBinding, savedInstanceState: Bundle?) { + super.onViewBindingCreated(binding, savedInstanceState) + val adapter = BaseListAdapter() + .addDelegate(ListItemType.NAV_ITEM, settingsItemAD(this)) + binding.root.adapter = adapter + binding.root.setHasFixedSize(true) + viewModel.content.observe(viewLifecycleOwner, adapter) + } + + override fun onWindowInsetsChanged(insets: Insets) { + val extraPadding = resources.getDimensionPixelOffset(R.dimen.list_spacing) + requireViewBinding().root.updatePadding( + top = extraPadding, + right = insets.right, + left = insets.left, + bottom = insets.bottom, + ) + } + + override fun onItemClick(item: SettingsItem, view: View) = viewModel.navigateToPreference(item) +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchHelper.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchHelper.kt new file mode 100644 index 000000000..2bdc6871b --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchHelper.kt @@ -0,0 +1,84 @@ +package org.koitharu.kotatsu.settings.search + +import android.annotation.SuppressLint +import android.content.Context +import androidx.annotation.XmlRes +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager +import androidx.preference.PreferenceScreen +import androidx.preference.get +import dagger.Reusable +import dagger.hilt.android.qualifiers.ApplicationContext +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.settings.AppearanceSettingsFragment +import org.koitharu.kotatsu.settings.DownloadsSettingsFragment +import org.koitharu.kotatsu.settings.NetworkSettingsFragment +import org.koitharu.kotatsu.settings.ReaderSettingsFragment +import org.koitharu.kotatsu.settings.ServicesSettingsFragment +import org.koitharu.kotatsu.settings.about.AboutSettingsFragment +import org.koitharu.kotatsu.settings.sources.SourcesSettingsFragment +import org.koitharu.kotatsu.settings.tracker.TrackerSettingsFragment +import org.koitharu.kotatsu.settings.userdata.UserDataSettingsFragment +import javax.inject.Inject + +@Reusable +@SuppressLint("RestrictedApi") +class SettingsSearchHelper @Inject constructor( + @ApplicationContext private val context: Context, +) { + + fun inflatePreferences(): List { + val preferenceManager = PreferenceManager(context) + val result = ArrayList() + preferenceManager.inflateTo(result, R.xml.pref_appearance, emptyList(), AppearanceSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_sources, emptyList(), SourcesSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_reader, emptyList(), ReaderSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_network, emptyList(), NetworkSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_user_data, emptyList(), UserDataSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_downloads, emptyList(), DownloadsSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_tracker, emptyList(), TrackerSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_services, emptyList(), ServicesSettingsFragment::class.java) + preferenceManager.inflateTo(result, R.xml.pref_about, emptyList(), AboutSettingsFragment::class.java) + return result + } + + private fun PreferenceManager.inflateTo( + result: MutableList, + @XmlRes resId: Int, + breadcrumbs: List, + fragmentClass: Class + ) { + val screen = inflateFromResource(context, resId, null) + val screenTitle = screen.title?.toString() + screen.inflateTo( + result = result, + breadcrumbs = if (screenTitle.isNullOrEmpty()) breadcrumbs else breadcrumbs + screenTitle, + fragmentClass = fragmentClass, + ) + } + + private fun PreferenceScreen.inflateTo( + result: MutableList, + breadcrumbs: List, + fragmentClass: Class + ): Unit = repeat(preferenceCount) { i -> + val pref = this[i] + if (pref is PreferenceScreen) { + val screenTitle = pref.title?.toString() + pref.inflateTo( + result = result, + breadcrumbs = if (screenTitle.isNullOrEmpty()) breadcrumbs else breadcrumbs + screenTitle, + fragmentClass = fragmentClass, + ) + } else { + result.add( + SettingsItem( + key = pref.key ?: return@repeat, + title = pref.title ?: return@repeat, + breadcrumbs = breadcrumbs, + fragmentClass = fragmentClass, + ), + ) + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchMenuProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchMenuProvider.kt new file mode 100644 index 000000000..7f2f4527e --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchMenuProvider.kt @@ -0,0 +1,51 @@ +package org.koitharu.kotatsu.settings.search + +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import androidx.appcompat.widget.SearchView +import androidx.core.view.MenuProvider +import org.koitharu.kotatsu.R + +class SettingsSearchMenuProvider( + private val viewModel: SettingsSearchViewModel, +) : MenuProvider, MenuItem.OnActionExpandListener, SearchView.OnQueryTextListener { + + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.opt_search, menu) + val menuItem = menu.findItem(R.id.action_search) + menuItem.setOnActionExpandListener(this) + val searchView = menuItem.actionView as SearchView + searchView.setOnQueryTextListener(this) + searchView.queryHint = menuItem.title + } + + override fun onPrepareMenu(menu: Menu) { + super.onPrepareMenu(menu) + val currentQuery = viewModel.currentQuery + if (currentQuery.isNotEmpty()) { + val menuItem = menu.findItem(R.id.action_search) + menuItem.expandActionView() + val searchView = menuItem.actionView as SearchView + searchView.setQuery(currentQuery, false) + } + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean = false + + override fun onMenuItemActionExpand(item: MenuItem): Boolean = true + + override fun onMenuItemActionCollapse(item: MenuItem): Boolean { + viewModel.discardSearch() + return true + } + + override fun onQueryTextSubmit(query: String?): Boolean { + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + viewModel.onQueryChanged(newText.orEmpty()) + return true + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchViewModel.kt new file mode 100644 index 000000000..6be04636a --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/search/SettingsSearchViewModel.kt @@ -0,0 +1,47 @@ +package org.koitharu.kotatsu.settings.search + +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.plus +import org.koitharu.kotatsu.core.ui.BaseViewModel +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call +import javax.inject.Inject + +@HiltViewModel +class SettingsSearchViewModel @Inject constructor( + private val searchHelper: SettingsSearchHelper, +) : BaseViewModel() { + + private val query = MutableStateFlow("") + private val allSettings by lazy { + searchHelper.inflatePreferences() + } + + val content = query.map { q -> + allSettings.filter { it.title.contains(q, ignoreCase = true) } + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, emptyList()) + + val isSearchActive = query.map { + it.isNotEmpty() + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, false) + + val onNavigateToPreference = MutableEventFlow() + val currentQuery: String + get() = query.value + + fun onQueryChanged(value: String) { + query.value = value + } + + fun discardSearch() = onQueryChanged("") + + fun navigateToPreference(item: SettingsItem) { + onNavigateToPreference.call(item) + } +} diff --git a/app/src/main/res/layout-w600dp-land/activity_settings.xml b/app/src/main/res/layout-w600dp-land/activity_settings.xml index 244fedc9d..1800be1f7 100644 --- a/app/src/main/res/layout-w600dp-land/activity_settings.xml +++ b/app/src/main/res/layout-w600dp-land/activity_settings.xml @@ -72,4 +72,15 @@ app:layout_constraintStart_toEndOf="@id/container_master" app:layout_constraintTop_toTopOf="parent" /> + + diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 897aef412..cb1fa645d 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -26,4 +26,11 @@ android:layout_height="match_parent" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> + + diff --git a/app/src/main/res/layout/item_preference.xml b/app/src/main/res/layout/item_preference.xml new file mode 100644 index 000000000..bfdb5e519 --- /dev/null +++ b/app/src/main/res/layout/item_preference.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/app/src/main/res/values-ldrtl/strings.xml b/app/src/main/res/values-ldrtl/strings.xml new file mode 100644 index 000000000..0a880c218 --- /dev/null +++ b/app/src/main/res/values-ldrtl/strings.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8f2623743..5d9314ded 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -757,4 +757,5 @@ Screen orientation Portrait Landscape + "]]> diff --git a/app/src/main/res/xml/pref_about.xml b/app/src/main/res/xml/pref_about.xml index aa3e7c27f..5ffc99411 100644 --- a/app/src/main/res/xml/pref_about.xml +++ b/app/src/main/res/xml/pref_about.xml @@ -1,7 +1,8 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/about"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/appearance"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/periodic_backups"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/notifications"> - \ No newline at end of file + diff --git a/app/src/main/res/xml/pref_proxy.xml b/app/src/main/res/xml/pref_proxy.xml index 97dd22002..38391805e 100644 --- a/app/src/main/res/xml/pref_proxy.xml +++ b/app/src/main/res/xml/pref_proxy.xml @@ -1,7 +1,8 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/proxy"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/reader_settings"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/services"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/remote_sources"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/suggestions"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/check_for_new_chapters"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:title="@string/data_and_privacy">