diff --git a/CHANGELOG.md b/CHANGELOG.md index c40eff41..10e0255b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,7 @@ Emojis for the following are chosen based on [gitmoji](https://gitmoji.dev/). - The application and community's relationship to the Wikimedia movement is explained in app ([#52](https://github.com/scribe-org/Scribe-Android/issues/52)). - Vibrate on keypress and key click functionalities are included ([#405](https://github.com/scribe-org/Scribe-Android/issues/405), [#406](https://github.com/scribe-org/Scribe-Android/issues/406)). - An in-app tutorial is provided to detail functionalities of the application ([#602](https://github.com/scribe-org/Scribe-Android/issues/602), [#615](https://github.com/scribe-org/Scribe-Android/issues/615), [#616](https://github.com/scribe-org/Scribe-Android/issues/616)). -- The user is able to easily rate the application ([#165](https://github.com/scribe-org/Scribe-Android/issues/165), [#640](https://github.com/scribe-org/Scribe-Android/issues/640)). +- The user is able to easily rate the application, with installer-aware routing to the appropriate store ([#165](https://github.com/scribe-org/Scribe-Android/issues/165), [#640](https://github.com/scribe-org/Scribe-Android/issues/640)). ### 🗃️ Data diff --git a/CHANGELOG_CONJUGATE.md b/CHANGELOG_CONJUGATE.md index 91fd8f97..6c62a4a5 100644 --- a/CHANGELOG_CONJUGATE.md +++ b/CHANGELOG_CONJUGATE.md @@ -31,7 +31,7 @@ Emojis for the following are chosen based on [gitmoji](https://gitmoji.dev/). - The Settings tab for the Scribe keyboard application was migrated to allow base settings for the app interface ([#562](https://github.com/scribe-org/Scribe-Android/issues/562)). - The About tab for the Scribe keyboard application was migrated to provide information on the application and community ([#561](https://github.com/scribe-org/Scribe-Android/issues/561)). - The application and community's relationship to the Wikimedia movement is explained in app ([#52](https://github.com/scribe-org/Scribe-Android/issues/52)). -- The user is able to easily rate the application ([#165](https://github.com/scribe-org/Scribe-Android/issues/165), [#640](https://github.com/scribe-org/Scribe-Android/issues/640)). +- The user is able to easily rate the application, with installer-aware routing to the appropriate store ([#165](https://github.com/scribe-org/Scribe-Android/issues/165), [#640](https://github.com/scribe-org/Scribe-Android/issues/640)). ### 🗃️ Data diff --git a/app/src/main/assets/i18n b/app/src/main/assets/i18n index 88ffe39c..77247dae 160000 --- a/app/src/main/assets/i18n +++ b/app/src/main/assets/i18n @@ -1 +1 @@ -Subproject commit 88ffe39cb72c192ea8f987f4ccb18d486d04f403 +Subproject commit 77247daeaa90eea2e7a0ac4e285986a1c01822ff diff --git a/app/src/main/java/be/scri/helpers/ui/RatingHelper.kt b/app/src/main/java/be/scri/helpers/ui/RatingHelper.kt index 87823929..96b6bc11 100644 --- a/app/src/main/java/be/scri/helpers/ui/RatingHelper.kt +++ b/app/src/main/java/be/scri/helpers/ui/RatingHelper.kt @@ -1,13 +1,16 @@ // SPDX-License-Identifier: GPL-3.0-or-later package be.scri.helpers.ui +import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri +import android.os.Build import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity +import be.scri.R import com.google.android.play.core.review.ReviewManagerFactory /** @@ -20,6 +23,13 @@ import com.google.android.play.core.review.ReviewManagerFactory object RatingHelper { private const val INSTALLER_PLAY_STORE = "com.android.vending" private const val INSTALLER_FDROID = "org.fdroid.fdroid" + private const val INSTALLER_AMAZON = "com.amazon.venezia" + private const val INSTALLER_SAMSUNG = "com.sec.android.app.samsungapps" + + private const val URL_PLAY_STORE = "https://play.google.com/store/apps/details?id=%s" + private const val URL_FDROID = "https://f-droid.org/packages/%s" + private const val URL_AMAZON = "https://www.amazon.com/gp/mas/dl/android?p=%s" + private const val URL_SAMSUNG = "https://galaxystore.samsung.com/detail/%s" /** * Gets the package name of the app that installed this app. @@ -31,12 +41,54 @@ object RatingHelper { */ private fun getInstallSource(context: Context): String? = try { - context.packageManager.getInstallerPackageName(context.packageName) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + context.packageManager.getInstallSourceInfo(context.packageName).installingPackageName + } else { + @Suppress("DEPRECATION") + context.packageManager.getInstallerPackageName(context.packageName) + } } catch (e: PackageManager.NameNotFoundException) { Log.e("RatingHelper", "Failed to get install source", e) null } + /** + * Gets the store description text (e.g. "Rate us on Google Play Store"). + * + * @param context App context. + * @return String for the description. + */ + fun getStoreDesc(context: Context): String? = + when (getInstallSource(context)) { + INSTALLER_PLAY_STORE -> context.getString(R.string.i18n_app_about_feedback_rate_description_google_play) + INSTALLER_FDROID -> context.getString(R.string.i18n_app_about_feedback_rate_description_f_droid) + INSTALLER_AMAZON -> context.getString(R.string.i18n_app_about_feedback_rate_description_amazon) + INSTALLER_SAMSUNG -> context.getString(R.string.i18n_app_about_feedback_rate_description_galaxy) + else -> context.getString(R.string.i18n_app_about_feedback_rate_description_google_play) + } + + /** + * Opens store page in browser + * + * @param context App context. + * @param urlTemplate URL format string. + * @param storeName Store name. + */ + private fun openStore( + context: Context, + urlTemplate: String, + storeName: String, + ) { + val url = urlTemplate.format(context.packageName) + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + try { + context.startActivity(intent) + } catch (e: ActivityNotFoundException) { + Toast.makeText(context, "No browser found to open $storeName page", Toast.LENGTH_SHORT).show() + Log.e("RatingHelper", "Unable to open $storeName link", e) + } + } + /** * Initiates the app rating process based on the installation source. * @@ -51,7 +103,8 @@ object RatingHelper { context: Context, activity: ComponentActivity, ) { - when (getInstallSource(context)) { + val installer = getInstallSource(context) + when (installer) { INSTALLER_PLAY_STORE -> { val reviewManager = ReviewManagerFactory.create(context) val request = reviewManager.requestReviewFlow() @@ -63,25 +116,18 @@ object RatingHelper { .launchReviewFlow(activity, reviewInfo) .addOnCompleteListener { } } else { - Toast.makeText(context, "Failed to launch review flow", Toast.LENGTH_SHORT).show() + openStore(context, URL_PLAY_STORE, "Play Store") } } } - INSTALLER_FDROID -> { - val url = "https://f-droid.org/packages/${context.packageName}" - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - try { - context.startActivity(intent) - } catch (e: PackageManager.NameNotFoundException) { - Toast.makeText(context, "No browser found to open F-Droid page", Toast.LENGTH_SHORT).show() - Log.e("RatingHelper", "Unable to open F-Droid link", e) - } - } + INSTALLER_FDROID -> openStore(context, URL_FDROID, "F-Droid") - else -> { - Toast.makeText(context, "Unknown installation source", Toast.LENGTH_SHORT).show() - } + INSTALLER_AMAZON -> openStore(context, URL_AMAZON, "Amazon") + + INSTALLER_SAMSUNG -> openStore(context, URL_SAMSUNG, "Galaxy Store") + + else -> openStore(context, URL_PLAY_STORE, "Play Store") } } } diff --git a/app/src/main/java/be/scri/ui/common/components/AboutPageItemComp.kt b/app/src/main/java/be/scri/ui/common/components/AboutPageItemComp.kt index 4bc29fc6..fa0aab14 100644 --- a/app/src/main/java/be/scri/ui/common/components/AboutPageItemComp.kt +++ b/app/src/main/java/be/scri/ui/common/components/AboutPageItemComp.kt @@ -36,6 +36,7 @@ fun AboutPageItemComp( trailingIcon: Int, onClick: () -> Unit, modifier: Modifier = Modifier, + descText: String? = null, altText: String? = null, ) { val semanticsModifier = @@ -72,12 +73,23 @@ fun AboutPageItemComp( contentDescription = "Leading Icon", ) Spacer(modifier = Modifier.width(8.dp)) - Text( - text = title, + androidx.compose.foundation.layout.Column( modifier = Modifier.weight(1f).padding(start = 4.dp), - color = MaterialTheme.colorScheme.onSurface, - style = MaterialTheme.typography.bodyMedium, - ) + ) { + Text( + text = title, + color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.bodyMedium, + ) + if (descText != null) { + Text( + text = descText, + color = Color.Gray, + style = MaterialTheme.typography.bodySmall, + modifier = Modifier.padding(top = 4.dp), + ) + } + } Icon( painter = painterResource(trailingIcon), modifier = diff --git a/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt b/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt index d92e4ab4..bfc948bb 100644 --- a/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt +++ b/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt @@ -64,6 +64,7 @@ fun ItemsCardContainer( is ScribeItem.ExternalLinkItem -> { AboutPageItemComp( title = stringResource(item.title), + descText = item.descText, altText = item.altText?.let { stringResource(it) }, leadingIcon = item.leadingIcon, trailingIcon = item.trailingIcon, diff --git a/app/src/main/java/be/scri/ui/models/ScribeItem.kt b/app/src/main/java/be/scri/ui/models/ScribeItem.kt index c52eaee9..1a56f28b 100644 --- a/app/src/main/java/be/scri/ui/models/ScribeItem.kt +++ b/app/src/main/java/be/scri/ui/models/ScribeItem.kt @@ -64,6 +64,7 @@ sealed class ScribeItem( data class ExternalLinkItem( override val title: Int, override val desc: Int? = null, + val descText: String? = null, override val altText: Int? = null, @DrawableRes val leadingIcon: Int, @DrawableRes val trailingIcon: Int, diff --git a/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt b/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt index 6eb6e342..5af84924 100644 --- a/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt +++ b/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt @@ -143,6 +143,7 @@ fun feedbackAndSupportList( } else { R.string.i18n_app_about_feedback_rate_scribe }, + descText = RatingHelper.getStoreDesc(context), trailingIcon = R.drawable.external_link, url = null, onClick = { onRateScribeClick() }, diff --git a/app/src/main/res/values/string.xml b/app/src/main/res/values/string.xml index 7fba4313..117e8923 100644 --- a/app/src/main/res/values/string.xml +++ b/app/src/main/res/values/string.xml @@ -51,6 +51,10 @@ Wikipedia is a multilingual free online encyclopedia written and maintained by a community of volunteers through open collaboration and a wiki-based editing system. Scribe uses data from Wikipedia to produce autosuggestions by deriving the most common words in a language as well as the most common words that follow them. Report a bug Rate Scribe Conjugate + Rate us on Amazon Appstore + Rate us on F-Droid + Rate us on Galaxy Store + Rate us on Google Play Store Rate Scribe Reset app hints Send us an email