From 460d679f9eb7a6ec26fc012caa745ca7a5683f00 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Wed, 22 May 2024 20:11:35 +0600 Subject: [PATCH 1/4] Add content rating helper with localization support This commit introduces a new `ContentRatingHelper` class that provides functionality for retrieving the content rating for a given app package based on the specified locale. Additionally, the `ContentRating` model has been enhanced to override `equals` and `hashCode` methods. The `MainActivityViewModel` class has also been updated to change the resource path for loading properties. The library version has been updated as well. --- lib/build.gradle.kts | 2 +- .../gplayapi/data/models/ContentRating.kt | 14 ++- .../gplayapi/helpers/ContentRatingHelper.kt | 97 +++++++++++++++++++ .../aurora/sampleapp/MainActivityViewModel.kt | 5 +- 4 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 1d39bab..344854f 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -10,7 +10,7 @@ plugins { val versionMajor = 3 val versionMinor = 2 val versionPatch = 10 -val releasePatch = "2" +val releasePatch = "3" val versionName = "${versionMajor}.${versionMinor}.${versionPatch}-${releasePatch}" diff --git a/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt index 1cb61e5..3ae479b 100644 --- a/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt @@ -5,9 +5,21 @@ import kotlinx.parcelize.Parcelize @Parcelize data class ContentRating( + val id: String = String(), val title: String = String(), val description: String = String(), val recommendation: String = String(), val artwork: Artwork = Artwork(), val recommendationAndDescriptionHtml: String = String() -) : Parcelable +) : Parcelable { + override fun equals(other: Any?): Boolean { + return when (other) { + is ContentRating -> this.artwork.url == other.artwork.url + else -> false + } + } + + override fun hashCode(): Int { + return this.artwork.url.hashCode() + } +} diff --git a/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt new file mode 100644 index 0000000..d18eee3 --- /dev/null +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt @@ -0,0 +1,97 @@ +/* + * 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 com.aurora.gplayapi.helpers + +import com.aurora.gplayapi.DetailsResponse +import com.aurora.gplayapi.GooglePlayApi +import com.aurora.gplayapi.data.builders.AppBuilder +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.ContentRating +import com.aurora.gplayapi.data.providers.HeaderProvider.getDefaultHeaders +import com.aurora.gplayapi.exceptions.ApiException +import com.aurora.gplayapi.network.IHttpClient +import java.util.Locale + +class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { + + override fun using(httpClient: IHttpClient) = apply { + this.httpClient = httpClient + } + + /** + * Retrieves the [ContentRating] for a given app package based on the + * specified locale. + * + * @param appPackage The app's package name to fetch the content rating for. + * @param locale The locale to use for fetching the content rating. Defaults to the system's default locale. + * + * @return [ContentRating] The content rating for the app. The ID of the content rating will be the rating's title in English. + * @throws Exception Throws an exception if there is an issue fetching the content ratings. + */ + @Throws(Exception::class) + fun getContentRating( + appPackage: String, + locale: Locale = Locale.getDefault() + ): ContentRating { + val defaultLocaleRating = fetchContentRating(appPackage) + + // Early return if the languages are English, avoids further network call and processing. + if (locale.language == Locale.ENGLISH.language) { + return buildRating(defaultLocaleRating, defaultLocaleRating) + } + + val englishRating = fetchContentRating(appPackage, Locale.US) + + return buildRating(defaultLocaleRating, englishRating) + } + + private fun fetchContentRating( + appPackage: String, locale: Locale = Locale.getDefault() + ): ContentRating { + val response = getAppDetails(packageName = appPackage, locale = locale) + return AppBuilder.build(response).contentRating + } + + // Sets the English title as the ID for the rating. + // The default title can be in any language but the id will always be in English. + private fun buildRating( + defaultLocaleRating: ContentRating, + englishRating: ContentRating + ) = defaultLocaleRating.copy(id = englishRating.title.lowercase()) + + private fun getAppDetails( + packageName: String, locale: Locale = Locale.getDefault() + ): DetailsResponse { + val headers = buildHeaders(locale) + val params = mapOf("doc" to packageName) + val playResponse = httpClient.get(GooglePlayApi.URL_DETAILS, headers, params) + + return if (playResponse.isSuccessful) { + getDetailsResponseFromBytes(playResponse.responseBytes) + } else { + throw ApiException.AppNotFound(playResponse.errorString) + } + } + + private fun buildHeaders(locale: Locale): Map { + return getDefaultHeaders(authData).apply { + this["Accept-Language"] = locale.toLanguageTag() + } + } +} diff --git a/sampleapp/src/main/java/com/aurora/sampleapp/MainActivityViewModel.kt b/sampleapp/src/main/java/com/aurora/sampleapp/MainActivityViewModel.kt index a47788b..aa990a5 100644 --- a/sampleapp/src/main/java/com/aurora/sampleapp/MainActivityViewModel.kt +++ b/sampleapp/src/main/java/com/aurora/sampleapp/MainActivityViewModel.kt @@ -3,14 +3,13 @@ package com.aurora.sampleapp import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.aurora.gplayapi.DeviceManager import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.helpers.AuthHelper -import java.util.Properties import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch +import java.util.Properties class MainActivityViewModel : ViewModel() { @@ -20,7 +19,7 @@ class MainActivityViewModel : ViewModel() { fun buildAuthData(context: Context) { viewModelScope.launch(Dispatchers.IO) { val properties = Properties() - context.resources.openRawResource(com.aurora.gplayapi.R.raw.gplayapi_px_7a).use { + context.resources.openRawResource(foundation.e.gplayapi.R.raw.gplayapi_px_7a).use { properties.load(it) } -- GitLab From afc798abbaae90ead9a87138bf7726688eaf1dd5 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Wed, 22 May 2024 20:40:41 +0600 Subject: [PATCH 2/4] Use constants for http headers and query params Refactored the ContentRatingHelper class to use constants for HTTP headers and query parameters, improving code readability and maintainability. --- .../com/aurora/gplayapi/helpers/ContentRatingHelper.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt index d18eee3..9253935 100644 --- a/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt @@ -30,6 +30,11 @@ import java.util.Locale class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { + companion object { + private const val HTTP_HEADER_ACCEPT_LANGUAGE = "Accept-Language" + private const val HTTP_QUERY_PARAM_DOC = "doc" + } + override fun using(httpClient: IHttpClient) = apply { this.httpClient = httpClient } @@ -79,7 +84,7 @@ class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { packageName: String, locale: Locale = Locale.getDefault() ): DetailsResponse { val headers = buildHeaders(locale) - val params = mapOf("doc" to packageName) + val params = mapOf(HTTP_QUERY_PARAM_DOC to packageName) val playResponse = httpClient.get(GooglePlayApi.URL_DETAILS, headers, params) return if (playResponse.isSuccessful) { @@ -91,7 +96,7 @@ class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { private fun buildHeaders(locale: Locale): Map { return getDefaultHeaders(authData).apply { - this["Accept-Language"] = locale.toLanguageTag() + this[HTTP_HEADER_ACCEPT_LANGUAGE] = locale.toLanguageTag() } } } -- GitLab From 8cc05e6f78eb2dd575bf4d0af8edc8a5e0baeef7 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Wed, 22 May 2024 20:53:18 +0600 Subject: [PATCH 3/4] Update variable names and comment Refactored variable names and comment for better readability and understanding of the code. --- .../aurora/gplayapi/helpers/ContentRatingHelper.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt index 9253935..23f5f36 100644 --- a/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt @@ -56,14 +56,16 @@ class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { ): ContentRating { val defaultLocaleRating = fetchContentRating(appPackage) - // Early return if the languages are English, avoids further network call and processing. + // If the device's language is English, then the default rating will be in English. + // So, its title can be treated as an identifier for the rating. + // By returning early from here, we avoid an extra network call and further processing. if (locale.language == Locale.ENGLISH.language) { - return buildRating(defaultLocaleRating, defaultLocaleRating) + return defaultLocaleRating.copy(id = defaultLocaleRating.title.lowercase()) } - val englishRating = fetchContentRating(appPackage, Locale.US) + val englishLocaleRating = fetchContentRating(appPackage, Locale.US) - return buildRating(defaultLocaleRating, englishRating) + return buildRating(defaultLocaleRating, englishLocaleRating) } private fun fetchContentRating( @@ -77,8 +79,8 @@ class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { // The default title can be in any language but the id will always be in English. private fun buildRating( defaultLocaleRating: ContentRating, - englishRating: ContentRating - ) = defaultLocaleRating.copy(id = englishRating.title.lowercase()) + otherLocaleRating: ContentRating + ) = defaultLocaleRating.copy(id = otherLocaleRating.title.lowercase()) private fun getAppDetails( packageName: String, locale: Locale = Locale.getDefault() -- GitLab From d95d34965ea038e8e4112c813086b642f97edeb9 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 23 May 2024 11:09:07 +0600 Subject: [PATCH 4/4] Optimize content rating helper in GPlayApi Optimize ContentRatingHelper by removing unnecessary code and updating function for content rating retrieval. The updateContentRatingWithId function now avoids an extra network call when the device's language is English, and handles ApiException.AppNotFound for other languages. Also, remove the equals and hashCode methods from ContentRating model as they are no longer needed. --- .../gplayapi/data/models/ContentRating.kt | 13 +----- .../gplayapi/helpers/ContentRatingHelper.kt | 42 ++++++------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt b/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt index 3ae479b..023a332 100644 --- a/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt +++ b/lib/src/main/java/com/aurora/gplayapi/data/models/ContentRating.kt @@ -11,15 +11,4 @@ data class ContentRating( val recommendation: String = String(), val artwork: Artwork = Artwork(), val recommendationAndDescriptionHtml: String = String() -) : Parcelable { - override fun equals(other: Any?): Boolean { - return when (other) { - is ContentRating -> this.artwork.url == other.artwork.url - else -> false - } - } - - override fun hashCode(): Int { - return this.artwork.url.hashCode() - } -} +) : Parcelable diff --git a/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt index 23f5f36..135f1f5 100644 --- a/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt +++ b/lib/src/main/java/com/aurora/gplayapi/helpers/ContentRatingHelper.kt @@ -39,33 +39,24 @@ class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { this.httpClient = httpClient } - /** - * Retrieves the [ContentRating] for a given app package based on the - * specified locale. - * - * @param appPackage The app's package name to fetch the content rating for. - * @param locale The locale to use for fetching the content rating. Defaults to the system's default locale. - * - * @return [ContentRating] The content rating for the app. The ID of the content rating will be the rating's title in English. - * @throws Exception Throws an exception if there is an issue fetching the content ratings. - */ - @Throws(Exception::class) - fun getContentRating( + fun updateContentRatingWithId( appPackage: String, - locale: Locale = Locale.getDefault() + currentContentRating: ContentRating, ): ContentRating { - val defaultLocaleRating = fetchContentRating(appPackage) - - // If the device's language is English, then the default rating will be in English. - // So, its title can be treated as an identifier for the rating. - // By returning early from here, we avoid an extra network call and further processing. - if (locale.language == Locale.ENGLISH.language) { - return defaultLocaleRating.copy(id = defaultLocaleRating.title.lowercase()) + // If the device's language is English, the default rating will be in English. + // So, its title can already be treated as an identifier for the rating. + if (Locale.getDefault().language == Locale.ENGLISH.language) { + return currentContentRating.copy(id = currentContentRating.title.lowercase()) } - val englishLocaleRating = fetchContentRating(appPackage, Locale.US) + return try { + val englishLocaleContentRating = fetchContentRating(appPackage, Locale.US) - return buildRating(defaultLocaleRating, englishLocaleRating) + // For rating in other languages, we set the English title as its ID + currentContentRating.copy(id = englishLocaleContentRating.title.lowercase()) + } catch (appNotFoundException: ApiException.AppNotFound) { + currentContentRating + } } private fun fetchContentRating( @@ -75,13 +66,6 @@ class ContentRatingHelper(authData: AuthData) : BaseHelper(authData) { return AppBuilder.build(response).contentRating } - // Sets the English title as the ID for the rating. - // The default title can be in any language but the id will always be in English. - private fun buildRating( - defaultLocaleRating: ContentRating, - otherLocaleRating: ContentRating - ) = defaultLocaleRating.copy(id = otherLocaleRating.title.lowercase()) - private fun getAppDetails( packageName: String, locale: Locale = Locale.getDefault() ): DetailsResponse { -- GitLab