compose: favourite: Initial migration

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2025-09-22 14:46:38 +08:00
parent 78d029b8e8
commit e8a1e18750
17 changed files with 330 additions and 348 deletions

View File

@@ -27,6 +27,7 @@ import com.aurora.store.compose.ui.commons.PermissionRationaleScreen
import com.aurora.store.compose.ui.details.AppDetailsScreen
import com.aurora.store.compose.ui.dev.DevProfileScreen
import com.aurora.store.compose.ui.downloads.DownloadsScreen
import com.aurora.store.compose.ui.favourite.FavouriteScreen
import com.aurora.store.compose.ui.search.SearchScreen
/**
@@ -114,6 +115,15 @@ fun NavDisplay(startDestination: NavKey) {
entry<Screen.About> {
AboutScreen(onNavigateUp = { onNavigateUp() })
}
entry<Screen.Favourite> {
FavouriteScreen(
onNavigateUp = { onNavigateUp() },
onNavigateToAppDetails = { packageName ->
backstack.add(Screen.AppDetails(packageName))
}
)
}
}
)
}

View File

@@ -47,4 +47,7 @@ sealed class Screen : NavKey, Parcelable {
@Serializable
data object About : Screen()
@Serializable
data object Favourite : Screen()
}

View File

@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2025 The Calyx Institute
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.aurora.store.compose.preview
import androidx.compose.runtime.Composable
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import kotlinx.coroutines.flow.flowOf
/**
* Empty lazy paging item flow for optional methods
*/
@Composable
fun <T: Any> emptyPagingItems(): LazyPagingItems<T> {
return flowOf(PagingData.empty<T>()).collectAsLazyPagingItems()
}

View File

@@ -49,6 +49,7 @@ import com.aurora.store.compose.composables.TopAppBarComposable
import com.aurora.store.compose.composables.details.ReviewComposable
import com.aurora.store.compose.preview.ReviewPreviewProvider
import com.aurora.store.compose.preview.coilPreviewProvider
import com.aurora.store.compose.preview.emptyPagingItems
import com.aurora.store.viewmodel.details.AppDetailsViewModel
import com.aurora.store.viewmodel.details.ReviewViewModel
import kotlinx.coroutines.flow.MutableStateFlow
@@ -87,7 +88,7 @@ fun ReviewScreen(
private fun ScreenContent(
topAppBarTitle: String? = null,
onNavigateUp: () -> Unit = {},
reviews: LazyPagingItems<Review>,
reviews: LazyPagingItems<Review> = emptyPagingItems(),
onFilter: (filter: Review.Filter) -> Unit = {},
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
) {

View File

@@ -25,7 +25,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.paging.LoadState
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
@@ -35,11 +34,11 @@ import com.aurora.store.compose.composables.DownloadComposable
import com.aurora.store.compose.composables.ErrorComposable
import com.aurora.store.compose.composables.ProgressComposable
import com.aurora.store.compose.composables.TopAppBarComposable
import com.aurora.store.compose.preview.emptyPagingItems
import com.aurora.store.compose.ui.downloads.menu.DownloadsMenu
import com.aurora.store.compose.ui.downloads.menu.MenuItem
import com.aurora.store.data.room.download.Download
import com.aurora.store.viewmodel.downloads.DownloadsViewModel
import kotlinx.coroutines.flow.flowOf
@Composable
fun DownloadsScreen(
@@ -85,7 +84,7 @@ fun DownloadsScreen(
@Composable
private fun ScreenContent(
downloads: LazyPagingItems<Download> = flowOf(PagingData.empty<Download>()).collectAsLazyPagingItems(),
downloads: LazyPagingItems<Download> = emptyPagingItems(),
onNavigateUp: () -> Unit = {},
onNavigateToAppDetails: (packageName: String) -> Unit = {},
onCancel: (packageName: String) -> Unit = {},

View File

@@ -0,0 +1,169 @@
/*
* SPDX-FileCopyrightText: 2025 The Calyx Institute
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.aurora.store.compose.ui.favourite
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.aurora.Constants.JSON_MIME_TYPE
import com.aurora.extensions.toast
import com.aurora.store.R
import com.aurora.store.compose.composables.ErrorComposable
import com.aurora.store.compose.composables.FavouriteComposable
import com.aurora.store.compose.composables.ProgressComposable
import com.aurora.store.compose.composables.TopAppBarComposable
import com.aurora.store.compose.preview.emptyPagingItems
import com.aurora.store.compose.ui.favourite.menu.FavouriteMenu
import com.aurora.store.compose.ui.favourite.menu.MenuItem
import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.viewmodel.all.FavouriteViewModel
import java.util.Calendar
@Composable
fun FavouriteScreen(
onNavigateUp: () -> Unit,
onNavigateToAppDetails: (packageName: String) -> Unit,
viewModel: FavouriteViewModel = hiltViewModel()
) {
val context = LocalContext.current
val favourites = viewModel.favourites.collectAsLazyPagingItems()
val documentOpenLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument(),
onResult = {
if (it != null) {
viewModel.importFavourites(it)
context.toast(R.string.toast_fav_import_success)
} else {
context.toast(R.string.toast_fav_import_failed)
}
}
)
val documentCreateLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.CreateDocument(JSON_MIME_TYPE),
onResult = {
if (it != null) {
viewModel.exportFavourites(it)
context.toast(R.string.toast_fav_export_success)
} else {
context.toast(R.string.toast_fav_export_failed)
}
}
)
ScreenContent(
favourites = favourites,
onNavigateUp = onNavigateUp,
onNavigateToAppDetails = onNavigateToAppDetails,
onRemoveFavourite = { packageName -> viewModel.removeFavourite(packageName) },
onImportFavourites = {
documentOpenLauncher.launch(arrayOf(JSON_MIME_TYPE))
},
onExportFavourites = {
documentCreateLauncher.launch(
"aurora_store_favourites_${Calendar.getInstance().time.time}.json"
)
}
)
}
@Composable
private fun ScreenContent(
favourites: LazyPagingItems<Favourite> = emptyPagingItems(),
onNavigateUp: () -> Unit = {},
onNavigateToAppDetails: (packageName: String) -> Unit = {},
onRemoveFavourite: (packageName: String) -> Unit = {},
onImportFavourites: () -> Unit = {},
onExportFavourites: () -> Unit = {}
) {
@Composable
fun SetupMenu() {
FavouriteMenu { menuItem ->
when (menuItem) {
MenuItem.IMPORT -> onImportFavourites()
MenuItem.EXPORT -> onExportFavourites()
}
}
}
Scaffold(
topBar = {
TopAppBarComposable(
title = stringResource(R.string.title_favourites_manager),
onNavigateUp = onNavigateUp,
actions = { if (favourites.itemCount != 0) SetupMenu() }
)
}
) { paddingValues ->
Column(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
.padding(vertical = dimensionResource(R.dimen.padding_medium))
) {
when (favourites.loadState.refresh) {
is LoadState.Loading -> ProgressComposable()
is LoadState.Error -> {
ErrorComposable(
modifier = Modifier.padding(paddingValues),
icon = painterResource(R.drawable.ic_disclaimer),
message = stringResource(R.string.error)
)
}
else -> {
if (favourites.itemCount == 0) {
ErrorComposable(
modifier = Modifier.padding(paddingValues),
icon = painterResource(R.drawable.ic_favorite_unchecked),
message = stringResource(R.string.details_no_favourites)
)
} else {
LazyColumn {
items(
count = favourites.itemCount,
key = favourites.itemKey { it.packageName }
) { index ->
favourites[index]?.let { favourite ->
FavouriteComposable(
favourite = favourite,
onClick = { onNavigateToAppDetails(favourite.packageName) },
onClear = { onRemoveFavourite(favourite.packageName) }
)
}
}
}
}
}
}
}
}
}
@Preview
@Composable
private fun FavouriteScreenPreview() {
ScreenContent()
}

View File

@@ -0,0 +1,67 @@
/*
* SPDX-FileCopyrightText: 2025 The Calyx Institute
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.aurora.store.compose.ui.favourite.menu
import androidx.compose.foundation.layout.Box
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.aurora.store.R
/**
* Menu for the favourite screen
* @param modifier The modifier to be applied to the composable
* @param onMenuItemClicked Callback when a menu item has been clicked
* @see MenuItem
*/
@Composable
fun FavouriteMenu(
modifier: Modifier = Modifier,
isExpanded: Boolean = false,
onMenuItemClicked: (menuItem: MenuItem) -> Unit = {}
) {
var expanded by remember { mutableStateOf(isExpanded) }
fun onClick(menuItem: MenuItem) {
onMenuItemClicked(menuItem)
expanded = false
}
Box(modifier = modifier) {
IconButton(onClick = { expanded = true }) {
Icon(
painter = painterResource(R.drawable.ic_more_vert),
contentDescription = stringResource(R.string.menu)
)
}
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_import)) },
onClick = { onClick(MenuItem.IMPORT) }
)
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_export)) },
onClick = { onClick(MenuItem.EXPORT) }
)
}
}
}
@Preview(showBackground = true)
@Composable
private fun FavouriteMenuPreview() {
FavouriteMenu(isExpanded = true)
}

View File

@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 The Calyx Institute
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.aurora.store.compose.ui.favourite.menu
/**
* Valid menu items for the purpose of handling clicks
*/
enum class MenuItem {
IMPORT,
EXPORT
}

View File

@@ -70,6 +70,7 @@ import com.aurora.store.compose.composables.SearchSuggestionComposable
import com.aurora.store.compose.composables.app.AppListComposable
import com.aurora.store.compose.preview.AppPreviewProvider
import com.aurora.store.compose.preview.coilPreviewProvider
import com.aurora.store.compose.preview.emptyPagingItems
import com.aurora.store.compose.ui.details.AppDetailsScreen
import com.aurora.store.data.model.SearchFilter
import com.aurora.store.viewmodel.search.SearchViewModel
@@ -98,7 +99,7 @@ fun SearchScreen(onNavigateUp: () -> Unit, viewModel: SearchViewModel = hiltView
@Composable
private fun ScreenContent(
suggestions: List<SearchSuggestEntry> = emptyList(),
results: LazyPagingItems<App> = flowOf(PagingData.empty<App>()).collectAsLazyPagingItems(),
results: LazyPagingItems<App> = emptyPagingItems(),
onNavigateUp: () -> Unit = {},
onFetchSuggestions: (String) -> Unit = {},
onSearch: (String) -> Unit = {},

View File

@@ -1,5 +1,6 @@
package com.aurora.store.data.room.favourite
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
@@ -18,6 +19,9 @@ interface FavouriteDao {
@Query("SELECT * FROM favourite")
fun favourites(): Flow<List<Favourite>>
@Query("SELECT * FROM favourite")
fun pagedFavourites(): PagingSource<Int, Favourite>
@Query("SELECT EXISTS(SELECT 1 FROM favourite WHERE packageName = :packageName)")
suspend fun isFavourite(packageName: String): Boolean

View File

@@ -1,65 +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 coil3.load
import coil3.request.placeholder
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.store.R
import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.databinding.ViewFavBinding
@ModelView(
autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT,
baseModelClass = BaseModel::class
)
class FavouriteView @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : BaseView<ViewFavBinding>(context, attrs, defStyleAttr) {
@ModelProp
fun favourite(favourite: Favourite) {
binding.imgIcon.load(favourite.iconURL) {
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(25F))
}
binding.txtLine1.text = favourite.displayName
binding.txtLine2.text = favourite.packageName
}
@CallbackProp
fun onClick(onClickListener: OnClickListener?) {
binding.root.setOnClickListener(onClickListener)
}
@CallbackProp
fun onFavourite(onClickListener: OnClickListener?) {
binding.btnFavourite.setOnClickListener(onClickListener)
}
}

View File

@@ -1,124 +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.commons
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.aurora.Constants
import com.aurora.extensions.toast
import com.aurora.store.R
import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.databinding.FragmentFavouriteBinding
import com.aurora.store.view.epoxy.views.FavouriteViewModel_
import com.aurora.store.view.epoxy.views.app.NoAppViewModel_
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
import com.aurora.store.viewmodel.all.FavouriteViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import java.util.Calendar
@AndroidEntryPoint
class FavouriteFragment : BaseFragment<FragmentFavouriteBinding>() {
private val viewModel: FavouriteViewModel by viewModels()
private val startForDocumentImport =
registerForActivityResult(ActivityResultContracts.OpenDocument()) {
if (it != null) importFavourites(it) else toast(R.string.toast_fav_import_failed)
}
private val startForDocumentExport =
registerForActivityResult(ActivityResultContracts.CreateDocument(Constants.JSON_MIME_TYPE)) {
if (it != null) exportFavourites(it) else toast(R.string.toast_fav_export_failed)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
viewModel.favouritesList.collect {
updateController(it)
}
}
// Toolbar
binding.toolbar.apply {
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_import -> startForDocumentImport.launch(arrayOf(Constants.JSON_MIME_TYPE))
R.id.action_export -> {
startForDocumentExport.launch(
"aurora_store_favourites_${Calendar.getInstance().time.time}.json"
)
}
else -> {}
}
true
}
setNavigationOnClickListener { findNavController().navigateUp() }
}
}
private fun updateController(favourites: List<Favourite>?) {
binding.recycler.withModels {
setFilterDuplicates(true)
if (favourites == null) {
for (i in 1..10) {
add(
AppListViewShimmerModel_()
.id(i)
)
}
} else if (favourites.isEmpty()) {
add(
NoAppViewModel_()
.id("no_app")
.icon(R.drawable.ic_favorite_unchecked)
.message(R.string.details_no_favourites)
)
} else {
favourites.forEach {
add(
FavouriteViewModel_()
.id(it.packageName.hashCode())
.favourite(it)
.onClick { _ -> openDetailsFragment(it.packageName) }
.onFavourite { _ -> viewModel.removeFavourite(it.packageName) }
)
}
}
}
}
private fun importFavourites(uri: Uri) {
viewModel.importFavourites(requireContext(), uri)
binding.recycler.requestModelBuild()
toast(R.string.toast_fav_import_success)
}
private fun exportFavourites(uri: Uri) {
viewModel.exportFavourites(requireContext(), uri)
toast(R.string.toast_fav_export_success)
}
}

View File

@@ -433,10 +433,10 @@ class MoreDialogFragment : DialogFragment() {
icon = R.drawable.ic_blacklist,
screen = Screen.Blacklist
),
ViewOption(
ComposeOption(
title = R.string.title_favourites_manager,
icon = R.drawable.ic_favorite_unchecked,
destinationID = R.id.favouriteFragment
screen = Screen.Favourite
),
ViewOption(
title = R.string.title_spoof_manager,

View File

@@ -1,20 +1,7 @@
/*
* 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/>.
*
* SPDX-FileCopyrightText: 2024-2025 Rahul Kumar Patel <whyorean@gmail.com>
* SPDX-FileCopyrightText: 2024-2025 The Calyx Institute
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.aurora.store.viewmodel.all
@@ -24,13 +11,21 @@ import android.net.Uri
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.aurora.store.data.paging.GenericPagingSource.Companion.pager
import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.data.room.favourite.FavouriteDao
import com.aurora.store.data.room.favourite.ImportExport
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import javax.inject.Inject
@@ -38,14 +33,19 @@ import javax.inject.Inject
@HiltViewModel
class FavouriteViewModel @Inject constructor(
private val favouriteDao: FavouriteDao,
private val json: Json
private val json: Json,
@ApplicationContext private val context: Context
) : ViewModel() {
private val TAG = FavouriteViewModel::class.java.simpleName
val favouritesList = favouriteDao.favourites()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
private val _favourites = MutableStateFlow<PagingData<Favourite>>(PagingData.empty())
val favourites = _favourites.asStateFlow()
fun importFavourites(context: Context, uri: Uri) {
init {
getPagedFavourites()
}
fun importFavourites(uri: Uri) {
viewModelScope.launch(Dispatchers.IO) {
try {
context.contentResolver.openInputStream(uri)?.use {
@@ -54,7 +54,9 @@ class FavouriteViewModel @Inject constructor(
)
favouriteDao.insertAll(
importExport.favourites.map { fav -> fav.copy(mode = Favourite.Mode.IMPORT) }
importExport.favourites.map { fav ->
fav.copy(mode = Favourite.Mode.IMPORT)
}
)
}
} catch (exception: Exception) {
@@ -63,12 +65,12 @@ class FavouriteViewModel @Inject constructor(
}
}
fun exportFavourites(context: Context, uri: Uri) {
fun exportFavourites(uri: Uri) {
viewModelScope.launch(Dispatchers.IO) {
try {
context.contentResolver.openOutputStream(uri)?.use {
it.write(
json.encodeToString(ImportExport(favouritesList.value!!))
json.encodeToString(ImportExport(favouriteDao.favourites().first()))
.encodeToByteArray()
)
}
@@ -83,4 +85,12 @@ class FavouriteViewModel @Inject constructor(
favouriteDao.delete(packageName)
}
}
private fun getPagedFavourites() {
pager { favouriteDao.pagedFavourites() }.flow
.distinctUntilChanged()
.cachedIn(viewModelScope)
.onEach { _favourites.value = it }
.launchIn(viewModelScope)
}
}

View File

@@ -1,46 +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"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
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_import_export"
app:navigationIcon="@drawable/ic_arrow_back"
app:title="@string/title_favourites_manager" />
<com.airbnb.epoxy.EpoxyRecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar"
android:clipToPadding="true"
android:paddingBottom="@dimen/height_bottom_adj"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/view_app_list"
app:stackFromEnd="false" />
</RelativeLayout>

View File

@@ -1,76 +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:orientation="horizontal"
android:paddingStart="@dimen/padding_small"
android:paddingTop="@dimen/padding_xsmall"
android:paddingEnd="@dimen/padding_small"
android:paddingBottom="@dimen/padding_xsmall">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/img_icon"
android:layout_width="@dimen/icon_size_medium"
android:layout_height="@dimen/icon_size_medium" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_line1"
style="@style/AuroraTextStyle.Line1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_normal"
android:layout_toStartOf="@id/btn_favourite"
android:layout_toEndOf="@id/img_icon"
tools:text="Line1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_line2"
style="@style/AuroraTextStyle.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/txt_line1"
android:layout_alignStart="@id/txt_line1"
android:layout_alignEnd="@id/txt_line1"
tools:text="Line2" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_line3"
style="@style/AuroraTextStyle.Line3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/txt_line2"
android:layout_alignStart="@id/txt_line1"
android:layout_alignEnd="@id/txt_line1"
tools:text="Line3" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_favourite"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:contentDescription="@string/action_favourite"
android:padding="@dimen/padding_large"
app:icon="@drawable/ic_favorite_checked" />
</RelativeLayout>

View File

@@ -66,11 +66,6 @@
android:name="com.aurora.store.view.ui.spoof.SpoofFragment"
android:label="@string/title_spoof_manager"
tools:layout="@layout/fragment_spoof" />
<fragment
android:id="@+id/favouriteFragment"
android:name="com.aurora.store.view.ui.commons.FavouriteFragment"
android:label="@string/title_favourites_manager"
tools:layout="@layout/fragment_generic_with_toolbar" />
<fragment
android:id="@+id/settingsFragment"
android:name="com.aurora.store.view.ui.preferences.SettingsFragment"