diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..7d61466
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,4 @@
+# These are supported funding model platforms
+
+github: [fanmixco]
+custom: ['https://www.buymeacoffee.com/fanmixco']
diff --git a/.gitignore b/.gitignore
index 37a96c4..b84cefa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@ captures/
# IntelliJ
*.iml
+.idea
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
@@ -62,4 +63,5 @@ fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
-fastlane/readme.md
\ No newline at end of file
+fastlane/readme.md
+*.hprof
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 30aa626..0d15693 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,29 +1,134 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index 9f1bae2..0000000
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..19364dc
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 99202cc..af0bbdd 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,29 +1,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index c2b81ab..a19cef9 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,12 +2,9 @@
-
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index e46958d..b9b1ecd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,29 +1,18 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
buildscript {
repositories {
jcenter()
- maven {
- url 'https://maven.google.com/'
- name 'Google'
- }
+ mavenCentral() // Use mavenCentral() instead of jcenter()
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
- classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' // Add this line
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
+ classpath 'com.android.tools.build:gradle:8.5.1'
+ // Update to the latest stable version (7.5.2)
}
}
allprojects {
repositories {
- jcenter()
- maven {
- url 'https://maven.google.com/'
- name 'Google'
- }
+ mavenCentral()
+ google()
}
}
diff --git a/fivestarslibrary/build.gradle b/fivestarslibrary/build.gradle
index 5a81f61..5015f64 100644
--- a/fivestarslibrary/build.gradle
+++ b/fivestarslibrary/build.gradle
@@ -1,17 +1,13 @@
apply plugin: 'com.android.library'
-apply plugin: 'com.github.dcendents.android-maven'
group='com.github.Angtrim'
android {
- compileSdkVersion 27
- buildToolsVersion '28.0.3'
+ compileSdk 34
defaultConfig {
- minSdkVersion 14
- targetSdkVersion 27
- versionCode 1
- versionName "1.0"
+ minSdkVersion 21
+ targetSdkVersion 34
}
buildTypes {
release {
@@ -19,10 +15,13 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ namespace 'angtrim.com.fivestarslibrary'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:27.1.1'
+ implementation 'androidx.appcompat:appcompat:1.7.0'
+ implementation 'com.google.android.gms:play-services-tasks:18.2.0'
+ implementation 'com.google.android.play:review:2.0.1'
}
diff --git a/fivestarslibrary/src/main/AndroidManifest.xml b/fivestarslibrary/src/main/AndroidManifest.xml
index eecb416..6f1f94b 100644
--- a/fivestarslibrary/src/main/AndroidManifest.xml
+++ b/fivestarslibrary/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
diff --git a/fivestarslibrary/src/main/java/angtrim/com/fivestarslibrary/FiveStarsDialog.java b/fivestarslibrary/src/main/java/angtrim/com/fivestarslibrary/FiveStarsDialog.java
index 01047b4..37fde26 100644
--- a/fivestarslibrary/src/main/java/angtrim/com/fivestarslibrary/FiveStarsDialog.java
+++ b/fivestarslibrary/src/main/java/angtrim/com/fivestarslibrary/FiveStarsDialog.java
@@ -1,5 +1,6 @@
package angtrim.com.fivestarslibrary;
+import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -7,27 +8,45 @@
import android.graphics.PorterDuff;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
-import android.support.v7.app.AlertDialog;
-import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RatingBar;
import android.widget.TextView;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.Task;
+import com.google.android.play.core.review.ReviewInfo;
+import com.google.android.play.core.review.ReviewManager;
+import com.google.android.play.core.review.ReviewManagerFactory;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
/**
* Created by angtrim on 12/09/15.
*/
public class FiveStarsDialog implements DialogInterface.OnClickListener {
- private final static String DEFAULT_TITLE = "Rate this app";
- private final static String DEFAULT_TEXT = "How much do you love our app?";
private final static String SP_NUM_OF_ACCESS = "numOfAccess";
+ private final static String SP_MAX_DATE = "maxDate";
+ private final static String PATTERN = "yyyy/MM/dd";
private static final String SP_DISABLED = "disabled";
private static final String TAG = FiveStarsDialog.class.getSimpleName();
private final Context context;
private boolean isForceMode = false;
private final SharedPreferences sharedPrefs;
+ private String defaultTitle;
+
+ private String defaultText;
private String supportEmail;
private TextView contentTextView;
private RatingBar ratingBar;
@@ -38,13 +57,21 @@ public class FiveStarsDialog implements DialogInterface.OnClickListener {
private int upperBound = 4;
private NegativeReviewListener negativeReviewListener;
private ReviewListener reviewListener;
+ private InAppReviewListener inAppReviewListener;
private int starColor;
- private String positiveButtonText = "Ok";
- private String negativeButtonText = "Not Now";
- private String neutralButtonText = "Never";
+ private String positiveButtonText;
+ private String negativeButtonText;
+ private String neutralButtonText;
+ private boolean inAppReviewMode = false;
+ private boolean afterNDaysMode = false;
public FiveStarsDialog(Context context, String supportEmail) {
this.context = context;
+ negativeButtonText = context.getString(R.string.BtnLater);
+ positiveButtonText = context.getString(R.string.BtnOK);
+ neutralButtonText = context.getString(R.string.BtnNever);
+ defaultTitle = context.getString(R.string.RateApp);
+ defaultText = context.getString(R.string.DefaultText);
sharedPrefs = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
this.supportEmail = supportEmail;
}
@@ -53,17 +80,20 @@ private void build() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
LayoutInflater inflater = LayoutInflater.from(context);
dialogView = inflater.inflate(R.layout.stars, null);
- String titleToAdd = (title == null) ? DEFAULT_TITLE : title;
- String textToAdd = (rateText == null) ? DEFAULT_TEXT : rateText;
+ String titleToAdd = (title == null) ? defaultTitle : title;
+ String textToAdd = (rateText == null) ? defaultText : rateText;
contentTextView = dialogView.findViewById(R.id.text_content);
contentTextView.setText(textToAdd);
ratingBar = dialogView.findViewById(R.id.ratingBar);
ratingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
@Override
public void onRatingChanged(RatingBar ratingBar, float v, boolean b) {
- Log.d(TAG, "Rating changed : " + v);
if (isForceMode && v >= upperBound) {
- openMarket();
+ if (inAppReviewMode) {
+ launchInAppReview();
+ } else {
+ openMarket();
+ }
if (reviewListener != null)
reviewListener.onReview((int) ratingBar.getRating());
}
@@ -121,9 +151,56 @@ private void show() {
}
}
+ private boolean isMaxDateEmpty() {
+ if (!sharedPrefs.contains(SP_MAX_DATE)) {
+ return true;
+ }
+ else if (TextUtils.isEmpty(sharedPrefs.getString(SP_MAX_DATE, ""))) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
public void showAfter(int numberOfAccess) {
build();
SharedPreferences.Editor editor = sharedPrefs.edit();
+ if (!afterNDaysMode) {
+ defaultLaunch(numberOfAccess, editor);
+ }
+ else {
+ launchByDates(numberOfAccess, editor);
+ }
+ }
+
+ private void launchByDates(int numberOfAccess, SharedPreferences.Editor editor) {
+ Date maxDate;
+ if (isMaxDateEmpty()) {
+ Calendar c = Calendar.getInstance();
+ c.add(Calendar.DATE, numberOfAccess);
+
+ SimpleDateFormat formatter = new SimpleDateFormat(PATTERN);
+ maxDate = c.getTime();
+ editor.putString(SP_MAX_DATE, formatter.format(maxDate));
+ editor.apply();
+ } else {
+ try {
+ maxDate = new SimpleDateFormat(PATTERN).parse(sharedPrefs.getString(SP_MAX_DATE, ""));
+
+ long diffInMillie = Math.abs((new Date()).getTime() - maxDate.getTime());
+ long diff = TimeUnit.DAYS.convert(diffInMillie, TimeUnit.MILLISECONDS);
+
+ if (diff >= numberOfAccess) {
+ show();
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void defaultLaunch(int numberOfAccess, SharedPreferences.Editor editor) {
int numOfAccess = sharedPrefs.getInt(SP_NUM_OF_ACCESS, 0);
editor.putInt(SP_NUM_OF_ACCESS, numOfAccess + 1);
editor.apply();
@@ -135,28 +212,33 @@ public void showAfter(int numberOfAccess) {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
- if (i == DialogInterface.BUTTON_POSITIVE) {
- if (ratingBar.getRating() < upperBound) {
- if (negativeReviewListener == null) {
- sendEmail();
- } else {
- negativeReviewListener.onNegativeReview((int) ratingBar.getRating());
+ switch (i) {
+ case DialogInterface.BUTTON_POSITIVE:
+ if (ratingBar.getRating() < upperBound) {
+ if (negativeReviewListener == null) {
+ sendEmail();
+ } else {
+ negativeReviewListener.onNegativeReview((int) ratingBar.getRating());
+ }
+ } else if (!isForceMode) {
+ openMarket();
}
-
- } else if (!isForceMode) {
- openMarket();
- }
- disable();
- if (reviewListener != null)
- reviewListener.onReview((int) ratingBar.getRating());
- }
- if (i == DialogInterface.BUTTON_NEUTRAL) {
- disable();
- }
- if (i == DialogInterface.BUTTON_NEGATIVE) {
- SharedPreferences.Editor editor = sharedPrefs.edit();
- editor.putInt(SP_NUM_OF_ACCESS, 0);
- editor.apply();
+ disable();
+ if (reviewListener != null) {
+ reviewListener.onReview((int) ratingBar.getRating());
+ }
+ break;
+ case DialogInterface.BUTTON_NEUTRAL:
+ disable();
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ SharedPreferences.Editor editor = sharedPrefs.edit();
+ editor.putInt(SP_NUM_OF_ACCESS, 0);
+ if (sharedPrefs.contains(SP_MAX_DATE)) {
+ editor.putString(SP_MAX_DATE, "");
+ }
+ editor.apply();
+ break;
}
alertDialog.hide();
}
@@ -242,4 +324,60 @@ public FiveStarsDialog setReviewListener(ReviewListener listener) {
return this;
}
-}
+ /**
+ * Enable in-app review popup
+ *
+ * @param inAppReviewMode
+ * @return
+ */
+ public FiveStarsDialog setInAppReviewMode(boolean inAppReviewMode) {
+ this.inAppReviewMode = inAppReviewMode;
+ return this;
+ }
+
+ /**
+ * Set a listener to get notified when in app review flow completed, for example for tracking purposes
+ *
+ * Note that, The API does not indicate whether the user reviewed or not, or even whether the review dialog was shown
+ *
+ * @param inAppReviewListener
+ * @return
+ */
+ public FiveStarsDialog setInAppReviewListener(InAppReviewListener inAppReviewListener) {
+ this.inAppReviewListener = inAppReviewListener;
+ return this;
+ }
+
+ /**
+ *
+ * Enable launching after N days
+ * @param afterNDaysMode
+ * @return
+ */
+ public FiveStarsDialog setAfterNDaysMode(boolean afterNDaysMode) {
+ this.afterNDaysMode = afterNDaysMode;
+ return this;
+ }
+
+ private void launchInAppReview() {
+ final ReviewManager manager = ReviewManagerFactory.create(context);
+ Task request = manager.requestReviewFlow();
+ request.addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ if (context instanceof Activity) {
+ Task flow = manager.launchReviewFlow(((Activity) context), task.getResult());
+ flow.addOnCompleteListener(task1 -> {
+ if (inAppReviewListener != null) {
+ inAppReviewListener.onInAppReview();
+ }
+ });
+ flow.addOnFailureListener(e -> openMarket());
+ } else {
+ openMarket();
+ }
+ } else {
+ openMarket();
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/fivestarslibrary/src/main/java/angtrim/com/fivestarslibrary/InAppReviewListener.java b/fivestarslibrary/src/main/java/angtrim/com/fivestarslibrary/InAppReviewListener.java
new file mode 100644
index 0000000..296f4ed
--- /dev/null
+++ b/fivestarslibrary/src/main/java/angtrim/com/fivestarslibrary/InAppReviewListener.java
@@ -0,0 +1,5 @@
+package angtrim.com.fivestarslibrary;
+
+public interface InAppReviewListener {
+ void onInAppReview();
+}
diff --git a/fivestarslibrary/src/main/res/layout/stars.xml b/fivestarslibrary/src/main/res/layout/stars.xml
index 3c3bd79..fc5f690 100644
--- a/fivestarslibrary/src/main/res/layout/stars.xml
+++ b/fivestarslibrary/src/main/res/layout/stars.xml
@@ -1,23 +1,22 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/fivestarslibrary/src/main/res/values/strings.xml b/fivestarslibrary/src/main/res/values/strings.xml
index 3c5d2ce..74edfda 100644
--- a/fivestarslibrary/src/main/res/values/strings.xml
+++ b/fivestarslibrary/src/main/res/values/strings.xml
@@ -1,3 +1,8 @@
FiveStarsLibrary
-
+ Not now
+ OK
+ Never
+ Rate this app
+ How much do you love this app?
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 1d3591c..8ab82c2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,4 +15,8 @@
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
\ No newline at end of file
+# org.gradle.parallel=true
+android.defaults.buildfeatures.buildconfig=true
+android.nonFinalResIds=false
+android.nonTransitiveRClass=false
+android.useAndroidX=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f13c268..3ac0493 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Dec 14 15:24:32 EET 2018
+#Sun Aug 04 12:01:19 CEST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
diff --git a/sampleapp/build.gradle b/sampleapp/build.gradle
index ff8176e..1ac891c 100644
--- a/sampleapp/build.gradle
+++ b/sampleapp/build.gradle
@@ -1,26 +1,27 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 28
- buildToolsVersion '28.0.3'
+ compileSdk 34
defaultConfig {
applicationId "angtrim.com.sampleapp"
- minSdkVersion 14
- targetSdkVersion 28
+ minSdkVersion 21
+ targetSdkVersion 34
versionCode 1
versionName "1.0"
}
+
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ namespace 'angtrim.com.sampleapp'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:27.1.1'
+ implementation 'androidx.appcompat:appcompat:1.7.0'
implementation project(':fivestarslibrary')
-}
+}
\ No newline at end of file
diff --git a/sampleapp/src/main/AndroidManifest.xml b/sampleapp/src/main/AndroidManifest.xml
index 8976761..634b326 100644
--- a/sampleapp/src/main/AndroidManifest.xml
+++ b/sampleapp/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/sampleapp/src/main/java/angtrim/com/sampleapp/MainActivity.java b/sampleapp/src/main/java/angtrim/com/sampleapp/MainActivity.java
index 4e67837..4fecb53 100644
--- a/sampleapp/src/main/java/angtrim/com/sampleapp/MainActivity.java
+++ b/sampleapp/src/main/java/angtrim/com/sampleapp/MainActivity.java
@@ -1,11 +1,10 @@
package angtrim.com.sampleapp;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
-
import angtrim.com.fivestarslibrary.FiveStarsDialog;
import angtrim.com.fivestarslibrary.NegativeReviewListener;
import angtrim.com.fivestarslibrary.ReviewListener;
@@ -26,6 +25,8 @@ protected void onCreate(Bundle savedInstanceState) {
.setUpperBound(2)
.setNegativeReviewListener(this)
.setReviewListener(this)
+ .setInAppReviewMode(true)
+ .setAfterNDaysMode(true)
.showAfter(0);
}