diff --git a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivity.kt b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivity.kt index 9ffbd1969e3..18fd3178e31 100644 --- a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivity.kt +++ b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivity.kt @@ -9,8 +9,10 @@ import org.oppia.android.app.home.RouteToExplorationListener import org.oppia.android.app.model.ExplorationActivityParams import org.oppia.android.app.model.ExplorationCheckpoint import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.ResumeLessonActivityParams import org.oppia.android.app.model.ScreenName.RESUME_LESSON_ACTIVITY +import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener import org.oppia.android.app.player.exploration.ExplorationActivity import org.oppia.android.util.extensions.getProtoExtra import org.oppia.android.util.extensions.putProtoExtra @@ -20,6 +22,7 @@ import javax.inject.Inject /** Activity that allows the user to resume a saved exploration. */ class ResumeLessonActivity : InjectableAutoLocalizedAppCompatActivity(), + DefaultFontSizeStateListener, RouteToExplorationListener { @Inject lateinit var resumeLessonActivityPresenter: ResumeLessonActivityPresenter @@ -87,6 +90,7 @@ class ResumeLessonActivity : parentScreen: ExplorationActivityParams.ParentScreen, isCheckpointingEnabled: Boolean ) { + resumeLessonActivityPresenter.setReadingTextSizeNormal() startActivity( ExplorationActivity.createExplorationActivityIntent( this, @@ -100,4 +104,13 @@ class ResumeLessonActivity : ) finish() } + + override fun onDefaultFontSizeLoaded(readingTextSize: ReadingTextSize) { + resumeLessonActivityPresenter.loadResumeLessonFragment(readingTextSize) + } + + override fun onBackPressed() { + resumeLessonActivityPresenter.setReadingTextSizeNormal() + finish() + } } diff --git a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt index e6cbc39c507..104a119e820 100644 --- a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt @@ -2,19 +2,40 @@ package org.oppia.android.app.resumelesson import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import org.oppia.android.R import org.oppia.android.app.model.ExplorationActivityParams import org.oppia.android.app.model.ExplorationCheckpoint +import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize +import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener +import org.oppia.android.app.utility.FontScaleConfigurationUtil import org.oppia.android.databinding.ResumeLessonActivityBinding +import org.oppia.android.domain.oppialogger.OppiaLogger +import org.oppia.android.domain.profile.ProfileManagementController +import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.data.DataProviders.Companion.toLiveData import javax.inject.Inject private const val RESUME_LESSON_TAG = "ResumeLesson" /** The presenter for [ResumeLessonActivity]. */ class ResumeLessonActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + private val profileManagementController: ProfileManagementController, + private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, + private val oppiaLogger: OppiaLogger ) { + private lateinit var profileId: ProfileId + + private lateinit var topicId: String + private lateinit var storyId: String + private lateinit var explorationId: String + private lateinit var parentScreen: ExplorationActivityParams.ParentScreen + private lateinit var explorationCheckpoint: ExplorationCheckpoint /** Handles onCreate() method of the [ResumeLessonActivity]. */ fun handleOnCreate( @@ -29,29 +50,82 @@ class ResumeLessonActivityPresenter @Inject constructor( activity, R.layout.resume_lesson_activity ) + this.profileId = profileId + this.topicId = topicId + this.storyId = storyId + this.explorationId = explorationId + this.explorationCheckpoint = explorationCheckpoint + this.parentScreen = parentScreen val resumeLessonToolbar = binding.resumeLessonActivityToolbar activity.setSupportActionBar(resumeLessonToolbar) + retrieveReadingTextSize().observe( + activity as ResumeLessonActivity, + { result -> + (activity as DefaultFontSizeStateListener).onDefaultFontSizeLoaded(result) + } + ) + resumeLessonToolbar.setNavigationOnClickListener { + fontScaleConfigurationUtil.adjustFontScale( + context = activity, + ReadingTextSize.MEDIUM_TEXT_SIZE + ) @Suppress("DEPRECATION") // TODO(#5404): Migrate to a back pressed dispatcher. activity.onBackPressed() } + } - if (getResumeLessonFragment() == null) { - val resumeLessonFragment = ResumeLessonFragment.newInstance( - profileId, - topicId, - storyId, - explorationId, - parentScreen, - explorationCheckpoint - ) - activity.supportFragmentManager.beginTransaction().add( - R.id.resume_lesson_fragment_placeholder, - resumeLessonFragment, - RESUME_LESSON_TAG - ).commitNow() - } + /** Loads [ResumeLessonFragment]. */ + fun loadResumeLessonFragment(readingTextSize: ReadingTextSize) { + if (getResumeLessonFragment() != null) + activity.supportFragmentManager.beginTransaction() + .remove(getResumeLessonFragment() as Fragment).commitNow() + + val resumeLessonFragment = ResumeLessonFragment.newInstance( + profileId, + topicId, + storyId, + explorationId, + parentScreen, + explorationCheckpoint, + readingTextSize + ) + activity.supportFragmentManager.beginTransaction().add( + R.id.resume_lesson_fragment_placeholder, + resumeLessonFragment, + RESUME_LESSON_TAG + ).commitNow() + } + + private fun retrieveReadingTextSize(): LiveData { + return Transformations.map( + profileManagementController.getProfile(profileId).toLiveData(), + ::processReadingTextSizeResult + ) + } + + private fun processReadingTextSizeResult( + profileResult: AsyncResult + ): ReadingTextSize { + return when (profileResult) { + is AsyncResult.Failure -> { + oppiaLogger.e( + "ResumeLessonActivity", + "Failed to retrieve profile", + profileResult.error + ) + Profile.getDefaultInstance() + } + is AsyncResult.Pending -> { + oppiaLogger.d( + "ResumeLessonActivity", + "Result is pending" + ) + Profile.getDefaultInstance() + } + is AsyncResult.Success -> profileResult.value + }.readingTextSize } private fun getResumeLessonFragment(): ResumeLessonFragment? { @@ -61,4 +135,12 @@ class ResumeLessonActivityPresenter @Inject constructor( R.id.resume_lesson_fragment_placeholder ) as ResumeLessonFragment? } + + /** Set reading text size normal. */ + fun setReadingTextSizeNormal() { + fontScaleConfigurationUtil.adjustFontScale( + context = activity, + ReadingTextSize.MEDIUM_TEXT_SIZE + ) + } } diff --git a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragment.kt b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragment.kt index 10a05914af6..df371344331 100644 --- a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragment.kt +++ b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragment.kt @@ -10,6 +10,7 @@ import org.oppia.android.app.fragment.InjectableFragment import org.oppia.android.app.model.ExplorationActivityParams import org.oppia.android.app.model.ExplorationCheckpoint import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.ResumeLessonFragmentArguments import org.oppia.android.util.extensions.getProto import org.oppia.android.util.extensions.putProto @@ -18,7 +19,9 @@ import javax.inject.Inject /** Fragment that allows the user to resume a saved exploration. */ class ResumeLessonFragment : InjectableFragment() { companion object { - private const val ARGUMENTS_KEY = "ResumeExplorationFragment.arguments" + + /** Arguments key for [ResumeLessonFragment]. */ + const val ARGUMENTS_KEY = "ResumeExplorationFragment.arguments" /** Creates new instance of [ResumeLessonFragment] for the provided parameters. */ fun newInstance( @@ -27,7 +30,8 @@ class ResumeLessonFragment : InjectableFragment() { storyId: String, explorationId: String, parentScreen: ExplorationActivityParams.ParentScreen, - checkpoint: ExplorationCheckpoint + checkpoint: ExplorationCheckpoint, + readingTextSize: ReadingTextSize ): ResumeLessonFragment { val args = ResumeLessonFragmentArguments.newBuilder().apply { this.profileId = profileId @@ -36,6 +40,7 @@ class ResumeLessonFragment : InjectableFragment() { this.explorationId = explorationId this.parentScreen = parentScreen this.checkpoint = checkpoint + this.readingTextSize = readingTextSize }.build() return ResumeLessonFragment().apply { arguments = Bundle().apply { @@ -51,6 +56,7 @@ class ResumeLessonFragment : InjectableFragment() { override fun onAttach(context: Context) { super.onAttach(context) (fragmentComponent as FragmentComponentImpl).inject(this) + resumeLessonFragmentPresenter.handleAttach(context) } override fun onCreateView( diff --git a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentPresenter.kt index b3775e5607f..c03b5db684e 100644 --- a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentPresenter.kt @@ -1,5 +1,6 @@ package org.oppia.android.app.resumelesson +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -12,7 +13,9 @@ import org.oppia.android.app.model.EphemeralChapterSummary import org.oppia.android.app.model.ExplorationActivityParams import org.oppia.android.app.model.ExplorationCheckpoint import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ResumeLessonFragmentArguments import org.oppia.android.app.translation.AppLanguageResourceHandler +import org.oppia.android.app.utility.FontScaleConfigurationUtil import org.oppia.android.databinding.ResumeLessonFragmentBinding import org.oppia.android.domain.exploration.ExplorationDataController import org.oppia.android.domain.oppialogger.OppiaLogger @@ -20,6 +23,7 @@ import org.oppia.android.domain.topic.TopicController import org.oppia.android.domain.translation.TranslationController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.extensions.getProto import org.oppia.android.util.gcsresource.DefaultResourceBucketName import org.oppia.android.util.parser.html.HtmlParser import javax.inject.Inject @@ -31,6 +35,7 @@ class ResumeLessonFragmentPresenter @Inject constructor( private val resumeLessonViewModel: ResumeLessonViewModel, private val topicController: TopicController, private val explorationDataController: ExplorationDataController, + private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, private val htmlParserFactory: HtmlParser.Factory, private val translationController: TranslationController, @DefaultResourceBucketName private val resourceBucketName: String, @@ -54,6 +59,11 @@ class ResumeLessonFragmentPresenter @Inject constructor( getChapterSummary() } + /** Handles the [Fragment.onAttach] portion of [ResumeLessonFragment]'s lifecycle. */ + fun handleAttach(context: Context) { + fontScaleConfigurationUtil.adjustFontScale(context, retrieveArguments().readingTextSize) + } + /** Handles onCreateView() method of the [ResumeLessonFragment]. */ fun handleOnCreate( inflater: LayoutInflater, @@ -70,7 +80,6 @@ class ResumeLessonFragmentPresenter @Inject constructor( container, /* attachToRoot= */ false ) - this.profileId = profileId this.topicId = topicId this.storyId = storyId @@ -105,10 +114,15 @@ class ResumeLessonFragmentPresenter @Inject constructor( parentScreen ) } - return binding.root } + private fun retrieveArguments(): ResumeLessonFragmentArguments { + return fragment.requireArguments().getProto( + ResumeLessonFragment.ARGUMENTS_KEY, ResumeLessonFragmentArguments.getDefaultInstance() + ) + } + private fun subscribeToChapterSummary() { chapterSummaryLiveData.observe( fragment, diff --git a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivity.kt b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivity.kt index 1f4a1c57e74..70239733952 100644 --- a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivity.kt +++ b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivity.kt @@ -11,9 +11,11 @@ import org.oppia.android.app.hintsandsolution.RevealSolutionInterface import org.oppia.android.app.model.HelpIndex import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.QuestionPlayerActivityParams +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.ScreenName.QUESTION_PLAYER_ACTIVITY import org.oppia.android.app.model.State import org.oppia.android.app.model.WrittenTranslationContext +import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener import org.oppia.android.app.player.state.listener.RouteToHintsAndSolutionListener import org.oppia.android.app.player.state.listener.StateKeyboardButtonListener import org.oppia.android.app.player.stopplaying.RestartPlayingSessionListener @@ -41,6 +43,7 @@ class QuestionPlayerActivity : RevealHintListener, RevealSolutionInterface, HintsAndSolutionQuestionManagerListener, + DefaultFontSizeStateListener, ConceptCardListener { @Inject @@ -57,6 +60,7 @@ class QuestionPlayerActivity : override fun onBackPressed() { showStopExplorationDialogFragment() + questionPlayerActivityPresenter.setReadingTextSizeNormal() } override fun restartSession() = questionPlayerActivityPresenter.restartSession() @@ -130,4 +134,8 @@ class QuestionPlayerActivity : override fun stopSession() { questionPlayerActivityPresenter.stopTrainingSession() } + + override fun onDefaultFontSizeLoaded(readingTextSize: ReadingTextSize) { + questionPlayerActivityPresenter.loadFragments(readingTextSize) + } } diff --git a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt index c705384c950..4eb9804a176 100644 --- a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt @@ -3,18 +3,26 @@ package org.oppia.android.app.topic.questionplayer import android.view.inputmethod.EditorInfo import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import org.oppia.android.R import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.hintsandsolution.HintsAndSolutionDialogFragment import org.oppia.android.app.model.HelpIndex +import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.QuestionPlayerActivityParams +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.State import org.oppia.android.app.model.WrittenTranslationContext +import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener import org.oppia.android.app.player.exploration.TAG_HINTS_AND_SOLUTION_DIALOG import org.oppia.android.app.topic.questionplayer.QuestionPlayerActivity.Companion.QUESTION_PLAYER_ACTIVITY_PARAMS_KEY +import org.oppia.android.app.utility.FontScaleConfigurationUtil import org.oppia.android.databinding.QuestionPlayerActivityBinding import org.oppia.android.domain.oppialogger.OppiaLogger +import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.question.QuestionTrainingController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData @@ -29,11 +37,14 @@ private const val TAG_HINTS_AND_SOLUTION_QUESTION_MANAGER = "HINTS_AND_SOLUTION_ class QuestionPlayerActivityPresenter @Inject constructor( private val activity: AppCompatActivity, private val questionTrainingController: QuestionTrainingController, - private val oppiaLogger: OppiaLogger + private val oppiaLogger: OppiaLogger, + private val profileManagementController: ProfileManagementController, + private val fontScaleConfigurationUtil: FontScaleConfigurationUtil ) { private lateinit var profileId: ProfileId private lateinit var state: State private lateinit var writtenTranslationContext: WrittenTranslationContext + private lateinit var readingTextSize: ReadingTextSize fun handleOnCreate(profileId: ProfileId) { this.profileId = profileId @@ -54,14 +65,31 @@ class QuestionPlayerActivityPresenter @Inject constructor( activity.onBackPressed() } + retrieveReadingTextSize().observe( + activity as QuestionPlayerActivity + ) { result -> + (activity as DefaultFontSizeStateListener).onDefaultFontSizeLoaded(result) + } + } + + private fun loadQuestionPlayerFragment(readingTextSize: ReadingTextSize) { + startTrainingSessionWithCallback { + activity.supportFragmentManager.beginTransaction().add( + R.id.question_player_fragment_placeholder, + QuestionPlayerFragment.newInstance(profileId, readingTextSize), + TAG_QUESTION_PLAYER_FRAGMENT + ).commitNow() + } + } + + fun loadFragments(readingTextSize: ReadingTextSize) { + this.readingTextSize = readingTextSize if (getQuestionPlayerFragment() == null) { - startTrainingSessionWithCallback { - activity.supportFragmentManager.beginTransaction().add( - R.id.question_player_fragment_placeholder, - QuestionPlayerFragment.newInstance(profileId), - TAG_QUESTION_PLAYER_FRAGMENT - ).commitNow() - } + loadQuestionPlayerFragment(readingTextSize) + } else { + activity.supportFragmentManager.beginTransaction() + .remove(getQuestionPlayerFragment() as Fragment).commitNow() + loadQuestionPlayerFragment(readingTextSize) } if (getHintsAndSolutionExplorationManagerFragment() == null) { @@ -72,6 +100,36 @@ class QuestionPlayerActivityPresenter @Inject constructor( } } + private fun retrieveReadingTextSize(): LiveData { + return Transformations.map( + profileManagementController.getProfile(profileId).toLiveData(), + ::processReadingTextSizeResult + ) + } + + private fun processReadingTextSizeResult( + profileResult: AsyncResult + ): ReadingTextSize { + return when (profileResult) { + is AsyncResult.Failure -> { + oppiaLogger.e( + "QuestionPlayerActivity", + "Failed to retrieve profile", + profileResult.error + ) + Profile.getDefaultInstance() + } + is AsyncResult.Pending -> { + oppiaLogger.d( + "QuestionPlayerActivity", + "Result is pending" + ) + Profile.getDefaultInstance() + } + is AsyncResult.Success -> profileResult.value + }.readingTextSize + } + private fun getHintsAndSolutionExplorationManagerFragment(): HintsAndSolutionQuestionManagerFragment? { // ktlint-disable max-line-length return activity.supportFragmentManager.findFragmentByTag( TAG_HINTS_AND_SOLUTION_QUESTION_MANAGER @@ -93,7 +151,7 @@ class QuestionPlayerActivityPresenter @Inject constructor( // Re-add the player fragment when the new session is ready. activity.supportFragmentManager.beginTransaction().add( R.id.question_player_fragment_placeholder, - QuestionPlayerFragment.newInstance(profileId), + QuestionPlayerFragment.newInstance(profileId, readingTextSize), TAG_QUESTION_PLAYER_FRAGMENT ).commitNow() } @@ -143,10 +201,12 @@ class QuestionPlayerActivityPresenter @Inject constructor( oppiaLogger.d("QuestionPlayerActivity", "Stopping training session") is AsyncResult.Failure -> { oppiaLogger.e("QuestionPlayerActivity", "Failed to stop training session", it.error) + setReadingTextSizeNormal() activity.finish() // Can't recover from the session failing to stop. } is AsyncResult.Success -> { oppiaLogger.d("QuestionPlayerActivity", "Successfully stopped training session") + setReadingTextSizeNormal() callback() } } @@ -221,4 +281,12 @@ class QuestionPlayerActivityPresenter @Inject constructor( TAG_HINTS_AND_SOLUTION_DIALOG ) as? HintsAndSolutionDialogFragment } + + /** Set reading text size normal. */ + fun setReadingTextSizeNormal() { + fontScaleConfigurationUtil.adjustFontScale( + context = activity, + ReadingTextSize.MEDIUM_TEXT_SIZE + ) + } } diff --git a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragment.kt b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragment.kt index f92e0884e3d..23cb0b8afe0 100644 --- a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragment.kt +++ b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragment.kt @@ -9,6 +9,8 @@ import org.oppia.android.app.fragment.FragmentComponentImpl import org.oppia.android.app.fragment.InjectableFragment import org.oppia.android.app.model.HelpIndex import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.QuestionPlayerFragmentArguments +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.UserAnswer import org.oppia.android.app.player.state.answerhandling.InteractionAnswerErrorOrAvailabilityCheckReceiver import org.oppia.android.app.player.state.answerhandling.InteractionAnswerReceiver @@ -42,6 +44,7 @@ class QuestionPlayerFragment : override fun onAttach(context: Context) { super.onAttach(context) (fragmentComponent as FragmentComponentImpl).inject(this) + questionPlayerFragmentPresenter.handleAttach(context) } override fun onCreateView( @@ -52,7 +55,9 @@ class QuestionPlayerFragment : val args = checkNotNull(arguments) { "Expected arguments to be passed to QuestionPlayerFragment" } - val profileId = args.getProto(PROFILE_ID_ARGUMENT_KEY, ProfileId.getDefaultInstance()) + val arguments = + args.getProto(ARGUMENTS_KEY, QuestionPlayerFragmentArguments.getDefaultInstance()) + val profileId = arguments.profileId return questionPlayerFragmentPresenter.handleCreateView(inflater, container, profileId) } @@ -96,7 +101,9 @@ class QuestionPlayerFragment : fun dismissConceptCard() = questionPlayerFragmentPresenter.dismissConceptCard() companion object { - private const val PROFILE_ID_ARGUMENT_KEY = "QuestionPlayerFragment.profile_id" + + /** Arguments key for [QuestionPlayerFragment]. */ + const val ARGUMENTS_KEY = "QuestionPlayerFragment.arguments" /** * Creates a new fragment to play a question session. @@ -104,12 +111,17 @@ class QuestionPlayerFragment : * @param profileId the profile in which the question play session will be played * @return a new [QuestionPlayerFragment] to start a question play session */ - fun newInstance(profileId: ProfileId): QuestionPlayerFragment { - return QuestionPlayerFragment().apply { - arguments = Bundle().apply { - putProto(PROFILE_ID_ARGUMENT_KEY, profileId) + fun newInstance(profileId: ProfileId, readingTextSize: ReadingTextSize): + QuestionPlayerFragment { + val args = QuestionPlayerFragmentArguments.newBuilder().apply { + this.profileId = profileId + this.readingTextSize = readingTextSize + }.build() + return QuestionPlayerFragment().apply { + arguments = Bundle().apply { + putProto(ARGUMENTS_KEY, args) + } } } - } } } diff --git a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragmentPresenter.kt index 78a978ba51c..e32c7349360 100644 --- a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerFragmentPresenter.kt @@ -18,6 +18,7 @@ import org.oppia.android.app.model.EphemeralQuestion import org.oppia.android.app.model.EphemeralState import org.oppia.android.app.model.HelpIndex import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.QuestionPlayerFragmentArguments import org.oppia.android.app.model.State import org.oppia.android.app.model.UserAnswer import org.oppia.android.app.player.state.ConfettiConfig.MINI_CONFETTI_BURST @@ -26,6 +27,7 @@ import org.oppia.android.app.player.state.listener.RouteToHintsAndSolutionListen import org.oppia.android.app.player.stopplaying.RestartPlayingSessionListener import org.oppia.android.app.player.stopplaying.StopStatePlayingSessionListener import org.oppia.android.app.topic.conceptcard.ConceptCardFragment +import org.oppia.android.app.utility.FontScaleConfigurationUtil import org.oppia.android.app.utility.SplitScreenManager import org.oppia.android.databinding.QuestionPlayerFragmentBinding import org.oppia.android.domain.oppialogger.OppiaLogger @@ -34,6 +36,7 @@ import org.oppia.android.domain.question.QuestionAssessmentProgressController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.extensions.getProto import org.oppia.android.util.gcsresource.QuestionResourceBucketName import javax.inject.Inject @@ -48,7 +51,8 @@ class QuestionPlayerFragmentPresenter @Inject constructor( private val analyticsController: AnalyticsController, @QuestionResourceBucketName private val resourceBucketName: String, private val assemblerBuilderFactory: StatePlayerRecyclerViewAssembler.Builder.Factory, - private val splitScreenManager: SplitScreenManager + private val splitScreenManager: SplitScreenManager, + private val fontScaleConfigurationUtil: FontScaleConfigurationUtil ) { // TODO(#503): Add tests for the question player. @@ -66,6 +70,11 @@ class QuestionPlayerFragmentPresenter @Inject constructor( private lateinit var helpIndex: HelpIndex private lateinit var profileId: ProfileId + /** Handles the [Fragment.onAttach] portion of [QuestionPlayerFragment]'s lifecycle. */ + fun handleAttach(context: Context) { + fontScaleConfigurationUtil.adjustFontScale(context, retrieveArguments().readingTextSize) + } + fun handleCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -117,6 +126,12 @@ class QuestionPlayerFragmentPresenter @Inject constructor( ConceptCardFragment.dismissAll(fragment.childFragmentManager) } + private fun retrieveArguments(): QuestionPlayerFragmentArguments { + return fragment.requireArguments().getProto( + QuestionPlayerFragment.ARGUMENTS_KEY, QuestionPlayerFragmentArguments.getDefaultInstance() + ) + } + fun handleAnswerReadyForSubmission(answer: UserAnswer) { // An interaction has indicated that an answer is ready for submission. handleSubmitAnswer(answer) diff --git a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivity.kt b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivity.kt index 4f6e87509e7..0dc515a04b7 100644 --- a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivity.kt +++ b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivity.kt @@ -6,9 +6,11 @@ import android.os.Bundle import org.oppia.android.app.activity.ActivityComponentImpl import org.oppia.android.app.activity.InjectableAutoLocalizedAppCompatActivity import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.RevisionCardActivityParams import org.oppia.android.app.model.ScreenName.REVISION_CARD_ACTIVITY import org.oppia.android.app.player.exploration.BottomSheetOptionsMenuItemClickListener +import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener import org.oppia.android.app.topic.RouteToRevisionCardListener import org.oppia.android.app.topic.conceptcard.ConceptCardListener import org.oppia.android.util.extensions.getProtoExtra @@ -24,6 +26,7 @@ class RevisionCardActivity : ReturnToTopicClickListener, ConceptCardListener, RouteToRevisionCardListener, + DefaultFontSizeStateListener, BottomSheetOptionsMenuItemClickListener { @Inject @@ -112,7 +115,13 @@ class RevisionCardActivity : revisionCardActivityPresenter.dismissConceptCard() } + @Deprecated("Deprecated in Java") override fun onBackPressed() { + revisionCardActivityPresenter.setReadingTextSizeMedium() onReturnToTopicRequested() } + + override fun onDefaultFontSizeLoaded(readingTextSize: ReadingTextSize) { + revisionCardActivityPresenter.loadRevisionCardFragment(readingTextSize) + } } diff --git a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt index 1d1036c3ef0..a6873bfd685 100644 --- a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt @@ -4,18 +4,24 @@ import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import org.oppia.android.R import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.help.HelpActivity import org.oppia.android.app.model.EphemeralRevisionCard +import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.options.OptionsActivity import org.oppia.android.app.player.exploration.BottomSheetOptionsMenu +import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener +import org.oppia.android.app.utility.FontScaleConfigurationUtil import org.oppia.android.databinding.RevisionCardActivityBinding import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController +import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicController import org.oppia.android.domain.translation.TranslationController import org.oppia.android.util.accessibility.AccessibilityService @@ -24,13 +30,16 @@ import org.oppia.android.util.data.DataProviders.Companion.toLiveData import javax.inject.Inject /** The presenter for [RevisionCardActivity]. */ +@Suppress("DEPRECATION") @ActivityScope class RevisionCardActivityPresenter @Inject constructor( private val activity: AppCompatActivity, private val oppiaLogger: OppiaLogger, private val analyticsController: AnalyticsController, private val topicController: TopicController, - private val translationController: TranslationController + private val translationController: TranslationController, + private val profileManagementController: ProfileManagementController, + private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, ) { @Inject lateinit var accessibilityService: AccessibilityService @@ -40,6 +49,7 @@ class RevisionCardActivityPresenter @Inject constructor( private lateinit var profileId: ProfileId private lateinit var topicId: String private var subtopicId: Int = 0 + private var subtopicListSize: Int = 0 fun handleOnCreate( internalProfileId: Int, @@ -54,11 +64,18 @@ class RevisionCardActivityPresenter @Inject constructor( profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() this.topicId = topicId this.subtopicId = subtopicId + this.subtopicListSize = subtopicListSize binding.apply { lifecycleOwner = activity } + retrieveReadingTextSize().observe( + activity + ) { result -> + (activity as DefaultFontSizeStateListener).onDefaultFontSizeLoaded(result) + } + revisionCardToolbar = binding.revisionCardToolbar revisionCardToolbarTitle = binding.revisionCardToolbarTitle activity.setSupportActionBar(revisionCardToolbar) @@ -66,6 +83,8 @@ class RevisionCardActivityPresenter @Inject constructor( binding.revisionCardToolbar.setNavigationOnClickListener { (activity as ReturnToTopicClickListener).onReturnToTopicRequested() + fontScaleConfigurationUtil.adjustFontScale(activity, ReadingTextSize.MEDIUM_TEXT_SIZE) + activity.onBackPressed() } if (!accessibilityService.isScreenReaderEnabled()) { binding.revisionCardToolbarTitle.setOnClickListener { @@ -79,17 +98,41 @@ class RevisionCardActivityPresenter @Inject constructor( val bottomSheetOptionsMenu = BottomSheetOptionsMenu() bottomSheetOptionsMenu.showNow(activity.supportFragmentManager, bottomSheetOptionsMenu.tag) } + } - if (getReviewCardFragment() == null) { - activity.supportFragmentManager.beginTransaction().add( - R.id.revision_card_fragment_placeholder, - RevisionCardFragment.newInstance(topicId, subtopicId, profileId, subtopicListSize) - ).commitNow() - } + private fun retrieveReadingTextSize(): LiveData { + return Transformations.map( + profileManagementController.getProfile(profileId).toLiveData(), + ::processReadingTextSizeResult + ) + } + + private fun processReadingTextSizeResult( + profileResult: AsyncResult + ): ReadingTextSize { + return when (profileResult) { + is AsyncResult.Failure -> { + oppiaLogger.e( + "RevisionCardActivity", + "Failed to retrieve profile", + profileResult.error + ) + Profile.getDefaultInstance() + } + is AsyncResult.Pending -> { + oppiaLogger.d( + "RevisionCardActivity", + "Result is pending" + ) + Profile.getDefaultInstance() + } + is AsyncResult.Success -> profileResult.value + }.readingTextSize } /** Action for onOptionsItemSelected. */ fun handleOnOptionsItemSelected(itemId: Int): Boolean { + setReadingTextSizeMedium() return when (itemId) { R.id.action_options -> { val intent = OptionsActivity.createOptionsActivity( @@ -172,4 +215,25 @@ class RevisionCardActivityPresenter @Inject constructor( R.id.revision_card_fragment_placeholder ) as RevisionCardFragment? } + + fun loadRevisionCardFragment(readingTextSize: ReadingTextSize) { + if (getReviewCardFragment() != null) + activity.supportFragmentManager.beginTransaction() + .remove(getReviewCardFragment() as Fragment).commitNow() + + activity.supportFragmentManager.beginTransaction().add( + R.id.revision_card_fragment_placeholder, + RevisionCardFragment.newInstance( + topicId, + subtopicId, + profileId, + subtopicListSize, + readingTextSize + ) + ).commitNow() + } + + fun setReadingTextSizeMedium() { + fontScaleConfigurationUtil.adjustFontScale(activity, ReadingTextSize.MEDIUM_TEXT_SIZE) + } } diff --git a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragment.kt b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragment.kt index 303c9c04478..54716b5db25 100755 --- a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragment.kt +++ b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragment.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import org.oppia.android.app.fragment.FragmentComponentImpl import org.oppia.android.app.fragment.InjectableDialogFragment import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.RevisionCardFragmentArguments import org.oppia.android.util.extensions.getProto import org.oppia.android.util.extensions.putProto @@ -25,12 +26,19 @@ class RevisionCardFragment : InjectableDialogFragment() { * Returns a new [RevisionCardFragment] to display the specific subtopic for the given topic & * profile. */ - fun newInstance(topicId: String, subtopicId: Int, profileId: ProfileId, subtopicListSize: Int): + fun newInstance( + topicId: String, + subtopicId: Int, + profileId: ProfileId, + subtopicListSize: Int, + readingTextSize: ReadingTextSize + ): RevisionCardFragment { val args = RevisionCardFragmentArguments.newBuilder().apply { this.topicId = topicId this.subtopicId = subtopicId this.subtopicListSize = subtopicListSize + this.readingTextSize = readingTextSize }.build() return RevisionCardFragment().apply { arguments = Bundle().apply { @@ -47,6 +55,7 @@ class RevisionCardFragment : InjectableDialogFragment() { override fun onAttach(context: Context) { super.onAttach(context) (fragmentComponent as FragmentComponentImpl).inject(this) + revisionCardFragmentPresenter.handleAttach(context) } override fun onCreateView( @@ -70,12 +79,16 @@ class RevisionCardFragment : InjectableDialogFragment() { val subtopicId = args?.subtopicId ?: -1 val profileId = arguments.extractCurrentUserProfileId() val subtopicListSize = args?.subtopicListSize ?: -1 - return revisionCardFragmentPresenter.handleCreateView( inflater, container, topicId, subtopicId, profileId, subtopicListSize ) } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + revisionCardFragmentPresenter.handleViewCreated() + } + /** Dismisses the concept card fragment if it's currently active in this fragment. */ fun dismissConceptCard() = revisionCardFragmentPresenter.dismissConceptCard() } diff --git a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentPresenter.kt index 5ac95363353..49da009045c 100755 --- a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentPresenter.kt @@ -1,17 +1,26 @@ package org.oppia.android.app.topic.revisioncard +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize +import org.oppia.android.app.model.RevisionCardFragmentArguments import org.oppia.android.app.topic.conceptcard.ConceptCardFragment +import org.oppia.android.app.topic.revisioncard.RevisionCardFragment.Companion.REVISION_CARD_FRAGMENT_ARGUMENTS_KEY import org.oppia.android.app.translation.AppLanguageResourceHandler +import org.oppia.android.app.utility.FontScaleConfigurationUtil import org.oppia.android.databinding.RevisionCardFragmentBinding import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController +import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.translation.TranslationController +import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.extensions.getProto import org.oppia.android.util.gcsresource.DefaultResourceBucketName import org.oppia.android.util.parser.html.HtmlParser import org.oppia.android.util.parser.html.TopicHtmlParserEntityType @@ -28,10 +37,18 @@ class RevisionCardFragmentPresenter @Inject constructor( @TopicHtmlParserEntityType private val entityType: String, private val translationController: TranslationController, private val appLanguageResourceHandler: AppLanguageResourceHandler, - private val revisionCardViewModelFactory: RevisionCardViewModel.Factory + private val revisionCardViewModelFactory: RevisionCardViewModel.Factory, + private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, + private val profileManagementController: ProfileManagementController ) : HtmlParser.CustomOppiaTagActionListener { private lateinit var profileId: ProfileId + /** Handles the [Fragment.onAttach] portion of [RevisionCardFragment]'s lifecycle. */ + fun handleAttach(context: Context) { + fontScaleConfigurationUtil.adjustFontScale(context, retrieveReadingTextSize()) + } + + /** Handles the [Fragment.onCreateView] portion of [RevisionCardFragment]'s lifecycle. */ fun handleCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -83,6 +100,23 @@ class RevisionCardFragmentPresenter @Inject constructor( return binding.root } + /** Handles the [Fragment.onCreateView] portion of [RevisionCardFragment]'s lifecycle. */ + fun handleViewCreated() { + val profileDataProvider = profileManagementController.getProfile(profileId) + profileDataProvider.toLiveData().observe( + fragment + ) { result -> + val readingTextSize = retrieveReadingTextSize() + if (result is AsyncResult.Success) { + if (result.value.readingTextSize != readingTextSize) { + // Since text views are based on sp for sizing, the activity needs to be recreated so that + // sp can be correctly recomputed. + fragment.requireActivity().recreate() + } + } + } + } + /** Dismisses the concept card fragment if it's currently active in this fragment. */ fun dismissConceptCard() { ConceptCardFragment.dismissAll(fragment.childFragmentManager) @@ -98,4 +132,12 @@ class RevisionCardFragmentPresenter @Inject constructor( override fun onConceptCardLinkClicked(view: View, skillId: String) { ConceptCardFragment.bringToFrontOrCreateIfNew(skillId, profileId, fragment.childFragmentManager) } + + private fun retrieveReadingTextSize(): ReadingTextSize { + return fragment.requireArguments() + .getProto( + REVISION_CARD_FRAGMENT_ARGUMENTS_KEY, + RevisionCardFragmentArguments.getDefaultInstance() + ).readingTextSize + } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentTest.kt b/app/src/sharedTest/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentTest.kt index 015955e6dde..b220e95051b 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/resumelesson/ResumeLessonFragmentTest.kt @@ -40,10 +40,12 @@ import org.oppia.android.app.devoptions.DeveloperOptionsStarterModule import org.oppia.android.app.model.ExplorationActivityParams import org.oppia.android.app.model.ExplorationCheckpoint import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.player.state.itemviewmodel.SplitScreenInteractionModule import org.oppia.android.app.shim.ViewBindingShimModule import org.oppia.android.app.translation.testing.ActivityRecreatorTestModule import org.oppia.android.app.utility.EspressoTestsMatchers.withDrawable +import org.oppia.android.app.utility.FontSizeMatcher.Companion.withFontSize import org.oppia.android.app.utility.OrientationChangeAction.Companion.orientationLandscape import org.oppia.android.data.backends.gae.NetworkConfigProdModule import org.oppia.android.data.backends.gae.NetworkModule @@ -83,8 +85,10 @@ import org.oppia.android.domain.topic.RATIOS_STORY_ID_0 import org.oppia.android.domain.topic.RATIOS_TOPIC_ID import org.oppia.android.domain.workmanager.WorkManagerConfigurationModule import org.oppia.android.testing.OppiaTestRule +import org.oppia.android.testing.RunOn import org.oppia.android.testing.TestImageLoaderModule import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.testing.TestPlatform import org.oppia.android.testing.firebase.TestAuthenticationModule import org.oppia.android.testing.junit.InitializeDefaultLocaleRule import org.oppia.android.testing.robolectric.RobolectricModule @@ -292,6 +296,62 @@ class ResumeLessonFragmentTest { ) } + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testResumeLessonFragment_extraLargeTextSize_hasCorrectDimension() { + launch(createResumeLessonActivityIntent()).use { + it.onActivity { activity -> + activity.resumeLessonActivityPresenter + .loadResumeLessonFragment(ReadingTextSize.EXTRA_LARGE_TEXT_SIZE) + } + onView(withId(R.id.resume_lesson_chapter_description_text_view)).check( + matches(withFontSize(67F)) + ) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testResumeLessonFragment_largeTextSize_hasCorrectDimension() { + launch(createResumeLessonActivityIntent()).use { + it.onActivity { activity -> + activity.resumeLessonActivityPresenter + .loadResumeLessonFragment(ReadingTextSize.LARGE_TEXT_SIZE) + } + onView(withId(R.id.resume_lesson_chapter_description_text_view)).check( + matches(withFontSize(58F)) + ) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testResumeLessonFragment_mediumTextSize_hasCorrectDimension() { + launch(createResumeLessonActivityIntent()).use { + it.onActivity { activity -> + activity.resumeLessonActivityPresenter + .loadResumeLessonFragment(ReadingTextSize.MEDIUM_TEXT_SIZE) + } + onView(withId(R.id.resume_lesson_chapter_description_text_view)).check( + matches(withFontSize(48F)) + ) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testResumeLessonFragment_smallTextSize_hasCorrectDimension() { + launch(createResumeLessonActivityIntent()).use { + it.onActivity { activity -> + activity.resumeLessonActivityPresenter + .loadResumeLessonFragment(ReadingTextSize.SMALL_TEXT_SIZE) + } + onView(withId(R.id.resume_lesson_chapter_description_text_view)).check( + matches(withFontSize(38F)) + ) + } + } + // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. @Singleton @Component( diff --git a/app/src/sharedTest/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityTest.kt index c2aacc1d4b0..1225e4aa29a 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityTest.kt @@ -63,6 +63,7 @@ import org.oppia.android.app.devoptions.DeveloperOptionsModule import org.oppia.android.app.devoptions.DeveloperOptionsStarterModule import org.oppia.android.app.model.OppiaLanguage import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.ScreenName import org.oppia.android.app.model.WrittenTranslationLanguageSelection import org.oppia.android.app.player.state.itemviewmodel.SplitScreenInteractionModule @@ -77,6 +78,7 @@ import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.atPositi import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.hasItemCount import org.oppia.android.app.shim.ViewBindingShimModule import org.oppia.android.app.translation.testing.ActivityRecreatorTestModule +import org.oppia.android.app.utility.FontSizeMatcher import org.oppia.android.app.utility.OrientationChangeAction.Companion.orientationLandscape import org.oppia.android.data.backends.gae.NetworkConfigProdModule import org.oppia.android.data.backends.gae.NetworkModule @@ -556,6 +558,73 @@ class QuestionPlayerActivityTest { } } + @Test + @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testQuestionPlayer_extraLargeTextSize_hasCorrectDimension() { + launchForSkillList(SKILL_ID_LIST).use { + it.onActivity { activity -> + activity.questionPlayerActivityPresenter + .loadFragments(ReadingTextSize.EXTRA_LARGE_TEXT_SIZE) + } + verifyFontSizeMatches(67F) + } + } + + @Test + @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testQuestionPlayer_largeTextSize_hasCorrectDimension() { + launchForSkillList(SKILL_ID_LIST).use { + it.onActivity { activity -> + activity.questionPlayerActivityPresenter + .loadFragments(ReadingTextSize.LARGE_TEXT_SIZE) + } + verifyFontSizeMatches(58F) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testQuestionPlayer_mediumTextSize_hasCorrectDimension() { + launchForSkillList(SKILL_ID_LIST).use { + it.onActivity { activity -> + activity.questionPlayerActivityPresenter + .loadFragments(ReadingTextSize.MEDIUM_TEXT_SIZE) + } + verifyFontSizeMatches(48F) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testQuestionPlayer_smallTextSize_hasCorrectDimension() { + launchForSkillList(SKILL_ID_LIST).use { + it.onActivity { activity -> + activity.questionPlayerActivityPresenter + .loadFragments(ReadingTextSize.SMALL_TEXT_SIZE) + } + verifyFontSizeMatches(38F) + } + } + + private fun verifyFontSizeMatches(fontSize: Float) { + scrollToViewType(CONTENT) + onView( + atPositionOnView( + recyclerViewId = R.id.question_recycler_view, + position = 0, + targetViewId = R.id.content_text_view + ) + ).check( + matches( + FontSizeMatcher.withFontSize( + fontSize = fontSize + ) + ) + ) + } + private fun setUpTestApplicationComponent() { ApplicationProvider.getApplicationContext().inject(this) } diff --git a/app/src/sharedTest/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentTest.kt b/app/src/sharedTest/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentTest.kt index d70c6c13791..2ace43dd119 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentTest.kt @@ -59,6 +59,7 @@ import org.oppia.android.app.model.HelpActivityParams import org.oppia.android.app.model.OppiaLanguage import org.oppia.android.app.model.OptionsActivityParams import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.model.RevisionCardActivityParams import org.oppia.android.app.model.WrittenTranslationLanguageSelection import org.oppia.android.app.options.OptionsActivity @@ -67,6 +68,7 @@ import org.oppia.android.app.player.state.itemviewmodel.SplitScreenInteractionMo import org.oppia.android.app.shim.ViewBindingShimModule import org.oppia.android.app.topic.revisioncard.RevisionCardActivity.Companion.createRevisionCardActivityIntent import org.oppia.android.app.translation.testing.ActivityRecreatorTestModule +import org.oppia.android.app.utility.FontSizeMatcher.Companion.withFontSize import org.oppia.android.app.utility.OrientationChangeAction.Companion.orientationLandscape import org.oppia.android.data.backends.gae.NetworkConfigProdModule import org.oppia.android.data.backends.gae.NetworkModule @@ -232,6 +234,96 @@ class RevisionCardFragmentTest { } } + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testRevisionCard_extraLargeTextSize_hasCorrectDimension() { + launch( + createRevisionCardActivityIntent( + context, + profileId.internalId, + FRACTIONS_TOPIC_ID, + subtopicId = 2, + FRACTIONS_SUBTOPIC_LIST_SIZE + ) + ).use { + it.onActivity { activity -> + activity.revisionCardActivityPresenter + .loadRevisionCardFragment(ReadingTextSize.EXTRA_LARGE_TEXT_SIZE) + } + onView(withId(R.id.revision_card_explanation_text)).check( + matches(withFontSize(67F)) + ) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testRevisionCard_largeTextSize_hasCorrectDimension() { + launch( + createRevisionCardActivityIntent( + context, + profileId.internalId, + FRACTIONS_TOPIC_ID, + subtopicId = 2, + FRACTIONS_SUBTOPIC_LIST_SIZE + ) + ).use { + it.onActivity { activity -> + activity.revisionCardActivityPresenter + .loadRevisionCardFragment(ReadingTextSize.LARGE_TEXT_SIZE) + } + onView(withId(R.id.revision_card_explanation_text)).check( + matches(withFontSize(58F)) + ) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testRevisionCard_mediumTextSize_hasCorrectDimension() { + launch( + createRevisionCardActivityIntent( + context, + profileId.internalId, + FRACTIONS_TOPIC_ID, + subtopicId = 2, + FRACTIONS_SUBTOPIC_LIST_SIZE + ) + ).use { + it.onActivity { activity -> + activity.revisionCardActivityPresenter + .loadRevisionCardFragment( + ReadingTextSize.MEDIUM_TEXT_SIZE + ) + } + onView(withId(R.id.revision_card_explanation_text)).check( + matches(withFontSize(48F)) + ) + } + } + + @Test @Config(qualifiers = "w360dp-h640dp-xxhdpi") + @RunOn(TestPlatform.ROBOLECTRIC) + fun testRevisionCard_smallTextSize_hasCorrectDimension() { + launch( + createRevisionCardActivityIntent( + context, + profileId.internalId, + FRACTIONS_TOPIC_ID, + subtopicId = 2, + FRACTIONS_SUBTOPIC_LIST_SIZE + ) + ).use { + it.onActivity { activity -> + activity.revisionCardActivityPresenter + .loadRevisionCardFragment(ReadingTextSize.SMALL_TEXT_SIZE) + } + onView(withId(R.id.revision_card_explanation_text)).check( + matches(withFontSize(38F)) + ) + } + } + @Test fun testRevisionCardTest_initialise_openBottomSheet_showsBottomSheet() { launch( diff --git a/model/src/main/proto/arguments.proto b/model/src/main/proto/arguments.proto index 2aca58d5e01..e42bbf09266 100644 --- a/model/src/main/proto/arguments.proto +++ b/model/src/main/proto/arguments.proto @@ -206,6 +206,9 @@ message ResumeLessonFragmentArguments { // The checkpoint that may be used to resume the exploration play session. ExplorationCheckpoint checkpoint = 6; + + // The text size at which content in the resume lesson should be rendered. + ReadingTextSize reading_text_size = 7; } // Params required when creating a new ReadingTextSizeActivity. @@ -328,6 +331,15 @@ message SurveyActivityParams { string exploration_id = 3; } +// Arguments required when creating a QuestionPlayerFragment. +message QuestionPlayerFragmentArguments{ + // The ID of current profile. + ProfileId profile_id = 1; + + // The ReadingTextSize previously selected by the user (upon opening the fragment). + ReadingTextSize reading_text_size = 2; +} + // Represents the parameters needed to create TopicActivity. message TopicActivityParams { // The ID of the topic to be loaded. @@ -801,6 +813,9 @@ message RevisionCardFragmentArguments { // The sub topic list size. int32 subtopic_list_size = 3; + + // The text size at which content in the resume lesson should be rendered. + ReadingTextSize reading_text_size = 7; } // Represents the parameters needed to create TestFontScaleConfigurationUtilActivity. diff --git a/scripts/assets/kdoc_validity_exemptions.textproto b/scripts/assets/kdoc_validity_exemptions.textproto index a41ece30e6e..c82f70cd255 100644 --- a/scripts/assets/kdoc_validity_exemptions.textproto +++ b/scripts/assets/kdoc_validity_exemptions.textproto @@ -250,7 +250,6 @@ exempted_file_path: "app/src/main/java/org/oppia/android/app/topic/revision/Topi exempted_file_path: "app/src/main/java/org/oppia/android/app/topic/revision/TopicRevisionViewModel.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragment.kt" -exempted_file_path: "app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardFragmentPresenter.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivityPresenter.kt"