compose: Remove epoxy and view related logic for searching

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2025-08-19 15:16:26 +08:00
parent 1e4820d53d
commit 0432dc0f00
13 changed files with 11 additions and 799 deletions

View File

@@ -67,7 +67,7 @@ fun DevProfileScreen(
) {
val apps = viewModel.apps.collectAsLazyPagingItems()
LaunchedEffect(key1 = Unit) { viewModel.newSearch("pub:$publisherId") }
LaunchedEffect(key1 = Unit) { viewModel.search("pub:$publisherId") }
ScreenContent(
apps = apps,

View File

@@ -72,7 +72,7 @@ fun SearchScreen(onNavigateUp: () -> Unit, viewModel: SearchViewModel = hiltView
suggestions = suggestions,
results = results,
onNavigateUp = onNavigateUp,
onSearch = { query -> viewModel.newSearch(query) },
onSearch = { query -> viewModel.search(query) },
onFetchSuggestions = { query -> viewModel.fetchSuggestions(query) }
)
}
@@ -159,7 +159,8 @@ private fun ScreenContent(
suggestions.forEach { suggestion ->
SearchSuggestionComposable(
searchSuggestEntry = suggestion,
onClick = { query -> onRequestSearch(query) }
onClick = { query -> onRequestSearch(query) },
onAction = { query -> currentQuery = query.trim() }
)
}
}

View File

@@ -1,72 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
*
* Aurora Store is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Aurora Store is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.aurora.store.view.epoxy.views
import android.content.Context
import android.util.AttributeSet
import androidx.core.content.ContextCompat
import coil3.load
import coil3.request.transformations
import coil3.transform.RoundedCornersTransformation
import com.airbnb.epoxy.CallbackProp
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.store.R
import com.aurora.store.databinding.ViewSearchSuggestionBinding
@ModelView(
autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT,
baseModelClass = BaseModel::class
)
class SearchSuggestionView @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : BaseView<ViewSearchSuggestionBinding>(context, attrs, defStyleAttr) {
@ModelProp
fun entry(searchSuggestEntry: SearchSuggestEntry) {
if (searchSuggestEntry.hasImageContainer()) {
binding.img.load(searchSuggestEntry.imageContainer.imageUrl) {
transformations(RoundedCornersTransformation(8F))
}
} else {
binding.img.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.ic_search_suggestion
)
)
}
binding.txtTitle.text = searchSuggestEntry.title
}
@CallbackProp
fun click(onClickListener: OnClickListener?) {
binding.root.setOnClickListener(onClickListener)
}
@CallbackProp
fun action(onClickListener: OnClickListener?) {
binding.action.setOnClickListener(onClickListener)
}
}

View File

@@ -31,8 +31,10 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.navigation.fragment.findNavController
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.aurora.extensions.navigate
import com.aurora.store.MobileNavigationDirections
import com.aurora.store.R
import com.aurora.store.compose.navigation.Screen
import com.aurora.store.databinding.FragmentAppsGamesBinding
import com.aurora.store.util.Preferences
import com.aurora.store.view.ui.commons.BaseFragment
@@ -113,7 +115,7 @@ class GamesContainerFragment : BaseFragment<FragmentAppsGamesBinding>() {
}.attach()
binding.searchFab.setOnClickListener {
findNavController().navigate(R.id.searchSuggestionFragment)
requireContext().navigate(Screen.Search)
}
}

View File

@@ -1,162 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
*
* Aurora Store is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Aurora Store is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.aurora.store.view.ui.search
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.aurora.extensions.hideKeyboard
import com.aurora.extensions.showKeyboard
import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.StreamCluster
import com.aurora.store.AppStreamStash
import com.aurora.store.R
import com.aurora.store.data.model.ViewState
import com.aurora.store.data.model.ViewState.Loading.getDataAs
import com.aurora.store.databinding.FragmentSearchResultBinding
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener
import com.aurora.store.view.epoxy.controller.GenericCarouselController
import com.aurora.store.view.epoxy.controller.SearchCarouselController
import com.aurora.store.view.ui.commons.BaseFragment
import com.aurora.store.viewmodel.search.SearchViewModel
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class SearchResultsFragment : BaseFragment<FragmentSearchResultBinding>(),
GenericCarouselController.Callbacks {
private val viewModel: SearchViewModel by activityViewModels()
private val controller = SearchCarouselController(this)
private var query: String
get() = requireArguments().getString("query").orEmpty()
set(value) = requireArguments().putString("query", value)
private var scrollListener: EndlessRecyclerOnScrollListener =
object : EndlessRecyclerOnScrollListener(visibleThreshold = 4) {
override fun onLoadMore(currentPage: Int) {
viewModel.observe(query)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Search
attachSearch()
with(binding) {
toolbar.apply {
setNavigationOnClickListener {
binding.searchBar.hideKeyboard()
findNavController().navigateUp()
}
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_clear -> {
binding.searchBar.text?.clear()
binding.searchBar.showKeyboard()
}
R.id.action_download -> findNavController().navigate(R.id.downloadFragment)
}
true
}
}
recycler.setController(controller)
recycler.addOnScrollListener(scrollListener)
}
with(viewModel) {
search(query)
liveData.observe(viewLifecycleOwner) {
when (it) {
is ViewState.Loading -> {
controller.setData(null)
}
is ViewState.Success<*> -> {
val stash = it.getDataAs<AppStreamStash>()
controller.setData(stash[query])
}
else -> {}
}
}
}
}
private fun attachSearch() {
binding.searchBar.text = Editable.Factory.getInstance().newEditable(query)
binding.searchBar.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
binding.toolbar.menu.findItem(R.id.action_clear)?.isVisible = s.isNotBlank()
}
override fun afterTextChanged(s: Editable) {}
})
binding.searchBar.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
if (actionId == EditorInfo.IME_ACTION_SEARCH
|| actionId == KeyEvent.ACTION_DOWN
|| actionId == KeyEvent.KEYCODE_ENTER
) {
query = binding.searchBar.text.toString()
queryViewModel(query)
return@setOnEditorActionListener true
}
false
}
}
private fun queryViewModel(query: String) {
scrollListener.resetPageCount()
viewModel.search(query)
}
override fun onHeaderClicked(streamCluster: StreamCluster) {
openStreamBrowseFragment(streamCluster)
}
override fun onClusterScrolled(streamCluster: StreamCluster) {
viewModel.observeCluster(query, streamCluster)
}
override fun onAppClick(app: App) {
openDetailsFragment(app.packageName)
}
override fun onAppLongClick(app: App) {
}
}

View File

@@ -1,145 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
*
* Aurora Store is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Aurora Store is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.aurora.store.view.ui.search
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.aurora.extensions.hideKeyboard
import com.aurora.extensions.showKeyboard
import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.store.R
import com.aurora.store.databinding.FragmentSearchSuggestionBinding
import com.aurora.store.view.epoxy.views.SearchSuggestionViewModel_
import com.aurora.store.view.ui.commons.BaseFragment
import com.aurora.store.viewmodel.search.SearchSuggestionViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@AndroidEntryPoint
class SearchSuggestionFragment : BaseFragment<FragmentSearchSuggestionBinding>() {
private val viewModel: SearchSuggestionViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Toolbar
binding.toolbar.apply {
setNavigationOnClickListener {
binding.searchBar.hideKeyboard()
findNavController().navigateUp()
}
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_clear -> binding.searchBar.text?.clear()
R.id.action_download -> findNavController().navigate(R.id.downloadFragment)
}
true
}
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.searchSuggestions.collectLatest {
updateController(it)
}
}
setupSearch()
}
override fun onResume() {
super.onResume()
binding.searchBar.showKeyboard()
}
private fun updateController(searchSuggestions: List<SearchSuggestEntry>) {
binding.recycler.withModels {
setFilterDuplicates(true)
searchSuggestions.forEach {
add(
SearchSuggestionViewModel_()
.id(it.title)
.entry(it)
.action { _ ->
updateQuery(it.title)
}
.click { _ ->
binding.searchBar.hideKeyboard()
search(it.title)
}
)
}
}
}
private fun setupSearch() {
binding.searchBar.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (s.isNotEmpty()) {
val query = s.toString()
if (query.isNotEmpty()) {
viewModel.observeStreamBundles(query)
}
}
binding.toolbar.menu.findItem(R.id.action_clear)?.isVisible = s.isNotBlank()
}
override fun afterTextChanged(s: Editable) {}
})
binding.searchBar.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
if (actionId == EditorInfo.IME_ACTION_SEARCH
|| actionId == KeyEvent.ACTION_DOWN
|| actionId == KeyEvent.KEYCODE_ENTER
) {
val query = binding.searchBar.text.toString()
if (query.isNotEmpty()) {
binding.searchBar.hideKeyboard()
search(query)
return@setOnEditorActionListener true
}
}
false
}
}
private fun updateQuery(query: String) {
binding.searchBar.text = Editable.Factory.getInstance().newEditable(query)
binding.searchBar.setSelection(query.length)
}
private fun search(query: String) {
findNavController().navigate(
SearchSuggestionFragmentDirections
.actionSearchSuggestionFragmentToSearchResultsFragment(query)
)
}
}

View File

@@ -30,9 +30,11 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.aurora.Constants
import com.aurora.extensions.browse
import com.aurora.extensions.navigate
import com.aurora.extensions.requiresObbDir
import com.aurora.store.MobileNavigationDirections
import com.aurora.store.R
import com.aurora.store.compose.navigation.Screen
import com.aurora.store.data.model.MinimalApp
import com.aurora.store.data.model.PermissionType
import com.aurora.store.data.room.download.Download
@@ -109,7 +111,7 @@ class UpdatesFragment : BaseFragment<FragmentUpdatesBinding>() {
}
binding.searchFab.setOnClickListener {
findNavController().navigate(R.id.searchSuggestionFragment)
requireContext().navigate(Screen.Search)
}
}

View File

@@ -1,54 +0,0 @@
/*
* Aurora Store
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
*
* Aurora Store is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Aurora Store is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.aurora.store.viewmodel.search
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.gplayapi.helpers.SearchHelper
import com.aurora.gplayapi.helpers.contracts.SearchContract
import com.aurora.gplayapi.helpers.web.WebSearchHelper
import com.aurora.store.data.providers.AuthProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class SearchSuggestionViewModel @Inject constructor(
private val authProvider: AuthProvider,
private val searchHelper: SearchHelper,
private val webSearchHelper: WebSearchHelper
) : ViewModel() {
private val _searchSuggestions = MutableStateFlow<List<SearchSuggestEntry>>(emptyList())
val searchSuggestions = _searchSuggestions.asStateFlow()
private val helper: SearchContract
get() = if (authProvider.isAnonymous) webSearchHelper else searchHelper
fun observeStreamBundles(query: String) {
viewModelScope.launch(Dispatchers.IO) {
_searchSuggestions.value = helper.searchSuggestions(query)
}
}
}

View File

@@ -20,20 +20,16 @@
package com.aurora.store.viewmodel.search
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.StreamBundle
import com.aurora.gplayapi.data.models.StreamCluster
import com.aurora.gplayapi.helpers.SearchHelper
import com.aurora.gplayapi.helpers.contracts.SearchContract
import com.aurora.gplayapi.helpers.web.WebSearchHelper
import com.aurora.store.AppStreamStash
import com.aurora.store.data.model.ViewState
import com.aurora.store.data.paging.GenericPagingSource.Companion.createPager
import com.aurora.store.data.providers.AuthProvider
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -44,8 +40,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import javax.inject.Inject
@HiltViewModel
@@ -57,10 +51,6 @@ class SearchViewModel @Inject constructor(
private val TAG = SearchViewModel::class.java.simpleName
val liveData: MutableLiveData<ViewState> = MutableLiveData()
private val stash: AppStreamStash = mutableMapOf()
private val contract: SearchContract
get() = if (authProvider.isAnonymous) webSearchHelper else searchHelper
@@ -70,9 +60,7 @@ class SearchViewModel @Inject constructor(
private val _apps = MutableStateFlow<PagingData<App>>(PagingData.empty())
val apps = _apps.asStateFlow()
private val stashMutex = Mutex()
fun newSearch(query: String) {
fun search(query: String) {
var nextBundleUrl: String? = null
val nextStreamUrls = mutableSetOf<String>()
@@ -128,138 +116,4 @@ class SearchViewModel @Inject constructor(
_suggestions.value = contract.searchSuggestions(query)
}
}
@Synchronized
fun search(query: String) {
viewModelScope.launch(Dispatchers.IO) {
try {
stashMutex.withLock {
liveData.postValue(ViewState.Loading)
var bundle = targetBundle(query)
// Post existing data if any clusters exist
if (bundle.hasCluster()) {
liveData.postValue(ViewState.Success(stash.toMap()))
return@launch
}
// Fetch new stream bundle
val newBundle = contract.searchResults(query)
bundle = bundle.copy(
streamClusters = newBundle.streamClusters,
streamNextPageUrl = newBundle.streamNextPageUrl
)
stash[query] = bundle
liveData.postValue(ViewState.Success(stash.toMap()))
}
} catch (e: Exception) {
liveData.postValue(ViewState.Error(e.message))
}
}
}
fun observe(query: String) {
viewModelScope.launch(Dispatchers.IO) {
try {
stashMutex.withLock {
var bundle = targetBundle(query)
if (bundle.hasNext()) {
val newBundle = contract.nextStreamBundle(
query,
bundle.streamNextPageUrl
)
// Update old bundle
bundle = bundle.copy(
streamClusters = bundle.streamClusters + newBundle.streamClusters,
streamNextPageUrl = newBundle.streamNextPageUrl
)
stash[query] = bundle
liveData.postValue(ViewState.Success(stash.toMap()))
} else {
Log.i(TAG, "End of Bundle")
// If stream ends, likely there are clusters that need to be processed
bundle.streamClusters.values.forEach {
if (it.clusterNextPageUrl.isEmpty()) {
postClusterEnd(query, it.id)
}
// Empty title or query as title indicates main stream cluster
if (it.clusterTitle.isEmpty() or (it.clusterTitle == bundle.streamTitle)) {
observeCluster(query, it)
}
}
}
}
} catch (e: Exception) {
liveData.postValue(ViewState.Error(e.message))
}
}
}
fun observeCluster(query: String, streamCluster: StreamCluster) {
viewModelScope.launch(Dispatchers.IO) {
try {
if (streamCluster.hasNext()) {
val newCluster = contract.nextStreamCluster(
query,
streamCluster.clusterNextPageUrl
)
stashMutex.withLock {
updateCluster(query, streamCluster.id, newCluster)
}
liveData.postValue(ViewState.Success(stash.toMap()))
} else {
stashMutex.withLock {
postClusterEnd(query, streamCluster.id)
}
liveData.postValue(ViewState.Success(stash.toMap()))
}
} catch (e: Exception) {
liveData.postValue(ViewState.Error(e.message))
}
}
}
private fun updateCluster(query: String, clusterID: Int, newCluster: StreamCluster) {
val bundle = stash[query] ?: return
val oldCluster = bundle.streamClusters[clusterID] ?: return
val mergedCluster = oldCluster.copy(
clusterNextPageUrl = newCluster.clusterNextPageUrl,
clusterAppList = oldCluster.clusterAppList + newCluster.clusterAppList
)
val updatedClusters = bundle.streamClusters.toMutableMap().apply {
this[clusterID] = mergedCluster
}
stash[query] = bundle.copy(streamClusters = updatedClusters)
}
private fun postClusterEnd(query: String, clusterID: Int) {
val bundle = stash[query] ?: return
val oldCluster = bundle.streamClusters[clusterID] ?: return
val updatedCluster = oldCluster.copy(clusterNextPageUrl = "")
val updatedClusters = bundle.streamClusters.toMutableMap().apply {
this[clusterID] = updatedCluster
}
stash[query] = bundle.copy(streamClusters = updatedClusters)
}
private fun targetBundle(query: String): StreamBundle {
return stash.getOrPut(query.trim()) { StreamBundle(streamTitle = query) }
}
}

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Aurora Store
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
~
~ Aurora Store is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 2 of the License, or
~ (at your option) any later version.
~
~ Aurora Store is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
~
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.ui.search.SearchResultsFragment">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:menu="@menu/menu_search"
app:navigationIcon="@drawable/ic_arrow_back">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/searchBar"
android:layout_width="match_parent"
android:layout_height="42dp"
android:background="@null"
android:hint="@string/search_hint"
android:imeOptions="flagNoExtractUi|actionSearch"
android:inputType="text"
android:paddingStart="@dimen/padding_large"
android:paddingEnd="@dimen/padding_normal"
android:singleLine="true" />
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar" />
<com.airbnb.epoxy.EpoxyRecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/divider"
android:clipToPadding="true"
android:paddingTop="@dimen/padding_normal"
android:paddingBottom="@dimen/height_bottom_adj"
tools:listitem="@layout/view_app_list" />
</RelativeLayout>

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Aurora Store
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
~
~ Aurora Store is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 2 of the License, or
~ (at your option) any later version.
~
~ Aurora Store is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
~
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.ui.search.SearchSuggestionFragment">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:menu="@menu/menu_search"
app:navigationIcon="@drawable/ic_arrow_back">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/searchBar"
android:layout_width="match_parent"
android:layout_height="42dp"
android:background="@null"
android:hint="@string/search_hint"
android:imeOptions="flagNoExtractUi|actionSearch"
android:inputType="text"
android:paddingStart="@dimen/padding_large"
android:paddingEnd="@dimen/padding_normal"
android:singleLine="true" />
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar" />
<com.airbnb.epoxy.EpoxyRecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/divider"
tools:listitem="@layout/view_search_suggestion" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Aurora Store
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
~
~ Aurora Store is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 2 of the License, or
~ (at your option) any later version.
~
~ Aurora Store is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
~
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:padding="@dimen/padding_large">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/img"
android:layout_width="@dimen/icon_size_default"
android:layout_height="@dimen/icon_size_default"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/margin_normal"
tools:src="@drawable/ic_search_suggestion" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/margin_small"
android:layout_marginEnd="@dimen/margin_small"
android:layout_toStartOf="@id/action"
android:layout_toEndOf="@id/img"
android:gravity="start|center"
android:textAppearance="@style/TextAppearance.Aurora.Line1"
tools:text="Line1" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/action"
android:layout_width="@dimen/icon_size_default"
android:layout_height="@dimen/icon_size_default"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_search_append"
app:tint="?colorControlNormal" />
</RelativeLayout>

View File

@@ -110,31 +110,6 @@
android:name="com.aurora.store.view.ui.preferences.updates.UpdatesPreference"
android:label="UpdatesPreference"
tools:layout="@layout/fragment_setting" />
<fragment
android:id="@+id/searchSuggestionFragment"
android:name="com.aurora.store.view.ui.search.SearchSuggestionFragment"
android:label="@string/title_search_suggestion"
tools:layout="@layout/fragment_search_suggestion">
<action
android:id="@+id/action_searchSuggestionFragment_to_searchResultsFragment"
app:destination="@id/searchResultsFragment" />
</fragment>
<fragment
android:id="@+id/searchResultsFragment"
android:name="com.aurora.store.view.ui.search.SearchResultsFragment"
android:label="@string/title_search_results"
tools:layout="@layout/fragment_search_result">
<argument
android:name="query"
app:argType="string" />
<!-- Google Play -->
<deepLink
app:action="android.intent.action.VIEW"
app:uri="play.google.com/store/search?q={query}" />
<action
android:id="@+id/action_searchSuggestionFragment_to_searchResultsFragment"
app:destination="@id/searchResultsFragment" />
</fragment>
<fragment
android:id="@+id/downloadFragment"
android:name="com.aurora.store.view.ui.downloads.DownloadFragment"