diff options
author | Thomas <tschneider.ac@gmail.com> | 2022-04-27 15:20:42 +0200 |
---|---|---|
committer | Thomas <tschneider.ac@gmail.com> | 2022-04-27 15:20:42 +0200 |
commit | 0f855c5ac2dccbc1c1df99b9d5ee17d6293d82df (patch) | |
tree | 157224e6752e2facae194034e2e709d23a04fc7d /ratethisapp |
first commit
Diffstat (limited to 'ratethisapp')
36 files changed, 861 insertions, 0 deletions
diff --git a/ratethisapp/.gitignore b/ratethisapp/.gitignore new file mode 100644 index 000000000..4380595bb --- /dev/null +++ b/ratethisapp/.gitignore @@ -0,0 +1,23 @@ +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Eclipse project files +.classpath +.project + +.DS_Store diff --git a/ratethisapp/build.gradle b/ratethisapp/build.gradle new file mode 100644 index 000000000..f4cd3f1a8 --- /dev/null +++ b/ratethisapp/build.gradle @@ -0,0 +1,22 @@ +apply plugin: "com.android.library" + +android { + compileSdkVersion 31 + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 31 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + } + } +} + +dependencies { + implementation 'androidx.annotation:annotation:1.3.0' +} diff --git a/ratethisapp/gradle.properties b/ratethisapp/gradle.properties new file mode 100644 index 000000000..f12455b76 --- /dev/null +++ b/ratethisapp/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=Android-RateThisApp Library +POM_ARTIFACT_ID=ratethisapp +POM_PACKAGING=aar diff --git a/ratethisapp/proguard-rules.pro b/ratethisapp/proguard-rules.pro new file mode 100644 index 000000000..5b86c0858 --- /dev/null +++ b/ratethisapp/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/ratethisapp/src/main/AndroidManifest.xml b/ratethisapp/src/main/AndroidManifest.xml new file mode 100644 index 000000000..380ea47b7 --- /dev/null +++ b/ratethisapp/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ +<manifest package="com.kobakei.ratethisapp"> + +</manifest> diff --git a/ratethisapp/src/main/java/com/kobakei/ratethisapp/RateThisApp.java b/ratethisapp/src/main/java/com/kobakei/ratethisapp/RateThisApp.java new file mode 100644 index 000000000..2398363de --- /dev/null +++ b/ratethisapp/src/main/java/com/kobakei/ratethisapp/RateThisApp.java @@ -0,0 +1,516 @@ +/* + * Copyright 2013-2017 Keisuke Kobayashi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.kobakei.ratethisapp; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; +import android.view.KeyEvent; + +import androidx.annotation.StringRes; + +import java.lang.ref.WeakReference; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * RateThisApp<br> + * A library to show the app rate dialog + * + * @author Keisuke Kobayashi (k.kobayashi.122@gmail.com) + */ +public class RateThisApp { + + /** + * If true, print LogCat + */ + public static final boolean DEBUG = false; + private static final String TAG = RateThisApp.class.getSimpleName(); + private static final String PREF_NAME = "RateThisApp"; + private static final String KEY_INSTALL_DATE = "rta_install_date"; + private static final String KEY_LAUNCH_TIMES = "rta_launch_times"; + private static final String KEY_OPT_OUT = "rta_opt_out"; + private static final String KEY_ASK_LATER_DATE = "rta_ask_later_date"; + private static Date mInstallDate = new Date(); + private static int mLaunchTimes = 0; + private static boolean mOptOut = false; + private static Date mAskLaterDate = new Date(); + private static Config sConfig = new Config(); + private static Callback sCallback = null; + // Weak ref to avoid leaking the context + private static WeakReference<AlertDialog> sDialogRef = null; + + /** + * Initialize RateThisApp configuration. + * + * @param config Configuration object. + */ + public static void init(Config config) { + sConfig = config; + } + + /** + * Set callback instance. + * The callback will receive yes/no/later events. + * + * @param callback + */ + public static void setCallback(Callback callback) { + sCallback = callback; + } + + /** + * Call this API when the launcher activity is launched.<br> + * It is better to call this API in onCreate() of the launcher activity. + * + * @param context Context + */ + public static void onCreate(Context context) { + SharedPreferences pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + Editor editor = pref.edit(); + // If it is the first launch, save the date in shared preference. + if (pref.getLong(KEY_INSTALL_DATE, 0) == 0L) { + storeInstallDate(context, editor); + } + // Increment launch times + int launchTimes = pref.getInt(KEY_LAUNCH_TIMES, 0); + launchTimes++; + editor.putInt(KEY_LAUNCH_TIMES, launchTimes); + log("Launch times; " + launchTimes); + + editor.apply(); + + mInstallDate = new Date(pref.getLong(KEY_INSTALL_DATE, 0)); + mLaunchTimes = pref.getInt(KEY_LAUNCH_TIMES, 0); + mOptOut = pref.getBoolean(KEY_OPT_OUT, false); + mAskLaterDate = new Date(pref.getLong(KEY_ASK_LATER_DATE, 0)); + + printStatus(context); + } + + /** + * This API is deprecated. + * You should call onCreate instead of this API in Activity's onCreate(). + * + * @param context + */ + @Deprecated + public static void onStart(Context context) { + onCreate(context); + } + + /** + * Show the rate dialog if the criteria is satisfied. + * + * @param context Context + * @return true if shown, false otherwise. + */ + public static boolean showRateDialogIfNeeded(final Context context) { + if (shouldShowRateDialog()) { + showRateDialog(context); + return true; + } else { + return false; + } + } + + /** + * Show the rate dialog if the criteria is satisfied. + * + * @param context Context + * @param themeId Theme ID + * @return true if shown, false otherwise. + */ + public static boolean showRateDialogIfNeeded(final Context context, int themeId) { + if (shouldShowRateDialog()) { + showRateDialog(context, themeId); + return true; + } else { + return false; + } + } + + /** + * Check whether the rate dialog should be shown or not. + * Developers may call this method directly if they want to show their own view instead of + * dialog provided by this library. + * + * @return + */ + public static boolean shouldShowRateDialog() { + if (mOptOut) { + return false; + } else { + if (mLaunchTimes >= sConfig.mCriteriaLaunchTimes) { + return true; + } + long threshold = TimeUnit.DAYS.toMillis(sConfig.mCriteriaInstallDays); // msec + return new Date().getTime() - mInstallDate.getTime() >= threshold && + new Date().getTime() - mAskLaterDate.getTime() >= threshold; + } + } + + /** + * Show the rate dialog + * + * @param context + */ + public static void showRateDialog(final Context context) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + showRateDialog(context, builder); + } + + /** + * Show the rate dialog + * + * @param context + * @param themeId + */ + public static void showRateDialog(final Context context, int themeId) { + AlertDialog.Builder builder = new AlertDialog.Builder(context, themeId); + showRateDialog(context, builder); + } + + /** + * Stop showing the rate dialog + * + * @param context + */ + public static void stopRateDialog(final Context context) { + setOptOut(context, true); + } + + /** + * Get count number of the rate dialog launches + * + * @return + */ + public static int getLaunchCount(final Context context) { + SharedPreferences pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + return pref.getInt(KEY_LAUNCH_TIMES, 0); + } + + private static void showRateDialog(final Context context, AlertDialog.Builder builder) { + if (sDialogRef != null && sDialogRef.get() != null) { + // Dialog is already present + return; + } + + int titleId = sConfig.mTitleId != 0 ? sConfig.mTitleId : R.string.rta_dialog_title; + int messageId = sConfig.mMessageId != 0 ? sConfig.mMessageId : R.string.rta_dialog_message; + int cancelButtonID = sConfig.mCancelButton != 0 ? sConfig.mCancelButton : R.string.rta_dialog_cancel; + int thanksButtonID = sConfig.mNoButtonId != 0 ? sConfig.mNoButtonId : R.string.rta_dialog_no; + int rateButtonID = sConfig.mYesButtonId != 0 ? sConfig.mYesButtonId : R.string.rta_dialog_ok; + builder.setTitle(titleId); + builder.setMessage(messageId); + switch (sConfig.mCancelMode) { + case Config.CANCEL_MODE_BACK_KEY_OR_TOUCH_OUTSIDE: + builder.setCancelable(true); // It's the default anyway + break; + case Config.CANCEL_MODE_BACK_KEY: + builder.setCancelable(false); + builder.setOnKeyListener(new DialogInterface.OnKeyListener() { + @Override + public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + dialog.cancel(); + return true; + } else { + return false; + } + } + }); + break; + case Config.CANCEL_MODE_NONE: + builder.setCancelable(false); + break; + } + builder.setPositiveButton(rateButtonID, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (sCallback != null) { + sCallback.onYesClicked(); + } + String appPackage = context.getPackageName(); + String url = "market://details?id=" + appPackage; + if (!TextUtils.isEmpty(sConfig.mUrl)) { + url = sConfig.mUrl; + } + try { + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); + } catch (android.content.ActivityNotFoundException anfe) { + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + context.getPackageName()))); + } + setOptOut(context, true); + } + }); + builder.setNeutralButton(cancelButtonID, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (sCallback != null) { + sCallback.onCancelClicked(); + } + clearSharedPreferences(context); + storeAskLaterDate(context); + } + }); + builder.setNegativeButton(thanksButtonID, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (sCallback != null) { + sCallback.onNoClicked(); + } + setOptOut(context, true); + } + }); + builder.setOnCancelListener(new OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + if (sCallback != null) { + sCallback.onCancelClicked(); + } + clearSharedPreferences(context); + storeAskLaterDate(context); + } + }); + builder.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + sDialogRef.clear(); + } + }); + sDialogRef = new WeakReference<>(builder.show()); + } + + /** + * Clear data in shared preferences.<br> + * This API is called when the "Later" is pressed or canceled. + * + * @param context + */ + private static void clearSharedPreferences(Context context) { + SharedPreferences pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + Editor editor = pref.edit(); + editor.remove(KEY_INSTALL_DATE); + editor.remove(KEY_LAUNCH_TIMES); + editor.apply(); + } + + /** + * Set opt out flag. + * If it is true, the rate dialog will never shown unless app data is cleared. + * This method is called when Yes or No is pressed. + * + * @param context + * @param optOut + */ + private static void setOptOut(final Context context, boolean optOut) { + SharedPreferences pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + Editor editor = pref.edit(); + editor.putBoolean(KEY_OPT_OUT, optOut); + editor.apply(); + mOptOut = optOut; + } + + /** + * Store install date. + * Install date is retrieved from package manager if possible. + * + * @param context + * @param editor + */ + private static void storeInstallDate(final Context context, SharedPreferences.Editor editor) { + Date installDate = new Date(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + PackageManager packMan = context.getPackageManager(); + try { + PackageInfo pkgInfo = packMan.getPackageInfo(context.getPackageName(), 0); + installDate = new Date(pkgInfo.firstInstallTime); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + editor.putLong(KEY_INSTALL_DATE, installDate.getTime()); + log("First install: " + installDate); + } + + /** + * Store the date the user asked for being asked again later. + * + * @param context + */ + private static void storeAskLaterDate(final Context context) { + SharedPreferences pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + Editor editor = pref.edit(); + editor.putLong(KEY_ASK_LATER_DATE, System.currentTimeMillis()); + editor.apply(); + } + + /** + * Print values in SharedPreferences (used for debug) + * + * @param context + */ + private static void printStatus(final Context context) { + SharedPreferences pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + log("*** RateThisApp Status ***"); + log("Install Date: " + new Date(pref.getLong(KEY_INSTALL_DATE, 0))); + log("Launch Times: " + pref.getInt(KEY_LAUNCH_TIMES, 0)); + log("Opt out: " + pref.getBoolean(KEY_OPT_OUT, false)); + } + + /** + * Print log if enabled + * + * @param message + */ + private static void log(String message) { + if (DEBUG) { + Log.v(TAG, message); + } + } + + /** + * Callback of dialog click event + */ + public interface Callback { + /** + * "Rate now" event + */ + void onYesClicked(); + + /** + * "No, thanks" event + */ + void onNoClicked(); + + /** + * "Later" event + */ + void onCancelClicked(); + } + + /** + * RateThisApp configuration. + */ + public static class Config { + public static final int CANCEL_MODE_BACK_KEY_OR_TOUCH_OUTSIDE = 0; + public static final int CANCEL_MODE_BACK_KEY = 1; + public static final int CANCEL_MODE_NONE = 2; + private final int mCriteriaInstallDays; + private final int mCriteriaLaunchTimes; + private String mUrl = null; + private int mTitleId = 0; + private int mMessageId = 0; + private int mYesButtonId = 0; + private int mNoButtonId = 0; + private int mCancelButton = 0; + private int mCancelMode = CANCEL_MODE_BACK_KEY_OR_TOUCH_OUTSIDE; + + /** + * Constructor with default criteria. + */ + public Config() { + this(7, 10); + } + + /** + * Constructor. + * + * @param criteriaInstallDays + * @param criteriaLaunchTimes + */ + public Config(int criteriaInstallDays, int criteriaLaunchTimes) { + this.mCriteriaInstallDays = criteriaInstallDays; + this.mCriteriaLaunchTimes = criteriaLaunchTimes; + } + + /** + * Set title string ID. + * + * @param stringId + */ + public void setTitle(@StringRes int stringId) { + this.mTitleId = stringId; + } + + /** + * Set message string ID. + * + * @param stringId + */ + public void setMessage(@StringRes int stringId) { + this.mMessageId = stringId; + } + + /** + * Set rate now string ID. + * + * @param stringId + */ + public void setYesButtonText(@StringRes int stringId) { + this.mYesButtonId = stringId; + } + + /** + * Set no thanks string ID. + * + * @param stringId + */ + public void setNoButtonText(@StringRes int stringId) { + this.mNoButtonId = stringId; + } + + /** + * Set cancel string ID. + * + * @param stringId + */ + public void setCancelButtonText(@StringRes int stringId) { + this.mCancelButton = stringId; + } + + /** + * Set navigation url when user clicks rate button. + * Typically, url will be https://play.google.com/store/apps/details?id=PACKAGE_NAME for Google Play. + * + * @param url + */ + public void setUrl(String url) { + this.mUrl = url; + } + + /** + * Set the cancel mode; namely, which ways the user can cancel the dialog. + * + * @param cancelMode + */ + public void setCancelMode(int cancelMode) { + this.mCancelMode = cancelMode; + } + } +} diff --git a/ratethisapp/src/main/res/value-vi/string.xml b/ratethisapp/src/main/res/value-vi/string.xml new file mode 100644 index 000000000..9303d87fa --- /dev/null +++ b/ratethisapp/src/main/res/value-vi/string.xml @@ -0,0 +1,11 @@ +<resources> + + <string name="rta_dialog_title">Đánh giá ứng dụng này</string> + <string name="rta_dialog_message">Nếu bạn thích ứng dụng này, bạn có phiền nếu dành một chút + thời gian để đánh giá ứng dụng? Nó sẽ không mất thời gian của bạn hơn một phút. Cám ơn sự hỗ + trợ của bạn rất nhiều! + </string> + <string name="rta_dialog_ok">Rate ngay và luôn</string> + <string name="rta_dialog_cancel">Để sau nha</string> + <string name="rta_dialog_no">Không hiện lại nữa</string> +</resources> diff --git a/ratethisapp/src/main/res/values-ar/strings.xml b/ratethisapp/src/main/res/values-ar/strings.xml new file mode 100644 index 000000000..1c0fb4fbd --- /dev/null +++ b/ratethisapp/src/main/res/values-ar/strings.xml @@ -0,0 +1,9 @@ +<resources> + + <string name="rta_dialog_title">قيم هذا التطبيق</string> + <string name="rta_dialog_message">إذا احببت هذا التطبيق أبدي ملاحظاتك ، افكارك من خلال تقييمه على سوق بلاي</string> + <string name="rta_dialog_ok">تقييم</string> + <string name="rta_dialog_cancel">لاحقا</string> + <string name="rta_dialog_no">لا شكرا</string> + +</resources> diff --git a/ratethisapp/src/main/res/values-az/strings.xml b/ratethisapp/src/main/res/values-az/strings.xml new file mode 100644 index 000000000..d2599de70 --- /dev/null +++ b/ratethisapp/src/main/res/values-az/strings.xml @@ -0,0 +1,9 @@ +<resources> + + <string name="rta_dialog_title">Bu tətbiqi dəyərləndirin</string> + <string name="rta_dialog_message">Əgər tətbiqdən razı qaldınızsa, zəhmət olmasa bir neçə saniyənizi ayırıb tətbiqi dəyərləndirin. Dəstəyiniz üçün təşəkkür edirik!</string> + <string name="rta_dialog_ok">Qiymətləndir</string> + <string name="rta_dialog_cancel">Sonra xatırlat</string> + <string name="rta_dialog_no">İmtina et</string> + +</resources> diff --git a/ratethisapp/src/main/res/values-bg/strings.xml b/ratethisapp/src/main/res/values-bg/strings.xml new file mode 100644 index 000000000..3a1021e9d --- /dev/null +++ b/ratethisapp/src/main/res/values-bg/strings.xml @@ -0,0 +1,9 @@ +<resources> + + <string name="rta_dialog_title">Оцени приложението</string> + <string name="rta_dialog_message">Ако харесвате приложението, моля отделете малко време, за да го оцените. Няма да отнеме повече от минута. Благодаря за подкрепата!</string> + <string name="rta_dialog_ok">Оцени сега</string> + <string name="rta_dialog_cancel">По-късно</string> + <string name="rta_dialog_no">Не, благодаря</string> + +</resources> diff --git a/ratethisapp/src/main/res/values-cs/strings.xml b/ratethisapp/src/main/res/values-cs/strings.xml new file mode 100644 index 000000000..d972161a6 --- /dev/null +++ b/ratethisapp/src/main/res/values-cs/strings.xml @@ -0,0 +1,9 @@ +<resources> + + <string name="rta_dialog_title">Ohodnotit aplikaci</string> + <string name="rta_dialog_message">Pokud se Vám aplikace líbí, rádi bychom Vás poprosili o její ohodnocení. Nezabere to více než minutu. Děkujeme za Vaši podporu!</string> + <string name="rta_dialog_ok">Ohodnotit nyní</string> + <string name="rta_dialog_cancel">Připomenout později</string> + <string name="rta_dialog_no">Ne, díky</string> + +</resources> diff --git a/ratethisapp/src/main/res/values-da/strings.xml b/ratethisapp/src/main/res/values-da/strings.xml new file mode 100644 index 000000000..ddc3b3e8d --- /dev/null +++ b/ratethisapp/src/main/res/values-da/strings.xml @@ -0,0 +1,9 @@ +<resources> + + <string name="rta_dialog_title">Bedøm appen</string> + <string name="rta |