Skip to content

Commit 0be17d8

Browse files
authored
Merge pull request #18 from SuddenH4X/release/2.2.0
Release/2.2.0
2 parents 6ab51c2 + 677825f commit 0be17d8

14 files changed

Lines changed: 318 additions & 60 deletions

File tree

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@ A highly customizable Android library providing a dialog, which asks the user to
66

77
![showcase](https://github.com/SuddenH4X/awesome-app-rating/raw/develop/preview/showcase.png)
88

9+
10+
11+
You can also use this library to show the [Google in-app review](https://developer.android.com/guide/playcore/in-app-review) easily under certain conditions:
12+
13+
<img src="https://developer.android.com/images/google/play/in-app-review/iar-flow.jpg" alt="In app review workflow for a user" />
14+
15+
(Source: https://developer.android.com/guide/playcore/in-app-review)
16+
917
## Features
18+
- Let the dialog (or the [Google in-app review](https://developer.android.com/guide/playcore/in-app-review)) show up at a defined app session, after n days of usage and/or if your custom conditions meet
1019
- Auto fetches the app icon to use it in the dialog
11-
- Let the dialog show up at a defined app session, after n days of usage and/or if your custom conditions meet
1220
- Ask the user to mail his feedback or show a custom feedback form if the user rates below the defined minimum threshold
1321
- All titles, messages and buttons are customizable
1422
- You can override all click listeners to fit your needs (or to implement extensive tracking)
@@ -32,7 +40,7 @@ The library supports API level 14 and higher. You can simply include it in your
3240
```groovy
3341
dependencies {
3442
...
35-
implementation 'com.suddenh4x.ratingdialog:awesome-app-rating:2.1.1'
43+
implementation 'com.suddenh4x.ratingdialog:awesome-app-rating:2.2.0'
3644
}
3745
```
3846

@@ -83,6 +91,22 @@ ratingBuilder.showNow()
8391

8492
Between the constructor and the show or create method you can adjust the dialog to suit your preferences. You have the following options:
8593

94+
#### Google in-app review
95+
96+
If you want to use the in-app review from Google instead of the library dialog, call the following function:
97+
98+
```kotlin
99+
.useGoogleInAppReview()
100+
```
101+
102+
You should also add a `completeListener` which gets called if the in-app review flow has been completed. The boolean indicates if the flow started correctly, but not if the in-app review was displayed to the user.
103+
104+
```kotlin
105+
.setGoogleInAppReviewCompleteListener(googleInAppReviewCompleteListener: (Boolean) -> Unit)
106+
```
107+
108+
Note: After the first in-app review flow was completed successfully the `toShowAgain` conditions will be used. For example `.setMinimumLaunchTimesToShowAgain(launchTimesToShowAgain: Int)` instead of `.setMinimumLaunchTimes(launchTimes: Int)`.
109+
86110
#### When to show up
87111

88112
- Change the number of days the app has to be installed
@@ -129,6 +153,8 @@ Between the constructor and the show or create method you can adjust the dialog
129153

130154
#### Design
131155

156+
The following settings will only take effect if the library dialog is used (and not the Google in-app review).
157+
132158
##### General
133159

134160
- Change the icon of the dialog
@@ -411,6 +437,7 @@ If you want to show the dialog on app start, but with your custom conditions, yo
411437

412438
## Note
413439

440+
* If the in-app review from Google will be used: After the first in-app review flow was completed successfully the `toShowAgain` conditions will be used. For example `.setMinimumLaunchTimesToShowAgain(launchTimesToShowAgain: Int)` instead of `.setMinimumLaunchTimes(launchTimes: Int)`
414441
* Use a MaterialComponent theme for better design
415442
* Don't forget to set up the mail settings if you want to use the mail feedback dialog (otherwise nothing will happen)
416443
* Use `setRatingThreshold(RatingThreshold.NONE)` if you don't want to show the feedback form to the user

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.3.72'
4+
ext.kotlin_version = '1.4.0'
55
repositories {
66
google()
77
jcenter()

exampleapp/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ android {
2626
dependencies {
2727
implementation fileTree(dir: 'libs', include: ['*.jar'])
2828
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
29-
implementation 'androidx.appcompat:appcompat:1.1.0'
30-
implementation 'com.google.android.material:material:1.1.0'
31-
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
29+
implementation 'androidx.appcompat:appcompat:1.2.0'
30+
implementation 'com.google.android.material:material:1.2.0'
31+
implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
3232
implementation project(':library')
3333

3434
testImplementation 'junit:junit:4.13'

exampleapp/src/main/java/com/suddenh4x/ratingdialog/exampleapp/MainActivity.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ class MainActivity : AppCompatActivity() {
2323
Toast.makeText(this, R.string.toast_reset, Toast.LENGTH_SHORT).show()
2424
}
2525

26+
fun onGoogleInAppReviewExampleButtonClicked(@Suppress("UNUSED_PARAMETER") view: View) {
27+
AppRating.Builder(this)
28+
.useGoogleInAppReview()
29+
.setGoogleInAppReviewCompleteListener { successful ->
30+
Toast.makeText(
31+
this@MainActivity,
32+
"Google in-app review completed (successful: $successful)",
33+
Toast.LENGTH_LONG
34+
).show()
35+
}
36+
.setDebug(true)
37+
.showIfMeetsConditions()
38+
}
39+
2640
fun onDefaultExampleButtonClicked(@Suppress("UNUSED_PARAMETER") view: View) {
2741
AppRating.Builder(this)
2842
.setDebug(true)

exampleapp/src/main/res/layout/activity_main.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@
2323
android:onClick="onResetButtonClicked"
2424
android:text="@string/button_example_reset" />
2525

26+
<TextView
27+
style="@style/ExampleText"
28+
android:layout_width="match_parent"
29+
android:layout_height="wrap_content"
30+
android:text="@string/text_example_google_in_app_review" />
31+
32+
<Button
33+
android:layout_width="match_parent"
34+
android:layout_height="wrap_content"
35+
android:onClick="onGoogleInAppReviewExampleButtonClicked"
36+
android:text="@string/button_example_google_in_app_review" />
37+
2638
<TextView
2739
style="@style/ExampleText"
2840
android:layout_width="match_parent"

exampleapp/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
<!-- Example Buttons and Descriptions -->
55
<string name="text_example_note_app_reset">Note: Use the reset button below or restart the app to clear all settings.</string>
66
<string name="button_example_reset">Reset</string>
7+
<string name="text_example_google_in_app_review">This example uses the Google in-app review instead of the library
8+
dialog. Debug is enabled. (note: this example doesn\'t work at the moment because the example app hasn\'t been uploaded
9+
to the Google Play Store)</string>
10+
<string name="button_example_google_in_app_review">Google In-App Review</string>
711
<string name="text_example_default">This example has no customizations. Debug is enabled.</string>
812
<string name="button_example_default">Default</string>
913
<string name="text_example_custom_icon">In this example the default icon (app icon) has been replaced with a cusom icon.

library/build.gradle

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ apply plugin: 'kotlin-android-extensions'
44
apply plugin: "de.mannodermaus.android-junit5"
55
apply plugin: 'com.novoda.bintray-release'
66

7-
def version = "2.1.1"
7+
def version = "2.2.0"
88

99
android {
1010
compileSdkVersion 29
@@ -30,12 +30,16 @@ android {
3030
dependencies {
3131
implementation fileTree(dir: 'libs', include: ['*.jar'])
3232
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
33-
implementation 'androidx.appcompat:appcompat:1.1.0'
34-
implementation 'com.google.android.material:material:1.1.0'
35-
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
36-
implementation 'androidx.core:core-ktx:1.3.0'
33+
implementation 'androidx.appcompat:appcompat:1.2.0'
34+
implementation 'com.google.android.material:material:1.2.0'
35+
implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
36+
implementation 'androidx.core:core-ktx:1.3.1'
3737
implementation 'androidx.annotation:annotation:1.1.0'
3838

39+
// needed for in-app review
40+
implementation 'com.google.android.play:core:1.8.0'
41+
implementation 'com.google.android.play:core-ktx:1.8.1'
42+
3943
testImplementation "org.junit.jupiter:junit-jupiter-api:5.5.0"
4044
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.5.0"
4145
testImplementation "io.mockk:mockk:1.9.3"

library/lint.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<lint>
2+
<!-- Temporary until https://github.com/Kotlin/kotlinx.coroutines/issues/2004 is resolved. -->
3+
<issue id="InvalidPackage">
4+
<ignore path="**/kotlinx-coroutines-core-*.jar"/>
5+
</issue>
6+
</lint>

library/src/main/java/com/suddenh4x/ratingdialog/AppRating.kt

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import android.graphics.drawable.Drawable
55
import androidx.annotation.StringRes
66
import androidx.appcompat.app.AppCompatActivity
77
import androidx.fragment.app.DialogFragment
8+
import com.google.android.play.core.review.ReviewManager
9+
import com.google.android.play.core.review.ReviewManagerFactory
810
import com.suddenh4x.ratingdialog.buttons.ConfirmButtonClickListener
911
import com.suddenh4x.ratingdialog.buttons.CustomFeedbackButtonClickListener
1012
import com.suddenh4x.ratingdialog.buttons.RateButton
@@ -41,6 +43,7 @@ object AppRating {
4143

4244
data class Builder(var activity: AppCompatActivity) {
4345
internal var isDebug = false
46+
internal var reviewManger: ReviewManager? = null
4447
private var dialogOptions = DialogOptions()
4548

4649
internal constructor(activity: AppCompatActivity, dialogOptions: DialogOptions) :
@@ -163,7 +166,9 @@ object AppRating {
163166
mailFeedbackButtonClickListener
164167
}
165168

166-
fun setAdditionalMailFeedbackButtonClickListener(additionalMailFeedbackButtonClickListener: RateDialogClickListener) =
169+
fun setAdditionalMailFeedbackButtonClickListener(
170+
additionalMailFeedbackButtonClickListener: RateDialogClickListener
171+
) =
167172
apply {
168173
dialogOptions.additionalMailFeedbackButtonClickListener =
169174
additionalMailFeedbackButtonClickListener
@@ -221,17 +226,26 @@ object AppRating {
221226

222227
fun setCustomCondition(customCondition: () -> Boolean) = apply {
223228
dialogOptions.customCondition = customCondition
224-
RatingLogger.debug("Custom condition set. This condition will be removed next time you call the Builder constructor.")
229+
RatingLogger.debug(
230+
"Custom condition set. This condition will be removed next" +
231+
" time you call the Builder constructor."
232+
)
225233
}
226234

227235
fun setCustomConditionToShowAgain(customConditionToShowAgain: () -> Boolean) = apply {
228236
dialogOptions.customConditionToShowAgain = customConditionToShowAgain
229-
RatingLogger.debug("Custom condition to show again set. This condition will be removed next time you call the Builder constructor.")
237+
RatingLogger.debug(
238+
"Custom condition to show again set. This condition will" +
239+
"be removed next time you call the Builder constructor."
240+
)
230241
}
231242

232243
fun dontCountThisAsAppLaunch() = apply {
233244
dialogOptions.countAppLaunch = false
234-
RatingLogger.debug("countAppLaunch is now set to false. This setting will be reset next time you call the Builder constructor.")
245+
RatingLogger.debug(
246+
"countAppLaunch is now set to false. This setting will be " +
247+
"reset next time you call the Builder constructor."
248+
)
235249
}
236250

237251
fun setLoggingEnabled(isLoggingEnabled: Boolean) = apply {
@@ -243,10 +257,49 @@ object AppRating {
243257
RatingLogger.warn("Set debug to $isDebug. Don't use this for production.")
244258
}
245259

246-
fun create(): DialogFragment = RateDialogFragment.newInstance(dialogOptions)
260+
// Google in-app review
261+
/**
262+
* If this method is called, the in-app review from Google will be used instead of
263+
* the library dialog.
264+
*/
265+
fun useGoogleInAppReview() = apply {
266+
reviewManger = ReviewManagerFactory.create(activity)
267+
dialogOptions.useGoogleInAppReview = true
268+
RatingLogger.info("Use in-app review from Google instead of the library dialog.")
269+
}
247270

248-
fun showNow() =
249-
RateDialogFragment.newInstance(dialogOptions).show(activity.supportFragmentManager, TAG)
271+
/**
272+
* The completion listener will be invoked with true if the in-app review flow started
273+
* correctly (otherwise false).
274+
* Note: true doesn't mean that the in-app review from Google was displayed.
275+
*/
276+
fun setGoogleInAppReviewCompleteListener(googleInAppReviewCompleteListener: (Boolean) -> Unit) =
277+
apply {
278+
dialogOptions.googleInAppReviewCompleteListener = googleInAppReviewCompleteListener
279+
}
280+
281+
/**
282+
* This method will return null if the in-app review from Google is used.
283+
*/
284+
fun create(): DialogFragment? {
285+
return if (dialogOptions.useGoogleInAppReview) {
286+
RatingLogger.warn("In-app review from Google will be used. Can't create the library dialog.")
287+
null
288+
} else {
289+
RateDialogFragment.newInstance(dialogOptions)
290+
}
291+
}
292+
293+
fun showNow() {
294+
if (dialogOptions.useGoogleInAppReview) {
295+
RatingLogger.info("In-app review from Google will be displayed now.")
296+
showGoogleInAppReview()
297+
} else {
298+
RatingLogger.debug("In-app review from Google hasn't been activated. Showing library dialog now.")
299+
RateDialogFragment.newInstance(dialogOptions)
300+
.show(activity.supportFragmentManager, TAG)
301+
}
302+
}
250303

251304
fun showIfMeetsConditions() {
252305
if (dialogOptions.countAppLaunch) {
@@ -264,6 +317,26 @@ object AppRating {
264317
}
265318
}
266319

320+
internal fun showGoogleInAppReview() {
321+
val requestTask = reviewManger?.requestReviewFlow()
322+
requestTask?.addOnCompleteListener { request ->
323+
if (request.isSuccessful) {
324+
val reviewInfo = request.result
325+
val flow = reviewManger?.launchReviewFlow(activity, reviewInfo)
326+
flow?.addOnCompleteListener { task ->
327+
RatingLogger.info("Google in-app review request completed.")
328+
PreferenceUtil.onGoogleInAppReviewFlowCompleted(activity)
329+
dialogOptions.googleInAppReviewCompleteListener?.invoke(task.isSuccessful)
330+
?: RatingLogger.warn("There's no completeListener for Google's in-app review.")
331+
}
332+
} else {
333+
RatingLogger.info("Google in-app review request wasn't successful.")
334+
dialogOptions.googleInAppReviewCompleteListener?.invoke(false)
335+
?: RatingLogger.warn("There's no completeListener for Google's in-app review.")
336+
}
337+
}
338+
}
339+
267340
companion object {
268341
private val TAG = AppRating::class.java.simpleName
269342
}

library/src/main/java/com/suddenh4x/ratingdialog/dialog/DialogManager.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,10 @@ internal object DialogManager {
294294
val numberOfLaterButtonClicks = PreferenceUtil.getNumberOfLaterButtonClicks(context)
295295
RatingLogger.debug("Rate later button was clicked $numberOfLaterButtonClicks times.")
296296
if (countOfLaterButtonClicksToShowNeverButton > numberOfLaterButtonClicks) {
297-
RatingLogger.info("Less than $countOfLaterButtonClicksToShowNeverButton later button clicks. Rate never button won't be displayed.")
297+
RatingLogger.info(
298+
"Less than $countOfLaterButtonClicksToShowNeverButton later " +
299+
"button clicks. Rate never button won't be displayed."
300+
)
298301
return
299302
}
300303

0 commit comments

Comments
 (0)