diff --git a/app/build.gradle b/app/build.gradle
index a3df297013e3ee28f0ace3e4b3457d92c23fa232..c324b36834b93086c4ae9296d977f19915afdaa4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -153,7 +153,7 @@ dependencies {
api files('libs/splitinstall-lib.jar')
implementation 'foundation.e.lib:telemetry:0.0.11-alpha'
- implementation "foundation.e:gplayapi:3.2.10-2"
+ implementation "foundation.e:gplayapi:3.2.10-3"
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.fragment:fragment-ktx:1.5.6'
diff --git a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt
index 50480c04e5915be98cf7519230a5ca7017929153..798eb4daa09362d8dfed036f1b60cab5a96ee0f2 100644
--- a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt
+++ b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt
@@ -1,6 +1,5 @@
/*
- * Copyright MURENA SAS 2023
- * Apps Quickly and easily install Android apps onto your device!
+ * Copyright (C) 2024 MURENA SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,6 +13,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
*/
package foundation.e.apps.data.playstore
@@ -21,6 +21,7 @@ package foundation.e.apps.data.playstore
import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.Category
+import com.aurora.gplayapi.data.models.ContentRating
import com.aurora.gplayapi.data.models.File
import com.aurora.gplayapi.data.models.SearchBundle
import foundation.e.apps.data.StoreRepository
@@ -43,4 +44,9 @@ interface PlayStoreRepository : StoreRepository {
versionCode: Int,
offerType: Int
): List
+
+ suspend fun updateContentRatingWithId(
+ appPackage: String,
+ contentRating: ContentRating
+ ): ContentRating
}
diff --git a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepositoryImpl.kt b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepositoryImpl.kt
index 63a467e92bba59fb25e1f16ae407080c7cd8c254..d971814641eab2d081f901391e634fea012d5cff 100644
--- a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepositoryImpl.kt
+++ b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepositoryImpl.kt
@@ -1,6 +1,5 @@
/*
- * Copyright MURENA SAS 2023
- * Apps Quickly and easily install Android apps onto your device!
+ * Copyright (C) 2024 MURENA SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,6 +13,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
*/
package foundation.e.apps.data.playstore
@@ -23,6 +23,7 @@ import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.Category
+import com.aurora.gplayapi.data.models.ContentRating
import com.aurora.gplayapi.data.models.File
import com.aurora.gplayapi.data.models.SearchBundle
import com.aurora.gplayapi.data.models.StreamCluster
@@ -30,14 +31,15 @@ import com.aurora.gplayapi.helpers.AppDetailsHelper
import com.aurora.gplayapi.helpers.CategoryAppsHelper
import com.aurora.gplayapi.helpers.CategoryHelper
import com.aurora.gplayapi.helpers.Chart
+import com.aurora.gplayapi.helpers.ContentRatingHelper
import com.aurora.gplayapi.helpers.PurchaseHelper
import com.aurora.gplayapi.helpers.SearchHelper
import com.aurora.gplayapi.helpers.TopChartsHelper
import dagger.hilt.android.qualifiers.ApplicationContext
import foundation.e.apps.R
import foundation.e.apps.data.application.utils.CategoryType
-import foundation.e.apps.data.playstore.utils.GPlayHttpClient
import foundation.e.apps.data.login.AuthenticatorRepository
+import foundation.e.apps.data.playstore.utils.GPlayHttpClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
@@ -78,8 +80,7 @@ class PlayStoreRepositoryImpl @Inject constructor(
subBundle: MutableSet?
): Pair, MutableSet> {
var authData = authenticatorRepository.gplayAuth!!
- val searchHelper =
- SearchHelper(authData).using(gPlayHttpClient)
+ val searchHelper = SearchHelper(authData).using(gPlayHttpClient)
Timber.d("Fetching search result for $query, subBundle: $subBundle")
@@ -115,8 +116,7 @@ class PlayStoreRepositoryImpl @Inject constructor(
override suspend fun getAppsByCategory(category: String, pageUrl: String?): StreamCluster {
val authData = authenticatorRepository.gplayAuth!!
- val subCategoryHelper =
- CategoryAppsHelper(authData).using(gPlayHttpClient)
+ val subCategoryHelper = CategoryAppsHelper(authData).using(gPlayHttpClient)
if (!pageUrl.isNullOrEmpty()) {
return subCategoryHelper.next(pageUrl)
@@ -163,7 +163,8 @@ class PlayStoreRepositoryImpl @Inject constructor(
}
private fun getCategoryType(type: CategoryType): Category.Type {
- return if (type == CategoryType.APPLICATION) Category.Type.APPLICATION else Category.Type.GAME
+ return if (type == CategoryType.APPLICATION) Category.Type.APPLICATION
+ else Category.Type.GAME
}
private suspend fun getTopApps(
@@ -207,14 +208,24 @@ class PlayStoreRepositoryImpl @Inject constructor(
withContext(Dispatchers.IO) {
val purchaseHelper = PurchaseHelper(authData).using(gPlayHttpClient)
downloadData.addAll(
- purchaseHelper.getOnDemandModule(
- packageName,
- moduleName,
- versionCode,
- offerType
- )
+ purchaseHelper.getOnDemandModule(packageName, moduleName, versionCode, offerType)
)
}
return downloadData
}
+
+ override suspend fun updateContentRatingWithId(
+ appPackage: String,
+ contentRating: ContentRating
+ ): ContentRating {
+ val authData = authenticatorRepository.gplayAuth!!
+ val contentRatingHelper = ContentRatingHelper(authData)
+
+ return withContext(Dispatchers.IO) {
+ contentRatingHelper.updateContentRatingWithId(
+ appPackage,
+ contentRating
+ )
+ }
+ }
}
diff --git a/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt
index 204767a8ffc96b6f0d58ffeec6ad754c6b4b0a99..4e43c269faa886ce92e1bdbee3926fd6d80df01b 100644
--- a/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt
+++ b/app/src/main/java/foundation/e/apps/di/RepositoryModule.kt
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2024 MURENA SAS
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see .
+ *
+ */
+
package foundation.e.apps.di
import dagger.Binds
@@ -12,6 +30,8 @@ import foundation.e.apps.data.fdroid.FdroidRepository
import foundation.e.apps.data.fdroid.IFdroidRepository
import foundation.e.apps.data.fusedDownload.FusedManagerImpl
import foundation.e.apps.data.fusedDownload.IFusedManager
+import foundation.e.apps.data.playstore.PlayStoreRepository
+import foundation.e.apps.data.playstore.PlayStoreRepositoryImpl
import javax.inject.Singleton
@Module
@@ -32,4 +52,8 @@ interface RepositoryModule {
@Singleton
@Binds
fun getPrivacyScoreRepository(privacyScoreRepositoryImpl: PrivacyScoreRepositoryImpl): PrivacyScoreRepository
+
+ @Singleton
+ @Binds
+ fun getPlayStoreRepository(playStoreRepository: PlayStoreRepositoryImpl): PlayStoreRepository
}
diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt
index d71d6def54bc50c53f44a07174826322ea67a2cb..e2011f01b23d36412450353097e7941a4d6e53a0 100644
--- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt
+++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt
@@ -494,23 +494,13 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) {
private fun collectAppContentRatingState() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
- applicationViewModel.appContentRating.collectLatest(::updateContentRatingUi)
+ applicationViewModel.appContentRatingState
+ .collectLatest(::updateContentRatingUi)
}
}
}
- private fun updateContentRatingUi(contentRating: ContentRating) {
- fun loadContentRating(contentRating: ContentRating) {
- lifecycleScope.launch {
- val drawable = loadContentRatingDrawable(contentRating.artwork.url)
- displayRating(contentRating, drawable)
- }
- }
-
- fun hideContentRating() {
- binding.ratingsInclude.appContentRatingLayout.visibility = View.GONE
- }
-
+ private suspend fun updateContentRatingUi(contentRating: ContentRating) {
if (contentRating.isValid()) {
loadContentRating(contentRating)
} else {
@@ -518,6 +508,15 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) {
}
}
+ private suspend fun loadContentRating(contentRating: ContentRating) {
+ val drawable = loadContentRatingDrawable(contentRating.artwork.url)
+ displayRating(contentRating, drawable)
+ }
+
+ private fun hideContentRating() {
+ binding.ratingsInclude.appContentRatingLayout.visibility = View.GONE
+ }
+
private fun displayRating(contentRating: ContentRating, drawable: Drawable?) {
binding.ratingsInclude.apply {
appContentRatingTitle.text = contentRating.title
diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt
index 8d1815588b215f8ff99a433f278ccda6b24f4890..57b2be86f6c3d5ce6790a22581f1e1327c222308 100644
--- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt
+++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt
@@ -36,6 +36,7 @@ import foundation.e.apps.data.fusedDownload.models.FusedDownload
import foundation.e.apps.data.login.AuthObject
import foundation.e.apps.data.login.exceptions.CleanApkException
import foundation.e.apps.data.login.exceptions.GPlayException
+import foundation.e.apps.data.playstore.PlayStoreRepository
import foundation.e.apps.install.download.data.DownloadProgress
import foundation.e.apps.install.download.data.DownloadProgressLD
import foundation.e.apps.ui.application.ShareButtonVisibilityState.Hidden
@@ -53,6 +54,7 @@ class ApplicationViewModel @Inject constructor(
downloadProgressLD: DownloadProgressLD,
private val applicationRepository: ApplicationRepository,
private val fusedManagerRepository: FusedManagerRepository,
+ private val playStoreRepository: PlayStoreRepository,
) : LoadingViewModel() {
val application: MutableLiveData> = MutableLiveData()
@@ -64,8 +66,8 @@ class ApplicationViewModel @Inject constructor(
private val _shareButtonVisibilityState = MutableStateFlow(Hidden)
val shareButtonVisibilityState = _shareButtonVisibilityState.asStateFlow()
- private val _appContentRating = MutableStateFlow(ContentRating())
- val appContentRating = _appContentRating.asStateFlow()
+ private val _appContentRatingState = MutableStateFlow(ContentRating())
+ val appContentRatingState = _appContentRatingState.asStateFlow()
fun loadData(
id: String,
@@ -119,7 +121,7 @@ class ApplicationViewModel @Inject constructor(
application.postValue(appData)
updateShareVisibilityState(appData.first.shareUri.toString())
- updateAppContentRatingState(appData.first.contentRating)
+ updateAppContentRatingState(packageName, appData.first.contentRating)
val status = appData.second
@@ -146,8 +148,17 @@ class ApplicationViewModel @Inject constructor(
}
}
- private fun updateAppContentRatingState(value: ContentRating) {
- _appContentRating.update { value }
+ private suspend fun updateAppContentRatingState(
+ packageName: String,
+ contentRating: ContentRating
+ ) {
+ // Initially update the state without ID to show the UI immediately
+ _appContentRatingState.update { contentRating }
+
+ val ratingWithId = playStoreRepository.updateContentRatingWithId(packageName, contentRating)
+
+ // Later, update with a new rating; no visual change in the UI
+ _appContentRatingState.update { contentRating.copy(id = ratingWithId.id) }
}
private fun updateShareVisibilityState(shareUri: String) {