From a36bbc7c6ce16ed99370e16997e6592e85a90075 Mon Sep 17 00:00:00 2001 From: Shridhar Date: Thu, 10 Jun 2021 00:20:38 +0530 Subject: [PATCH] Update with required changes and better implementation --- .../ichi2/anki/AbstractFlashcardViewer.java | 22 ++-- .../main/java/com/ichi2/anki/DeckPicker.java | 44 ++++---- .../com/ichi2/anki/IntroductionActivity.kt | 105 ++++++++++-------- .../main/java/com/ichi2/anki/NoteEditor.java | 24 ++-- .../com/ichi2/anki/OnboardingConstants.kt | 14 --- .../java/com/ichi2/anki/OnboardingUtils.kt | 39 +++++++ .../main/java/com/ichi2/anki/Reviewer.java | 25 ++--- .../utils/DimmedCirclePromptBackground.java | 4 +- .../DimmedRectanglePromptBackground.java | 4 +- .../src/main/res/values/19-onboarding.xml | 31 ++++++ .../com/ichi2/testutils/ActivityList.java | 4 +- 11 files changed, 178 insertions(+), 138 deletions(-) delete mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/OnboardingConstants.kt create mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/OnboardingUtils.kt create mode 100644 AnkiDroid/src/main/res/values/19-onboarding.xml diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java b/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java index 95b0be2aa973..d63c8d163671 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java @@ -163,8 +163,6 @@ import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; import uk.co.samuelwall.materialtaptargetprompt.extras.focals.RectanglePromptFocal; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_CARD_DIFFICULTY_SELECTOR; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_SHOW_ANSWER; import static com.ichi2.anki.cardviewer.CardAppearance.calculateDynamicFontSize; import static com.ichi2.anki.cardviewer.ViewerCommand.*; import static com.ichi2.anki.reviewer.CardMarker.*; @@ -397,8 +395,6 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity i private final OnRenderProcessGoneDelegate mOnRenderProcessGoneDelegate = new OnRenderProcessGoneDelegate(this); - private SharedPreferences mSharedPreferences; - // ---------------------------------------------------------------------------- // LISTENERS // ---------------------------------------------------------------------------- @@ -958,18 +954,16 @@ protected void onCreate(Bundle savedInstanceState) { mShortAnimDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); - mSharedPreferences = getSharedPreferences("PERSISTENT_STATE_FILE", 0); - - if (mSharedPreferences.getBoolean(ONBOARDING_SHOW_ANSWER, true)) { + if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(4, this)) { new MaterialTapTargetPrompt.Builder(this) .setTarget(R.id.flip_card) - .setPrimaryText("See the answer") - .setSecondaryText("When you are ready to view the answer, click here") + .setPrimaryText(this.getString(R.string.see_answer)) + .setSecondaryText(this.getString(R.string.see_answer_desc)) .setPromptBackground(new DimmedRectanglePromptBackground()) .setPromptFocal(new RectanglePromptFocal()) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_SHOW_ANSWER, false); + OnboardingUtils.INSTANCE.setAsVisited(4, this); } } @@ -1843,16 +1837,16 @@ protected void displayAnswerBottomBar() { mFlipCardLayout.animate().alpha(0).setDuration(mShortAnimDuration).withEndAction(after); } - if (mSharedPreferences.getBoolean(ONBOARDING_CARD_DIFFICULTY_SELECTOR, true)) { + if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(7, this)) { new MaterialTapTargetPrompt.Builder(this) .setTarget(mEaseButtonsLayout) - .setPrimaryText("Select the difficulty") - .setSecondaryText("This will decide the time when this card will be displayed again") + .setPrimaryText(this.getString(R.string.select_difficulty)) + .setSecondaryText(this.getString(R.string.select_difficulty_desc)) .setPromptBackground(new DimmedRectanglePromptBackground()) .setPromptFocal(new RectanglePromptFocal()) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_CARD_DIFFICULTY_SELECTOR, false).apply(); + OnboardingUtils.INSTANCE.setAsVisited(7, this); } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java index b6d9ade5bced..4f4acaa345a1 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java @@ -154,10 +154,6 @@ import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; import uk.co.samuelwall.materialtaptargetprompt.extras.focals.RectanglePromptFocal; -import static com.ichi2.anki.OnboardingConstants.FIRST_LAUNCH; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_COUNTS_LAYOUT; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_DECK_PICKER_FAB; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_SELECT_DECK; import static com.ichi2.async.Connection.ConflictResolution.FULL_DOWNLOAD; import static com.ichi2.anim.ActivityTransitionAnimation.Direction.*; @@ -263,8 +259,6 @@ public class DeckPicker extends NavigationDrawerActivity implements private CustomStudyDialogFactory mCustomStudyDialogFactory; - private SharedPreferences mSharedPreferences; - // ---------------------------------------------------------------------------- // LISTENERS // ---------------------------------------------------------------------------- @@ -465,10 +459,8 @@ protected void onCreate(Bundle savedInstanceState) throws SQLException { return; } - SharedPreferences sharedPreferences = getSharedPreferences("PERSISTENT_STATE_FILE", 0); - - if (sharedPreferences.getBoolean(FIRST_LAUNCH, true)) { - sharedPreferences.edit().putBoolean(FIRST_LAUNCH, false).apply(); + if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(0, this)) { + OnboardingUtils.INSTANCE.setAsVisited(0, this); Intent introductionIntent = new Intent(this, IntroductionActivity.class); startActivityWithoutAnimation(introductionIntent); } @@ -556,19 +548,16 @@ protected void onCreate(Bundle savedInstanceState) throws SQLException { mShortAnimDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); - mSharedPreferences = getSharedPreferences("PERSISTENT_STATE_FILE", 0); - - if (mSharedPreferences.getBoolean(ONBOARDING_DECK_PICKER_FAB, true)) { + if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(1, this)) { showTutorialForFAB(); - mSharedPreferences.edit().putBoolean(ONBOARDING_DECK_PICKER_FAB, false).apply(); } } public void showTutorialForFAB() { new MaterialTapTargetPrompt.Builder(this) .setTarget(R.id.fab_main) - .setPrimaryText("Get started") - .setSecondaryText("Create a deck, download a pre-made deck or add a note") + .setPrimaryText(this.getString(R.string.fab_tutorial_title)) + .setSecondaryText(this.getString(R.string.fab_tutorial_desc)) .setPromptBackground(new DimmedCirclePromptBackground()) .setFocalColour(ContextCompat.getColor(this, R.color.material_light_blue_500)) .setPromptStateChangeListener((prompt, state) -> { @@ -577,6 +566,8 @@ public void showTutorialForFAB() { } }) .show(); + + OnboardingUtils.INSTANCE.setAsVisited(1, this); } /** @@ -994,42 +985,45 @@ protected void onResume() { private void startDeckAndCountsTutorial() { - if (mDeckListAdapter.getItemCount() > 0 && mSharedPreferences.getBoolean(ONBOARDING_SELECT_DECK, true)) { + if (mDeckListAdapter.getItemCount() > 0 && OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(2, this)) { showTutorialForDeck(); - } else if (mDeckListAdapter.getItemCount() > 0 && mSharedPreferences.getBoolean(ONBOARDING_COUNTS_LAYOUT, true)) { + } else if (mDeckListAdapter.getItemCount() > 0 && OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(3, this)) { showTutorialForCountsLayout(); } } private void showTutorialForDeck() { + if (mRecyclerViewLayoutManager.getChildAt(0) == null) return; + new MaterialTapTargetPrompt.Builder(this) .setTarget(mRecyclerViewLayoutManager.getChildAt(0).findViewById(R.id.deck_name_linear_layout)) - .setPrimaryText("Click on a deck to start studying") - .setSecondaryText("Long press on a deck to get more options related to it") + .setPrimaryText(this.getString(R.string.start_studying)) + .setSecondaryText(this.getString(R.string.start_studying_desc)) .setPromptBackground(new DimmedRectanglePromptBackground()) .setPromptFocal(new RectanglePromptFocal()) .setPromptStateChangeListener((prompt, state) -> { if (state == MaterialTapTargetPrompt.STATE_DISMISSED) { showTutorialForCountsLayout(); - mSharedPreferences.edit().putBoolean(ONBOARDING_COUNTS_LAYOUT, false).apply(); } }) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_SELECT_DECK, false).apply(); + OnboardingUtils.INSTANCE.setAsVisited(2, this); } private void showTutorialForCountsLayout() { + if (mRecyclerViewLayoutManager.getChildAt(0) == null) return; + new MaterialTapTargetPrompt.Builder(this) .setTarget(mRecyclerViewLayoutManager.getChildAt(0).findViewById(R.id.counts_layout)) - .setPrimaryText("Study options") - .setSecondaryText("Open study options to see card review details for a deck") + .setPrimaryText(this.getString(R.string.menu__study_options)) + .setSecondaryText(this.getString(R.string.study_options_desc)) .setPromptBackground(new DimmedRectanglePromptBackground()) .setPromptFocal(new RectanglePromptFocal()) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_COUNTS_LAYOUT, false).apply(); + OnboardingUtils.INSTANCE.setAsVisited(3, this); } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/IntroductionActivity.kt b/AnkiDroid/src/main/java/com/ichi2/anki/IntroductionActivity.kt index a9da1b128238..e71cb5d1e8d4 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/IntroductionActivity.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/IntroductionActivity.kt @@ -13,62 +13,52 @@ class IntroductionActivity : AppIntro() { setTransformer(AppIntroPageTransformerType.Zoom) - addSlide( - AppIntroFragment.newInstance( - title = "Welcome to AnkiDroid!", - description = "AnkiDroid is a spaced repetition flashcard app. Memorize anything with AnkiDroid!", - backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), - imageDrawable = R.drawable.ankidroid_logo - ) + val welcomeSlide = Triple( + R.string.collection_load_welcome_request_permissions_title, + R.string.introduction_desc, + R.drawable.ankidroid_logo ) - addSlide( - AppIntroFragment.newInstance( - title = "Create powerful decks with customised cards", - description = "Choose from multiple card types", - backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), - imageDrawable = R.drawable.decks - ) + + val decksSlide = Triple( + R.string.decks_intro, + R.string.decks_intro_desc, + R.drawable.decks ) - addSlide( - AppIntroFragment.newInstance( - title = "Create cards which support multiple content formats", - description = "Text - Images - Sounds - MathJax - LaTeX", - backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), - imageDrawable = R.drawable.create_cards, - ) + + val cardsSlide = Triple( + R.string.create_cards_intro, + R.string.create_cards_intro_desc, + R.drawable.create_cards ) - addSlide( - AppIntroFragment.newInstance( - title = "Choose from 6000+ pre-made decks", - description = "You can browse and import decks made by others.", - backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), - imageDrawable = R.drawable.premade_decks - ) + + val premadeDecksSlide = Triple( + R.string.pre_made_decks, + R.string.pre_made_decks_desc, + R.drawable.premade_decks ) - addSlide( - AppIntroFragment.newInstance( - title = "Study time", - description = "Review cards and select their difficulty according to which the time interval for their next appearance will be decided", - backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), - imageDrawable = R.drawable.review - ) + + val reviewerSlide = Triple( + R.string.study_time, + R.string.study_desc, + R.drawable.review ) - addSlide( - AppIntroFragment.newInstance( - title = "Detailed Statistics", - description = "Helps you track your study progress", - backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), - imageDrawable = R.drawable.statistics - ) + + val statisticsSlide = Triple( + R.string.detailed_statistics, + R.string.detailed_statistics_desc, + R.drawable.statistics ) - addSlide( - AppIntroFragment.newInstance( - title = "Night Mode", - description = "Put less strain on your eyes", - backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), - imageDrawable = R.drawable.night_mode - ) + + val nightModeSlide = Triple( + R.string.night_mode, + R.string.night_mode_desc, + R.drawable.night_mode ) + + val slidesList = listOf(welcomeSlide, decksSlide, cardsSlide, premadeDecksSlide, reviewerSlide, statisticsSlide, nightModeSlide) + slidesList.forEach { + insertSlide(it) + } } override fun onSkipPressed(currentFragment: Fragment?) { @@ -80,4 +70,21 @@ class IntroductionActivity : AppIntro() { super.onDonePressed(currentFragment) finish() } + + /** + * Insert a slide to be shown in the introduction + * resources.first -> Title of the slide + * resources.second -> Description of the slide + * resources.third -> Image of the slide + */ + private fun insertSlide(resources: Triple) { + addSlide( + AppIntroFragment.newInstance( + title = this.getString(resources.first), + description = this.getString(resources.second), + backgroundColor = ContextCompat.getColor(this, R.color.material_blue_500), + imageDrawable = resources.third + ) + ) + } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.java b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.java index c7bb653b956a..a426bb5bb2fd 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.java @@ -143,8 +143,6 @@ import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; import uk.co.samuelwall.materialtaptargetprompt.extras.focals.RectanglePromptFocal; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_CARD_FORMATTING_TOOLS; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_FRONT_AND_BACK; import static com.ichi2.compat.Compat.ACTION_PROCESS_TEXT; import static com.ichi2.compat.Compat.EXTRA_PROCESS_TEXT; @@ -263,8 +261,6 @@ public class NoteEditor extends AnkiActivity implements // Use the same HTML if the same image is pasted multiple times. private HashMap mPastedImageCache = new HashMap<>(); - private SharedPreferences mSharedPreferences; - private SaveNoteHandler saveNoteHandler() { return new SaveNoteHandler(this); } @@ -442,11 +438,9 @@ protected void onCreate(Bundle savedInstanceState) { startLoadingCollection(); - mSharedPreferences = getSharedPreferences("PERSISTENT_STATE_FILE", 0); - - if (mSharedPreferences.getBoolean(ONBOARDING_FRONT_AND_BACK, true)) { + if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(8, this)) { showTutorialForFrontAndBack(); - } else if (mSharedPreferences.getBoolean(ONBOARDING_CARD_FORMATTING_TOOLS, true)) { + } else if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(9, this)) { showTutorialForFormattingTools(); } } @@ -454,32 +448,32 @@ protected void onCreate(Bundle savedInstanceState) { public void showTutorialForFrontAndBack() { new MaterialTapTargetPrompt.Builder(this) .setTarget(R.id.CardEditorEditFieldsLayout) - .setPrimaryText("Enter card contents here") - .setSecondaryText("Enter the front part of card in 'Front' field and the answer in 'Back' field") + .setPrimaryText(this.getString(R.string.card_contents)) + .setSecondaryText(this.getString(R.string.card_contents_desc)) .setPromptBackground(new DimmedRectanglePromptBackground()) .setPromptFocal(new RectanglePromptFocal()) .setPromptStateChangeListener((prompt, state) -> { if (state == MaterialTapTargetPrompt.STATE_DISMISSED) { - if (mSharedPreferences.getBoolean(ONBOARDING_CARD_FORMATTING_TOOLS, true)) { + if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(9, this)) { showTutorialForFormattingTools(); } } }) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_FRONT_AND_BACK, false).apply(); + OnboardingUtils.INSTANCE.setAsVisited(8, this); } public void showTutorialForFormattingTools() { new MaterialTapTargetPrompt.Builder(this) .setTarget(R.id.editor_toolbar) - .setPrimaryText("Format content") - .setSecondaryText("Format your card's content using various formatting options") + .setPrimaryText(this.getString(R.string.format_content)) + .setSecondaryText(this.getString(R.string.format_content_desc)) .setPromptBackground(new DimmedRectanglePromptBackground()) .setPromptFocal(new RectanglePromptFocal()) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_CARD_FORMATTING_TOOLS, false).apply(); + OnboardingUtils.INSTANCE.setAsVisited(9, this); } @Override diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/OnboardingConstants.kt b/AnkiDroid/src/main/java/com/ichi2/anki/OnboardingConstants.kt deleted file mode 100644 index 4631d45ff5a0..000000000000 --- a/AnkiDroid/src/main/java/com/ichi2/anki/OnboardingConstants.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.ichi2.anki - -object OnboardingConstants { - const val FIRST_LAUNCH = "FirstLaunch" - const val ONBOARDING_SHOW_ANSWER = "FirstShowAnswer" - const val ONBOARDING_FLAG = "FirstFlag" - const val ONBOARDING_UNDO_PREVIOUS_CARD = "FirstUndoPreviousCard" - const val ONBOARDING_CARD_DIFFICULTY_SELECTOR = "FirstCardDifficultySelector" - const val ONBOARDING_DECK_PICKER_FAB = "FirstDeckPickerFAB" - const val ONBOARDING_SELECT_DECK = "OnboardingSelectDeck" - const val ONBOARDING_COUNTS_LAYOUT = "OnboardingCountsLayout" - const val ONBOARDING_FRONT_AND_BACK = "OnboardingFrontAndBack" - const val ONBOARDING_CARD_FORMATTING_TOOLS = "OnboardingCardFormattingTools" -} diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/OnboardingUtils.kt b/AnkiDroid/src/main/java/com/ichi2/anki/OnboardingUtils.kt new file mode 100644 index 000000000000..cf30885f1a30 --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/OnboardingUtils.kt @@ -0,0 +1,39 @@ +package com.ichi2.anki + +import android.content.Context + +object OnboardingUtils { + + const val ONBOARDING = "Onboarding" + const val defaultValue: Long = Long.MAX_VALUE + + /** + * Check if the tutorial for a particular feature should be displayed or not based on whether + * the bit at the index defined for that feature is set or not. + */ + fun checkIfNotAlreadyVisited(index: Int, context: Context): Boolean { + return (AnkiDroidApp.getSharedPrefs(context).getLong(ONBOARDING, defaultValue) and (1L shl index)) != 0L + } + + /** + * Set the bit at the index defined for a feature once the tutorial for that feature is seen by the user. + */ + fun setAsVisited(index: Int, context: Context) { + val currentValue = AnkiDroidApp.getSharedPrefs(context).getLong(ONBOARDING, defaultValue) + return AnkiDroidApp.getSharedPrefs(context).edit().putLong(ONBOARDING, currentValue and (1L shl index).inv()).apply() + } +} + +/* +Meaning of each index: +0 -> Introduction slides +1 -> FAB in Deck Picker +2 -> Deck name +3 -> Deck counts layout +4 -> Show answer +5 -> Flag option in reviewer +6 -> Undo option in reviewer +7 -> Difficulty selection after looking at answer +8 -> Front and back fields in note editor +9 -> Formatting tools in note editor +*/ diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.java b/AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.java index 554ff9c4120a..ec35f0065b3c 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.java @@ -81,7 +81,6 @@ import com.ichi2.themes.Themes; import com.ichi2.utils.AndroidUiUtils; import com.ichi2.utils.DimmedCirclePromptBackground; -import com.ichi2.utils.DimmedRectanglePromptBackground; import com.ichi2.utils.FunctionalInterfaces.Consumer; import com.ichi2.utils.PairWithBoolean; import com.ichi2.utils.Permissions; @@ -94,8 +93,6 @@ import timber.log.Timber; import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_FLAG; -import static com.ichi2.anki.OnboardingConstants.ONBOARDING_UNDO_PREVIOUS_CARD; import static com.ichi2.anki.reviewer.CardMarker.*; import static com.ichi2.anki.cardviewer.ViewerCommand.COMMAND_NOTHING; import static com.ichi2.anim.ActivityTransitionAnimation.Direction.*; @@ -129,8 +126,6 @@ public class Reviewer extends AbstractFlashcardViewer { // Preferences from the collection private boolean mShowRemainingCardCount; - private SharedPreferences mSharedPreferences; - private final ActionButtons mActionButtons = new ActionButtons(this); @@ -695,11 +690,9 @@ public boolean onCreateOptionsMenu(Menu menu) { setupSubMenu(menu, R.id.action_schedule, new ScheduleProvider(this)); - mSharedPreferences = getSharedPreferences("PERSISTENT_STATE_FILE", 0); - - if (mSharedPreferences.getBoolean(ONBOARDING_FLAG, true)) { + if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(5, this)) { new Handler().post(this::showTutorialForFlag); - } else if (mSharedPreferences.getBoolean(ONBOARDING_UNDO_PREVIOUS_CARD, true)) { + } else if (OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(6, this)) { new Handler().post(this::showTutorialForUndo); } @@ -709,30 +702,30 @@ public boolean onCreateOptionsMenu(Menu menu) { public void showTutorialForFlag() { new MaterialTapTargetPrompt.Builder(this) .setTarget(R.id.action_flag) - .setPrimaryText("Flag card") - .setSecondaryText("Select a coloured flag for this card") + .setPrimaryText(this.getString(R.string.flag_card)) + .setSecondaryText(this.getString(R.string.flag_card_desc)) .setFocalColour(ContextCompat.getColor(this, R.color.material_light_blue_500)) .setPromptStateChangeListener((prompt, state) -> { if (state == MaterialTapTargetPrompt.STATE_DISMISSED && - mSharedPreferences.getBoolean(ONBOARDING_UNDO_PREVIOUS_CARD, true)) { + OnboardingUtils.INSTANCE.checkIfNotAlreadyVisited(6, this)) { showTutorialForUndo(); } }) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_FLAG, false).apply(); + OnboardingUtils.INSTANCE.setAsVisited(5, this); } public void showTutorialForUndo() { new MaterialTapTargetPrompt.Builder(this) .setTarget(R.id.action_undo) - .setPrimaryText("Undo") - .setSecondaryText("Undo and go back to the previous card") + .setPrimaryText(this.getString(R.string.undo)) + .setSecondaryText(this.getString(R.string.undo_desc)) .setPromptBackground(new DimmedCirclePromptBackground()) .setFocalColour(ContextCompat.getColor(this, R.color.material_light_blue_500)) .show(); - mSharedPreferences.edit().putBoolean(ONBOARDING_UNDO_PREVIOUS_CARD, false).apply(); + OnboardingUtils.INSTANCE.setAsVisited(6, this); } @SuppressLint("RestrictedApi") // setOptionalIconsVisible diff --git a/AnkiDroid/src/main/java/com/ichi2/utils/DimmedCirclePromptBackground.java b/AnkiDroid/src/main/java/com/ichi2/utils/DimmedCirclePromptBackground.java index 869b8b30daef..38a8459a129b 100644 --- a/AnkiDroid/src/main/java/com/ichi2/utils/DimmedCirclePromptBackground.java +++ b/AnkiDroid/src/main/java/com/ichi2/utils/DimmedCirclePromptBackground.java @@ -41,7 +41,7 @@ public void update(@NonNull final PromptOptions options, float revealModifier, f { super.update(options, revealModifier, alphaModifier); // Allow for the dimmed background to fade in and out - this.mDimPaint.setAlpha((int) (200 * alphaModifier)); + this.mDimPaint.setAlpha((int) (150 * alphaModifier)); } @Override @@ -52,4 +52,4 @@ public void draw(@NonNull Canvas canvas) // Draw the background super.draw(canvas); } -} \ No newline at end of file +} diff --git a/AnkiDroid/src/main/java/com/ichi2/utils/DimmedRectanglePromptBackground.java b/AnkiDroid/src/main/java/com/ichi2/utils/DimmedRectanglePromptBackground.java index 8a0c461aa65b..b9deccb90bfd 100644 --- a/AnkiDroid/src/main/java/com/ichi2/utils/DimmedRectanglePromptBackground.java +++ b/AnkiDroid/src/main/java/com/ichi2/utils/DimmedRectanglePromptBackground.java @@ -41,7 +41,7 @@ public void update(@NonNull final PromptOptions options, float revealModifier, f { super.update(options, revealModifier, alphaModifier); // Allow for the dimmed background to fade in and out - this.mDimPaint.setAlpha((int) (200 * alphaModifier)); + this.mDimPaint.setAlpha((int) (150 * alphaModifier)); } @Override @@ -52,4 +52,4 @@ public void draw(@NonNull Canvas canvas) // Draw the background super.draw(canvas); } -} \ No newline at end of file +} diff --git a/AnkiDroid/src/main/res/values/19-onboarding.xml b/AnkiDroid/src/main/res/values/19-onboarding.xml new file mode 100644 index 000000000000..0adfd3761050 --- /dev/null +++ b/AnkiDroid/src/main/res/values/19-onboarding.xml @@ -0,0 +1,31 @@ + + + AnkiDroid is a spaced repetition flashcard app. Memorize anything with AnkiDroid! + Create powerful decks with customised cards + Choose from multiple card types + Create cards which support multiple content formats + Text - Images - Sounds - MathJax - LaTeX + Choose from 6000+ pre-made decks + You can browse and import decks made by others. + Study time + Review cards and select their difficulty according to which the time interval for their next appearance will be decided + Detailed Statistics + Helps you track your study progress + Put less strain on your eyes + Select the difficulty + This will decide the time when this card will be displayed again + Get started + Create a deck, download a pre-made deck or add a note + Flag card + Select a coloured flag for this card + Undo and go back to the previous card + Format content + Format your card\'s content using various formatting options + Enter card contents here + Enter the front part of card in \'Front\' field and the answer in \'Back\' field + See the answer + When you are ready to view the answer, click here + Click on a deck to start studying + Long press on a deck to get more options related to it + Open study options to see card review details for a deck + \ No newline at end of file diff --git a/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.java b/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.java index b8575a14fa20..56ed2a7440ea 100644 --- a/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.java +++ b/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.java @@ -30,6 +30,7 @@ import com.ichi2.anki.FilteredDeckOptions; import com.ichi2.anki.Info; import com.ichi2.anki.IntentHandler; +import com.ichi2.anki.IntroductionActivity; import com.ichi2.anki.ModelBrowser; import com.ichi2.anki.ModelFieldEditor; import com.ichi2.anki.MyAccount; @@ -90,7 +91,8 @@ public static List allActivitiesAndIntents() { get(LoadPronounciationActivity.class), get(CardInfo.class), get(CardTemplateEditor.class, ActivityList::intentForCardTemplateEditor), - get(CardTemplateBrowserAppearanceEditor.class, ActivityList::intentForCardTemplateBrowserAppearanceEditor) + get(CardTemplateBrowserAppearanceEditor.class, ActivityList::intentForCardTemplateBrowserAppearanceEditor), + get(IntroductionActivity.class) ); }