mirror of
https://github.com/ankidroid/Anki-Android.git
synced 2024-09-20 12:02:16 +02:00
feat: implement App Introduction System
* Displays the App Introduction System * Handles only displaying it once * Handles syncing if the app intro loads an existing AnkiWeb account * (special case) Handles an upgrade from 2.15 -> 2.16 where the preference for the app intro was unset.
This commit is contained in:
parent
b3a138035b
commit
529bc11db7
@ -149,6 +149,9 @@ import kotlin.math.roundToLong
|
||||
* * A custom image as a background can be added: [applyDeckPickerBackground]
|
||||
*/
|
||||
@KotlinCleanup("lots to do")
|
||||
@NeedsTest("On a new startup, the App Intro is displayed")
|
||||
@NeedsTest("If the collection has been created, the app intro is not displayed")
|
||||
@NeedsTest("If the user selects 'Sync Profile' in the app intro, a sync starts immediately")
|
||||
open class DeckPicker :
|
||||
NavigationDrawerActivity(),
|
||||
StudyOptionsListener,
|
||||
@ -382,6 +385,19 @@ open class DeckPicker :
|
||||
|
||||
// Then set theme and content view
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// handle the first load: display the app introduction
|
||||
if (!hasShownAppIntro()) {
|
||||
val appIntro = Intent(this, IntroductionActivity::class.java)
|
||||
appIntro.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivityWithoutAnimation(appIntro)
|
||||
finish() // calls onDestroy() immediately
|
||||
return
|
||||
}
|
||||
if (intent.hasExtra(INTENT_SYNC_FROM_LOGIN)) {
|
||||
mSyncOnResume = true
|
||||
}
|
||||
|
||||
setContentView(R.layout.homescreen)
|
||||
handleStartup()
|
||||
val mainView = findViewById<View>(android.R.id.content)
|
||||
@ -463,6 +479,23 @@ open class DeckPicker :
|
||||
Onboarding.DeckPicker(this, mRecyclerViewLayoutManager).onCreate()
|
||||
}
|
||||
|
||||
private fun hasShownAppIntro(): Boolean {
|
||||
val prefs = AnkiDroidApp.getSharedPrefs(this)
|
||||
|
||||
// if moving from 2.15 to 2.16 then we do not want to show the intro
|
||||
// remove this after ~2.17 and default to 'false' if the pref is not set
|
||||
if (!prefs.contains(IntroductionActivity.INTRODUCTION_SLIDES_SHOWN)) {
|
||||
return if (!InitialActivity.wasFreshInstall(prefs)) {
|
||||
prefs.edit { putBoolean(IntroductionActivity.INTRODUCTION_SLIDES_SHOWN, true) }
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
return prefs.getBoolean(IntroductionActivity.INTRODUCTION_SLIDES_SHOWN, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* The first call in showing dialogs for startup - error or success.
|
||||
* Attempts startup if storage permission has been acquired, else, it requests the permission
|
||||
@ -861,7 +894,8 @@ open class DeckPicker :
|
||||
|
||||
fun refreshState() {
|
||||
mActivityPaused = false
|
||||
if (mSyncOnResume) {
|
||||
// Due to the App Introduction, this may be called before permission has been granted.
|
||||
if (mSyncOnResume && hasStorageAccessPermission(this)) {
|
||||
Timber.i("Performing Sync on Resume")
|
||||
sync()
|
||||
mSyncOnResume = false
|
||||
@ -2684,6 +2718,14 @@ open class DeckPicker :
|
||||
const val RESULT_DB_ERROR = 203
|
||||
const val UPGRADE_VERSION_KEY = "lastUpgradeVersion"
|
||||
|
||||
/**
|
||||
* If passed into the intent, the user should have been logged in and DeckPicker
|
||||
* should sync immediately.
|
||||
*
|
||||
* This is for the 'download existing collection from AnkiWeb' use case
|
||||
*/
|
||||
const val INTENT_SYNC_FROM_LOGIN = "syncFromLogin"
|
||||
|
||||
/**
|
||||
* Available options performed by other activities (request codes for onActivityResult())
|
||||
*/
|
||||
|
@ -96,7 +96,7 @@ class IntroductionActivity : AppIntro() {
|
||||
val deckPicker = Intent(this, DeckPicker::class.java)
|
||||
deckPicker.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
if (result == RESULT_SYNC_PROFILE) {
|
||||
deckPicker.putExtra("syncFromLogin", true)
|
||||
deckPicker.putExtra(DeckPicker.INTENT_SYNC_FROM_LOGIN, true)
|
||||
}
|
||||
|
||||
startActivity(deckPicker)
|
||||
|
@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.PackageManager
|
||||
import android.view.Menu
|
||||
import androidx.core.content.edit
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import com.ichi2.anki.dialogs.DatabaseErrorDialog
|
||||
import com.ichi2.anki.dialogs.DeckPickerConfirmDeleteDeckDialog
|
||||
@ -54,6 +55,7 @@ class DeckPickerTest : RobolectricTest() {
|
||||
@Before
|
||||
fun before() {
|
||||
RuntimeEnvironment.setQualifiers(mQualifiers)
|
||||
getPreferences().edit { putBoolean(IntroductionActivity.INTRODUCTION_SLIDES_SHOWN, true) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.ichi2.anki.dialogs
|
||||
|
||||
import android.widget.EditText
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import com.afollestad.materialdialogs.WhichButton
|
||||
@ -24,6 +25,7 @@ import com.afollestad.materialdialogs.actions.getActionButton
|
||||
import com.afollestad.materialdialogs.input.getInputField
|
||||
import com.ichi2.anki.CollectionManager.withCol
|
||||
import com.ichi2.anki.DeckPicker
|
||||
import com.ichi2.anki.IntroductionActivity
|
||||
import com.ichi2.anki.R
|
||||
import com.ichi2.anki.RobolectricTest
|
||||
import com.ichi2.libanki.DeckManager
|
||||
@ -51,6 +53,7 @@ class CreateDeckDialogTest : RobolectricTest() {
|
||||
private var mActivityScenario: ActivityScenario<DeckPicker>? = null
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
getPreferences().edit { putBoolean(IntroductionActivity.INTRODUCTION_SLIDES_SHOWN, true) }
|
||||
ensureCollectionLoadIsSynchronous()
|
||||
mActivityScenario = ActivityScenario.launch(DeckPicker::class.java)
|
||||
val activityScenario: ActivityScenario<DeckPicker>? = mActivityScenario
|
||||
|
Loading…
Reference in New Issue
Block a user