compose: Remove epoxy and view related logic for searching
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -67,7 +67,7 @@ fun DevProfileScreen(
|
|||||||
) {
|
) {
|
||||||
val apps = viewModel.apps.collectAsLazyPagingItems()
|
val apps = viewModel.apps.collectAsLazyPagingItems()
|
||||||
|
|
||||||
LaunchedEffect(key1 = Unit) { viewModel.newSearch("pub:$publisherId") }
|
LaunchedEffect(key1 = Unit) { viewModel.search("pub:$publisherId") }
|
||||||
|
|
||||||
ScreenContent(
|
ScreenContent(
|
||||||
apps = apps,
|
apps = apps,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ fun SearchScreen(onNavigateUp: () -> Unit, viewModel: SearchViewModel = hiltView
|
|||||||
suggestions = suggestions,
|
suggestions = suggestions,
|
||||||
results = results,
|
results = results,
|
||||||
onNavigateUp = onNavigateUp,
|
onNavigateUp = onNavigateUp,
|
||||||
onSearch = { query -> viewModel.newSearch(query) },
|
onSearch = { query -> viewModel.search(query) },
|
||||||
onFetchSuggestions = { query -> viewModel.fetchSuggestions(query) }
|
onFetchSuggestions = { query -> viewModel.fetchSuggestions(query) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,8 @@ private fun ScreenContent(
|
|||||||
suggestions.forEach { suggestion ->
|
suggestions.forEach { suggestion ->
|
||||||
SearchSuggestionComposable(
|
SearchSuggestionComposable(
|
||||||
searchSuggestEntry = suggestion,
|
searchSuggestEntry = suggestion,
|
||||||
onClick = { query -> onRequestSearch(query) }
|
onClick = { query -> onRequestSearch(query) },
|
||||||
|
onAction = { query -> currentQuery = query.trim() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,8 +31,10 @@ import androidx.fragment.app.viewModels
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
import com.aurora.extensions.navigate
|
||||||
import com.aurora.store.MobileNavigationDirections
|
import com.aurora.store.MobileNavigationDirections
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.compose.navigation.Screen
|
||||||
import com.aurora.store.databinding.FragmentAppsGamesBinding
|
import com.aurora.store.databinding.FragmentAppsGamesBinding
|
||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Preferences
|
||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
import com.aurora.store.view.ui.commons.BaseFragment
|
||||||
@@ -113,7 +115,7 @@ class GamesContainerFragment : BaseFragment<FragmentAppsGamesBinding>() {
|
|||||||
}.attach()
|
}.attach()
|
||||||
|
|
||||||
binding.searchFab.setOnClickListener {
|
binding.searchFab.setOnClickListener {
|
||||||
findNavController().navigate(R.id.searchSuggestionFragment)
|
requireContext().navigate(Screen.Search)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,9 +30,11 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.aurora.Constants
|
import com.aurora.Constants
|
||||||
import com.aurora.extensions.browse
|
import com.aurora.extensions.browse
|
||||||
|
import com.aurora.extensions.navigate
|
||||||
import com.aurora.extensions.requiresObbDir
|
import com.aurora.extensions.requiresObbDir
|
||||||
import com.aurora.store.MobileNavigationDirections
|
import com.aurora.store.MobileNavigationDirections
|
||||||
import com.aurora.store.R
|
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.MinimalApp
|
||||||
import com.aurora.store.data.model.PermissionType
|
import com.aurora.store.data.model.PermissionType
|
||||||
import com.aurora.store.data.room.download.Download
|
import com.aurora.store.data.room.download.Download
|
||||||
@@ -109,7 +111,7 @@ class UpdatesFragment : BaseFragment<FragmentUpdatesBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.searchFab.setOnClickListener {
|
binding.searchFab.setOnClickListener {
|
||||||
findNavController().navigate(R.id.searchSuggestionFragment)
|
requireContext().navigate(Screen.Search)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,20 +20,16 @@
|
|||||||
package com.aurora.store.viewmodel.search
|
package com.aurora.store.viewmodel.search
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import com.aurora.gplayapi.SearchSuggestEntry
|
import com.aurora.gplayapi.SearchSuggestEntry
|
||||||
import com.aurora.gplayapi.data.models.App
|
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.data.models.StreamCluster
|
||||||
import com.aurora.gplayapi.helpers.SearchHelper
|
import com.aurora.gplayapi.helpers.SearchHelper
|
||||||
import com.aurora.gplayapi.helpers.contracts.SearchContract
|
import com.aurora.gplayapi.helpers.contracts.SearchContract
|
||||||
import com.aurora.gplayapi.helpers.web.WebSearchHelper
|
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.paging.GenericPagingSource.Companion.createPager
|
||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.providers.AuthProvider
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
@@ -44,8 +40,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import kotlinx.coroutines.sync.withLock
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@@ -57,10 +51,6 @@ class SearchViewModel @Inject constructor(
|
|||||||
|
|
||||||
private val TAG = SearchViewModel::class.java.simpleName
|
private val TAG = SearchViewModel::class.java.simpleName
|
||||||
|
|
||||||
val liveData: MutableLiveData<ViewState> = MutableLiveData()
|
|
||||||
|
|
||||||
private val stash: AppStreamStash = mutableMapOf()
|
|
||||||
|
|
||||||
private val contract: SearchContract
|
private val contract: SearchContract
|
||||||
get() = if (authProvider.isAnonymous) webSearchHelper else searchHelper
|
get() = if (authProvider.isAnonymous) webSearchHelper else searchHelper
|
||||||
|
|
||||||
@@ -70,9 +60,7 @@ class SearchViewModel @Inject constructor(
|
|||||||
private val _apps = MutableStateFlow<PagingData<App>>(PagingData.empty())
|
private val _apps = MutableStateFlow<PagingData<App>>(PagingData.empty())
|
||||||
val apps = _apps.asStateFlow()
|
val apps = _apps.asStateFlow()
|
||||||
|
|
||||||
private val stashMutex = Mutex()
|
fun search(query: String) {
|
||||||
|
|
||||||
fun newSearch(query: String) {
|
|
||||||
var nextBundleUrl: String? = null
|
var nextBundleUrl: String? = null
|
||||||
val nextStreamUrls = mutableSetOf<String>()
|
val nextStreamUrls = mutableSetOf<String>()
|
||||||
|
|
||||||
@@ -128,138 +116,4 @@ class SearchViewModel @Inject constructor(
|
|||||||
_suggestions.value = contract.searchSuggestions(query)
|
_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) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -110,31 +110,6 @@
|
|||||||
android:name="com.aurora.store.view.ui.preferences.updates.UpdatesPreference"
|
android:name="com.aurora.store.view.ui.preferences.updates.UpdatesPreference"
|
||||||
android:label="UpdatesPreference"
|
android:label="UpdatesPreference"
|
||||||
tools:layout="@layout/fragment_setting" />
|
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
|
<fragment
|
||||||
android:id="@+id/downloadFragment"
|
android:id="@+id/downloadFragment"
|
||||||
android:name="com.aurora.store.view.ui.downloads.DownloadFragment"
|
android:name="com.aurora.store.view.ui.downloads.DownloadFragment"
|
||||||
|
|||||||
Reference in New Issue
Block a user