Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ class DocumentFragment : Fragment(), DocumentLoader.Listener {
freshOpenPending = false

ReviewInvitation.recordDocumentOpen(activity)
(activity as? MainActivity)?.onDocumentShown()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,33 @@ class MainActivity : AppCompatActivity() {
// an externally opened document leaves the app rather than the document, and
// carries unsaved edits out just the same
confirmLeavingEdits {
// fall through to the default behavior (close the activity)
isEnabled = false
onBackPressedDispatcher.onBackPressed()
isEnabled = true
// the only moment a document opened from another app is put down again
val asked =
documentFragment != null &&
preparedReview?.showIfReady(
onAsked = { ReviewInvitation.recordAsk(this@MainActivity) },
onDone = { leaveApp() },
) == true
preparedReview = null

if (!asked) {
leaveApp()
}
}
}
}

/** Falls through to the default back behavior, which closes the activity. */
private fun leaveApp() {
if (isFinishing || isDestroyed) {
return
}

backCallback.isEnabled = false
onBackPressedDispatcher.onBackPressed()
backCallback.isEnabled = true
}

// kept because onPause has to stop it
private var ttsActionMode: TtsActionModeCallback? = null

Expand Down Expand Up @@ -145,6 +164,9 @@ class MainActivity : AppCompatActivity() {
// lands would pass isEarned again. never reset: one hand-off per activity is plenty
private var reviewRequested = false

// fetched while an externally opened document is read: back must not wait on the network
private var preparedReview: InAppReview.Prepared? = null

/**
* Loads and saves the open document. Scoped to the activity, so it survives a configuration
* change and [DocumentFragment] finds it already there rather than waiting for a binding.
Expand Down Expand Up @@ -870,6 +892,16 @@ class MainActivity : AppCompatActivity() {
.show()
}

/** Called once a fresh open has rendered. */
fun onDocumentShown() {
if (!documentOpenedExternally || reviewRequested || !ReviewInvitation.isEarned(this)) {
return
}

reviewRequested = true
preparedReview = InAppReview.prepare(this, analyticsManager)
}

/** Deliberately not from [closeFailedDocument], the last moment on earth to ask for stars. */
private fun askForReviewIfEarned() {
if (reviewRequested || !ReviewInvitation.isEarned(this)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,11 @@ import android.app.Activity
object InAppReview {

fun request(activity: Activity, analyticsManager: AnalyticsManager, onAsked: () -> Unit) {}

fun prepare(activity: Activity, analyticsManager: AnalyticsManager): Prepared = Prepared()

class Prepared {

fun showIfReady(onAsked: () -> Unit, onDone: () -> Unit): Boolean = false
}
}
44 changes: 44 additions & 0 deletions app/src/review/java/app/opendocument/droid/nonfree/InAppReview.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app.opendocument.droid.nonfree

import android.app.Activity
import com.google.android.play.core.review.ReviewInfo
import com.google.android.play.core.review.ReviewManagerFactory

/**
Expand Down Expand Up @@ -34,4 +35,47 @@ object InAppReview {
}
}
}

/**
* Fetches the sheet ahead of the moment to show it, so that moment does not wait on the
* network.
*/
fun prepare(activity: Activity, analyticsManager: AnalyticsManager): Prepared {
val prepared = Prepared(activity, analyticsManager)
analyticsManager.report("in_app_review_eligible")

prepared.manager.requestReviewFlow().addOnCompleteListener { task ->
if (task.isSuccessful) {
prepared.reviewInfo = task.result
} else {
analyticsManager.report("in_app_review_error")
}
}

return prepared
}

class Prepared
internal constructor(
private val activity: Activity,
private val analyticsManager: AnalyticsManager,
) {
internal val manager = ReviewManagerFactory.create(activity)
internal var reviewInfo: ReviewInfo? = null

/** False when the sheet has not arrived yet - then [onDone] does not run. */
fun showIfReady(onAsked: () -> Unit, onDone: () -> Unit): Boolean {
val reviewInfo = reviewInfo ?: return false

analyticsManager.report("in_app_review_start")
onAsked()

manager.launchReviewFlow(activity, reviewInfo).addOnCompleteListener {
analyticsManager.report("in_app_review_done")
onDone()
}

return true
}
}
}
Loading