-
Notifications
You must be signed in to change notification settings - Fork 26
Feature/in app rating integration #676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
82c0a26
ff3a64f
24f7706
16cd7b5
32c81f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,5 +1,6 @@ | ||||||
| package net.opendasharchive.openarchive.features.main | ||||||
|
|
||||||
| import android.app.Activity | ||||||
Check warningCode scanning / detekt Detects unused imports Warning
Unused import
|
||||||
| import android.content.Context | ||||||
| import android.content.Intent | ||||||
| import android.graphics.Point | ||||||
|
|
@@ -16,6 +17,7 @@ | |||||
| import android.view.inputmethod.InputMethodManager | ||||||
| import android.widget.LinearLayout | ||||||
| import android.widget.PopupWindow | ||||||
| import android.widget.Toast | ||||||
|
||||||
| import android.widget.Toast |
Check warning
Code scanning / detekt
Detects unused imports Warning
Check warning
Code scanning / detekt
Detects unused imports Warning
Check warning
Code scanning / detekt
Detects unused imports Warning
Check warning
Code scanning / detekt
Detects unused imports Warning
Copilot
AI
Jun 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the unused import 'FakeReviewManager' to reduce clutter in the production code.
| import com.google.android.play.core.review.testing.FakeReviewManager |
Check warning
Code scanning / detekt
Detects unused imports Warning
Copilot
AI
Jun 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the unused import 'androidx.core.content.edit' as it is not required.
| import androidx.core.content.edit |
Check warning
Code scanning / detekt
Detects unused imports Warning
Copilot
AI
Jun 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Consider extracting the delay duration (2 seconds) into a named constant for better maintainability and clarity.
| delay(2_000) | |
| delay(REVIEW_PROMPT_DELAY_MS) |
Check warning
Code scanning / detekt
Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers. Warning
Check warning
Code scanning / detekt
Reports consecutive blank lines Warning
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| package net.opendasharchive.openarchive.util | ||
|
|
||
| import android.app.Activity | ||
| import android.content.Context | ||
| import com.google.android.play.core.review.ReviewException | ||
| 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 net.opendasharchive.openarchive.core.logger.AppLogger | ||
|
|
||
| object InAppReviewHelper { | ||
| // Keys for our Prefs helper: | ||
| private const val KEY_LAUNCH_COUNT = "launch_count" | ||
| private const val KEY_LAST_REVIEW_TIME = "last_review_time" | ||
|
|
||
| // After this many launches, we become eligible: | ||
| private const val MIN_LAUNCHES = 5 | ||
|
|
||
| // 30 days in ms | ||
| private const val THIRTY_DAYS_MS = 30L * 24 * 60 * 60 * 1000 | ||
|
|
||
| // Once requestReviewFlow() succeeds, we cache this: | ||
| private var reviewInfo: ReviewInfo? = null | ||
|
|
||
| /** | ||
| * Call once (e.g. in Application.onCreate or first Activity) so that Prefs.load(...) runs. | ||
| */ | ||
| fun init(context: Context) { | ||
| Prefs.load(context) | ||
| } | ||
|
|
||
| /** | ||
| * Call early (e.g. in onCreate of MainActivity) to asynchronously fetch ReviewInfo. | ||
| */ | ||
| fun requestReviewInfo(context: Context) { | ||
| val manager: ReviewManager = ReviewManagerFactory.create(context) | ||
| manager.requestReviewFlow() | ||
| .addOnCompleteListener { task -> | ||
| if (task.isSuccessful) { | ||
| reviewInfo = task.result | ||
| AppLogger.d("InAppReview", "ReviewInfo obtained successfully.") | ||
Check warningCode scanning / detekt Multiple occurrences of the same string literal within a single file detected. Prefer extracting the string literal into a property or constant. Warning
Multiple occurrences of the same string literal within a single file detected. Prefer extracting the string literal into a property or constant.
|
||
| } else { | ||
| (task.exception as? ReviewException)?.let { ex -> | ||
| AppLogger.e("InAppReview", "Error requesting review flow: ${ex.errorCode}", ex) | ||
| } | ||
| reviewInfo = null | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Call this immediately on app launch (in onCreate). It increments the stored launch count | ||
| * and returns TRUE if we are now eligible to show a review (≥ MIN_LAUNCHES AND ≥ 30 days since last). | ||
| * | ||
| * It does NOT actually show anything. It only says “yes/no.” | ||
| */ | ||
| fun onAppLaunched(): Boolean { | ||
| val previousCount = Prefs.getInt(KEY_LAUNCH_COUNT, 0) | ||
| val newCount = previousCount + 1 | ||
| Prefs.putInt(KEY_LAUNCH_COUNT, newCount) | ||
|
|
||
| val lastReviewTime = Prefs.getLong(KEY_LAST_REVIEW_TIME, 0L) | ||
| val now = System.currentTimeMillis() | ||
|
|
||
| return if (newCount >= MIN_LAUNCHES && (now - lastReviewTime) >= THIRTY_DAYS_MS) { | ||
| true | ||
| } else { | ||
| false | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Once you decide it’s time to actually show the prompt (e.g. in onResume, after UI ready), | ||
| * call this. If reviewInfo is non-null it will launch; otherwise it just logs “no Info.” | ||
| */ | ||
| fun showReviewIfPossible(activity: Activity, reviewManager: ReviewManager) { | ||
| reviewInfo?.let { info -> | ||
| reviewManager.launchReviewFlow(activity, info) | ||
| .addOnCompleteListener { | ||
| AppLogger.d("InAppReview", "Review flow finished.") | ||
| reviewInfo = null | ||
| } | ||
| } ?: run { | ||
| AppLogger.d("InAppReview", "ReviewInfo was null; cannot launch review flow.") | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * After you do showReviewIfPossible(...), call this to reset counters. | ||
| * That ensures we won’t prompt again for another 30 days. | ||
| */ | ||
| fun markReviewDone() { | ||
| val now = System.currentTimeMillis() | ||
| Prefs.putInt(KEY_LAUNCH_COUNT, 0) | ||
| Prefs.putLong(KEY_LAST_REVIEW_TIME, now) | ||
| } | ||
| } | ||
Check warning
Code scanning / detekt
Detects imports in non default order Warning