Add favourites apps [1/2]
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
committed by
Aayush Gupta
parent
8bc2545067
commit
bbedb30d46
@@ -6,9 +6,12 @@ import androidx.room.TypeConverters
|
|||||||
import com.aurora.store.data.room.download.Download
|
import com.aurora.store.data.room.download.Download
|
||||||
import com.aurora.store.data.room.download.DownloadDao
|
import com.aurora.store.data.room.download.DownloadDao
|
||||||
import com.aurora.store.data.room.download.DownloadConverter
|
import com.aurora.store.data.room.download.DownloadConverter
|
||||||
|
import com.aurora.store.data.room.favourites.Favourite
|
||||||
|
import com.aurora.store.data.room.favourites.FavouriteDao
|
||||||
|
|
||||||
@Database(entities = [Download::class], version = 1, exportSchema = false)
|
@Database(entities = [Download::class, Favourite::class], version = 2, exportSchema = false)
|
||||||
@TypeConverters(DownloadConverter::class)
|
@TypeConverters(DownloadConverter::class)
|
||||||
abstract class AuroraDatabase : RoomDatabase() {
|
abstract class AuroraDatabase : RoomDatabase() {
|
||||||
abstract fun downloadDao(): DownloadDao
|
abstract fun downloadDao(): DownloadDao
|
||||||
|
abstract fun favouriteDao(): FavouriteDao
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import com.aurora.store.data.room.download.DownloadConverter
|
import com.aurora.store.data.room.download.DownloadConverter
|
||||||
import com.aurora.store.data.room.download.DownloadDao
|
import com.aurora.store.data.room.download.DownloadDao
|
||||||
|
import com.aurora.store.data.room.favourites.FavouriteDao
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
@@ -33,4 +34,9 @@ object RoomModule {
|
|||||||
fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao {
|
fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao {
|
||||||
return auroraDatabase.downloadDao()
|
return auroraDatabase.downloadDao()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun providesFavouriteDao(auroraDatabase: AuroraDatabase): FavouriteDao {
|
||||||
|
return auroraDatabase.favouriteDao()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.aurora.store.data.room.favourites
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
@Entity(tableName = "favourite")
|
||||||
|
data class Favourite(
|
||||||
|
@PrimaryKey
|
||||||
|
val packageName: String,
|
||||||
|
val displayName: String,
|
||||||
|
val iconURL: String,
|
||||||
|
val added: Long,
|
||||||
|
val mode: Mode
|
||||||
|
) : Parcelable {
|
||||||
|
|
||||||
|
enum class Mode {
|
||||||
|
MANUAL,
|
||||||
|
IMPORT
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.aurora.store.data.room.favourites;
|
||||||
|
|
||||||
|
import androidx.room.Dao;
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface FavouriteDao {
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insert(favourite: Favourite)
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insertAll(favourites: List<Favourite>)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM favourite")
|
||||||
|
fun favourites(): Flow<List<Favourite>>
|
||||||
|
|
||||||
|
@Query("SELECT EXISTS(SELECT 1 FROM favourite WHERE packageName = :packageName)")
|
||||||
|
suspend fun isFavourite(packageName: String): Boolean
|
||||||
|
|
||||||
|
@Query("DELETE FROM favourite WHERE packageName = :packageName")
|
||||||
|
suspend fun delete(packageName: String)
|
||||||
|
|
||||||
|
@Query("DELETE FROM favourite")
|
||||||
|
suspend fun deleteAll()
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(*) FROM favourite")
|
||||||
|
suspend fun count(): Int
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.widget.RelativeLayout
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.RoundedCornersTransformation
|
||||||
|
import com.airbnb.epoxy.CallbackProp
|
||||||
|
import com.airbnb.epoxy.ModelProp
|
||||||
|
import com.airbnb.epoxy.ModelView
|
||||||
|
import com.aurora.gplayapi.data.models.App
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.room.favourites.Favourite
|
||||||
|
import com.aurora.store.databinding.ViewFavBinding
|
||||||
|
|
||||||
|
@ModelView(
|
||||||
|
autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT,
|
||||||
|
baseModelClass = BaseView::class
|
||||||
|
)
|
||||||
|
class FavouriteView : RelativeLayout {
|
||||||
|
|
||||||
|
private lateinit var binding: ViewFavBinding
|
||||||
|
|
||||||
|
constructor(context: Context?) : super(context) {
|
||||||
|
init(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
|
||||||
|
init(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||||
|
context,
|
||||||
|
attrs,
|
||||||
|
defStyleAttr
|
||||||
|
) {
|
||||||
|
init(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context?) {
|
||||||
|
val view = inflate(context, R.layout.view_fav, this)
|
||||||
|
binding = ViewFavBinding.bind(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.room.favourites.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
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class FavouriteFragment : BaseFragment(R.layout.fragment_favourite) {
|
||||||
|
|
||||||
|
private var _binding: FragmentFavouriteBinding? = null
|
||||||
|
private val binding: FragmentFavouriteBinding
|
||||||
|
get() = _binding!!
|
||||||
|
|
||||||
|
private val viewModel: FavouriteViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
_binding = FragmentFavouriteBinding.bind(view)
|
||||||
|
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
viewModel.favouritesList.collect {
|
||||||
|
updateController(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toolbar
|
||||||
|
binding.toolbar.setNavigationOnClickListener {
|
||||||
|
findNavController().navigateUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
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(getString(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) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -280,6 +280,11 @@ class MoreDialogFragment : DialogFragment() {
|
|||||||
icon = R.drawable.ic_blacklist,
|
icon = R.drawable.ic_blacklist,
|
||||||
destinationID = R.id.blacklistFragment
|
destinationID = R.id.blacklistFragment
|
||||||
),
|
),
|
||||||
|
Option(
|
||||||
|
title = R.string.title_favourites_manager,
|
||||||
|
icon = R.drawable.ic_favorite_unchecked,
|
||||||
|
destinationID = R.id.favouriteFragment
|
||||||
|
),
|
||||||
Option(
|
Option(
|
||||||
title = R.string.title_spoof_manager,
|
title = R.string.title_spoof_manager,
|
||||||
icon = R.drawable.ic_spoof,
|
icon = R.drawable.ic_spoof,
|
||||||
|
|||||||
@@ -368,6 +368,7 @@ class AppDetailsFragment : BaseFragment(R.layout.fragment_details) {
|
|||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inflateMenu(R.menu.menu_details)
|
inflateMenu(R.menu.menu_details)
|
||||||
|
|
||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
@@ -383,6 +384,10 @@ class AppDetailsFragment : BaseFragment(R.layout.fragment_details) {
|
|||||||
view.context.share(app)
|
view.context.share(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.action_favourite -> {
|
||||||
|
viewModel.toggleFavourite(app)
|
||||||
|
}
|
||||||
|
|
||||||
R.id.action_uninstall -> {
|
R.id.action_uninstall -> {
|
||||||
AppInstaller.uninstall(requireContext(), app.packageName)
|
AppInstaller.uninstall(requireContext(), app.packageName)
|
||||||
}
|
}
|
||||||
@@ -428,6 +433,20 @@ class AppDetailsFragment : BaseFragment(R.layout.fragment_details) {
|
|||||||
uninstallActionEnabled = app.isInstalled
|
uninstallActionEnabled = app.isInstalled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
viewModel.favourite.collect {
|
||||||
|
if (it) {
|
||||||
|
binding.layoutDetailsToolbar.toolbar.menu
|
||||||
|
?.findItem(R.id.action_favourite)
|
||||||
|
?.setIcon(R.drawable.ic_favorite_checked)
|
||||||
|
} else {
|
||||||
|
binding.layoutDetailsToolbar.toolbar.menu
|
||||||
|
?.findItem(R.id.action_favourite)
|
||||||
|
?.setIcon(R.drawable.ic_favorite_unchecked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.all
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.aurora.store.data.room.favourites.FavouriteDao
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class FavouriteViewModel @Inject constructor(
|
||||||
|
private val favouriteDao: FavouriteDao,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
val favouritesList = favouriteDao.favourites()
|
||||||
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
|
fun removeFavourite(packageName: String) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
favouriteDao.delete(packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,12 +13,16 @@ import com.aurora.store.data.model.ExodusReport
|
|||||||
import com.aurora.store.data.model.Report
|
import com.aurora.store.data.model.Report
|
||||||
import com.aurora.store.data.network.HttpClient
|
import com.aurora.store.data.network.HttpClient
|
||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.providers.AuthProvider
|
||||||
|
import com.aurora.store.data.room.favourites.Favourite
|
||||||
|
import com.aurora.store.data.room.favourites.FavouriteDao
|
||||||
import com.aurora.store.util.DownloadWorkerUtil
|
import com.aurora.store.util.DownloadWorkerUtil
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.lang.reflect.Modifier
|
import java.lang.reflect.Modifier
|
||||||
@@ -27,7 +31,8 @@ import javax.inject.Inject
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class AppDetailsViewModel @Inject constructor(
|
class AppDetailsViewModel @Inject constructor(
|
||||||
private val downloadWorkerUtil: DownloadWorkerUtil,
|
private val downloadWorkerUtil: DownloadWorkerUtil,
|
||||||
private val authProvider: AuthProvider
|
private val authProvider: AuthProvider,
|
||||||
|
private val favouriteDao: FavouriteDao
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val TAG = AppDetailsViewModel::class.java.simpleName
|
private val TAG = AppDetailsViewModel::class.java.simpleName
|
||||||
@@ -50,11 +55,16 @@ class AppDetailsViewModel @Inject constructor(
|
|||||||
private val _testingProgramStatus = MutableSharedFlow<TestingProgramStatus?>()
|
private val _testingProgramStatus = MutableSharedFlow<TestingProgramStatus?>()
|
||||||
val testingProgramStatus = _testingProgramStatus.asSharedFlow()
|
val testingProgramStatus = _testingProgramStatus.asSharedFlow()
|
||||||
|
|
||||||
|
private val _favourite = MutableStateFlow<Boolean>(false)
|
||||||
|
val favourite = _favourite.asStateFlow()
|
||||||
|
|
||||||
val downloadsList get() = downloadWorkerUtil.downloadsList
|
val downloadsList get() = downloadWorkerUtil.downloadsList
|
||||||
|
|
||||||
fun fetchAppDetails(context: Context, packageName: String) {
|
fun fetchAppDetails(context: Context, packageName: String) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
isFavourite(packageName)
|
||||||
|
|
||||||
_app.emit(
|
_app.emit(
|
||||||
AppDetailsHelper(authProvider.authData)
|
AppDetailsHelper(authProvider.authData)
|
||||||
.using(HttpClient.getPreferredClient(context))
|
.using(HttpClient.getPreferredClient(context))
|
||||||
@@ -70,9 +80,11 @@ class AppDetailsViewModel @Inject constructor(
|
|||||||
fun fetchAppReviews(context: Context, packageName: String) {
|
fun fetchAppReviews(context: Context, packageName: String) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
_reviews.emit(ReviewsHelper(authProvider.authData)
|
_reviews.emit(
|
||||||
.using(HttpClient.getPreferredClient(context))
|
ReviewsHelper(authProvider.authData)
|
||||||
.getReviewSummary(packageName))
|
.using(HttpClient.getPreferredClient(context))
|
||||||
|
.getReviewSummary(packageName)
|
||||||
|
)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed to fetch app reviews", exception)
|
Log.e(TAG, "Failed to fetch app reviews", exception)
|
||||||
_reviews.emit(emptyList())
|
_reviews.emit(emptyList())
|
||||||
@@ -83,15 +95,17 @@ class AppDetailsViewModel @Inject constructor(
|
|||||||
fun postAppReview(context: Context, packageName: String, review: Review, isBeta: Boolean) {
|
fun postAppReview(context: Context, packageName: String, review: Review, isBeta: Boolean) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
_userReview.emit(ReviewsHelper(authProvider.authData)
|
_userReview.emit(
|
||||||
.using(HttpClient.getPreferredClient(context))
|
ReviewsHelper(authProvider.authData)
|
||||||
.addOrEditReview(
|
.using(HttpClient.getPreferredClient(context))
|
||||||
packageName,
|
.addOrEditReview(
|
||||||
review.title,
|
packageName,
|
||||||
review.comment,
|
review.title,
|
||||||
review.rating,
|
review.comment,
|
||||||
isBeta
|
review.rating,
|
||||||
)!!)
|
isBeta
|
||||||
|
)!!
|
||||||
|
)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed to post review", exception)
|
Log.e(TAG, "Failed to post review", exception)
|
||||||
_userReview.emit(Review())
|
_userReview.emit(Review())
|
||||||
@@ -100,7 +114,7 @@ class AppDetailsViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun fetchAppReport(context: Context,packageName: String) {
|
fun fetchAppReport(context: Context, packageName: String) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val headers: MutableMap<String, String> = mutableMapOf()
|
val headers: MutableMap<String, String> = mutableMapOf()
|
||||||
@@ -143,10 +157,36 @@ class AppDetailsViewModel @Inject constructor(
|
|||||||
viewModelScope.launch { downloadWorkerUtil.cancelDownload(app.packageName) }
|
viewModelScope.launch { downloadWorkerUtil.cancelDownload(app.packageName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isFavourite(packageName: String) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
_favourite.value = favouriteDao.isFavourite(packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleFavourite(app: App) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
if (favourite.value) {
|
||||||
|
favouriteDao.delete(app.packageName)
|
||||||
|
} else {
|
||||||
|
favouriteDao.insert(
|
||||||
|
Favourite(
|
||||||
|
packageName = app.packageName,
|
||||||
|
displayName = app.displayName,
|
||||||
|
iconURL = app.iconArtwork.url,
|
||||||
|
mode = Favourite.Mode.MANUAL,
|
||||||
|
added = System.currentTimeMillis(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_favourite.value = !favourite.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseResponse(response: String, packageName: String): List<Report> {
|
private fun parseResponse(response: String, packageName: String): List<Report> {
|
||||||
try {
|
try {
|
||||||
val gson = GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC)
|
val gson = GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC)
|
||||||
.create()
|
.create()
|
||||||
|
|
||||||
val jsonObject = JSONObject(response)
|
val jsonObject = JSONObject(response)
|
||||||
val exodusObject = jsonObject.getJSONObject(packageName)
|
val exodusObject = jsonObject.getJSONObject(packageName)
|
||||||
|
|||||||
10
app/src/main/res/drawable/ic_favorite_checked.xml
Normal file
10
app/src/main/res/drawable/ic_favorite_checked.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="m480,840 l-58,-52q-101,-91 -167,-157T150,512.5Q111,460 95.5,416T80,326q0,-94 63,-157t157,-63q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,46 -15.5,90T810,512.5Q771,565 705,631T538,788l-58,52Z" />
|
||||||
|
</vector>
|
||||||
10
app/src/main/res/drawable/ic_favorite_unchecked.xml
Normal file
10
app/src/main/res/drawable/ic_favorite_unchecked.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="m480,840 l-58,-52q-101,-91 -167,-157T150,512.5Q111,460 95.5,416T80,326q0,-94 63,-157t157,-63q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,46 -15.5,90T810,512.5Q771,565 705,631T538,788l-58,52ZM480,732q96,-86 158,-147.5t98,-107q36,-45.5 50,-81t14,-70.5q0,-60 -40,-100t-100,-40q-47,0 -87,26.5T518,280h-76q-15,-41 -55,-67.5T300,186q-60,0 -100,40t-40,100q0,35 14,70.5t50,81q36,45.5 98,107T480,732ZM480,459Z" />
|
||||||
|
</vector>
|
||||||
45
app/src/main/res/layout/fragment_favourite.xml
Normal file
45
app/src/main/res/layout/fragment_favourite.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?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"
|
||||||
|
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"
|
||||||
|
android:theme="?attr/actionBarTheme"
|
||||||
|
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:itemSpacing="@dimen/margin_normal"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:stackFromEnd="false" />
|
||||||
|
</RelativeLayout>
|
||||||
74
app/src/main/res/layout/view_fav.xml
Normal file
74
app/src/main/res/layout/view_fav.xml
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?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="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="@dimen/padding_normal"
|
||||||
|
android:paddingEnd="@dimen/padding_small">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/img_icon"
|
||||||
|
android:layout_width="@dimen/icon_size_medium"
|
||||||
|
android:layout_height="@dimen/icon_size_medium"
|
||||||
|
android:layout_centerVertical="true" />
|
||||||
|
|
||||||
|
|
||||||
|
<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" />
|
||||||
|
|
||||||
|
<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"
|
||||||
|
android:layout_marginTop="@dimen/margin_xxsmall" />
|
||||||
|
|
||||||
|
<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"
|
||||||
|
android:layout_marginTop="@dimen/margin_xxsmall" />
|
||||||
|
|
||||||
|
<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>
|
||||||
@@ -19,6 +19,11 @@
|
|||||||
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_favourite"
|
||||||
|
android:icon="@drawable/ic_favorite_unchecked"
|
||||||
|
android:title="@string/action_favourite"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_share"
|
android:id="@+id/action_share"
|
||||||
|
|||||||
@@ -88,6 +88,11 @@
|
|||||||
android:name="com.aurora.store.view.ui.spoof.SpoofFragment"
|
android:name="com.aurora.store.view.ui.spoof.SpoofFragment"
|
||||||
android:label="@string/title_spoof_manager"
|
android:label="@string/title_spoof_manager"
|
||||||
tools:layout="@layout/activity_generic_pager" />
|
tools:layout="@layout/activity_generic_pager" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/favouriteFragment"
|
||||||
|
android:name="com.aurora.store.view.ui.commons.FavouriteFragment"
|
||||||
|
android:label="@string/title_favourites_manager"
|
||||||
|
tools:layout="@layout/activity_generic_recycler" />
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/blacklistFragment"
|
android:id="@+id/blacklistFragment"
|
||||||
android:name="com.aurora.store.view.ui.commons.BlacklistFragment"
|
android:name="com.aurora.store.view.ui.commons.BlacklistFragment"
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
<string name="action_disable">"Disable"</string>
|
<string name="action_disable">"Disable"</string>
|
||||||
<string name="action_export">"Export"</string>
|
<string name="action_export">"Export"</string>
|
||||||
<string name="action_import">"Import"</string>
|
<string name="action_import">"Import"</string>
|
||||||
|
<string name="action_favourite">"Favourite"</string>
|
||||||
<string name="action_filter">"Filters"</string>
|
<string name="action_filter">"Filters"</string>
|
||||||
<string name="action_filter_all">"All"</string>
|
<string name="action_filter_all">"All"</string>
|
||||||
<string name="action_filter_apply">"Apply"</string>
|
<string name="action_filter_apply">"Apply"</string>
|
||||||
@@ -119,6 +120,7 @@
|
|||||||
<string name="details_more_about_app">"More about app"</string>
|
<string name="details_more_about_app">"More about app"</string>
|
||||||
<string name="details_no_ads">"No ads"</string>
|
<string name="details_no_ads">"No ads"</string>
|
||||||
<string name="details_no_app_match">"No app match found"</string>
|
<string name="details_no_app_match">"No app match found"</string>
|
||||||
|
<string name="details_no_favourites">"No favourite apps found"</string>
|
||||||
<string name="details_no_dependencies">"No Dependencies"</string>
|
<string name="details_no_dependencies">"No Dependencies"</string>
|
||||||
<string name="details_no_permission">"No permissions"</string>
|
<string name="details_no_permission">"No permissions"</string>
|
||||||
<string name="details_no_updates">"No updates available"</string>
|
<string name="details_no_updates">"No updates available"</string>
|
||||||
@@ -280,6 +282,7 @@
|
|||||||
<string name="title_apps_sale">"Apps on sale"</string>
|
<string name="title_apps_sale">"Apps on sale"</string>
|
||||||
<string name="title_apps_sale_provider">"Provider - bestappsales.com"</string>
|
<string name="title_apps_sale_provider">"Provider - bestappsales.com"</string>
|
||||||
<string name="title_blacklist_manager">"Blacklist manager"</string>
|
<string name="title_blacklist_manager">"Blacklist manager"</string>
|
||||||
|
<string name="title_favourites_manager">"Favourite Apps"</string>
|
||||||
<string name="title_device">"Device"</string>
|
<string name="title_device">"Device"</string>
|
||||||
<string name="title_download_manager">"Downloads"</string>
|
<string name="title_download_manager">"Downloads"</string>
|
||||||
<string name="title_download_playstore">"Play Store"</string>
|
<string name="title_download_playstore">"Play Store"</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user