Skip to content

Commit

Permalink
Fix #2953: Add support for concept cards in revision cards (#3017)
Browse files Browse the repository at this point in the history
* Add support for loading proto versions of lessons.

* Upgrade Espresso versions to work around build issues.

Note that I can't actually verify Espresso tests are working with these
versions since the Bazel project doesn't yet have Espresso tests set up.

* Lint fix post-copying from #2927.

* Fix Glide in Bazel.

* Fix concept card name escaping.

Also, refactor HtmlParser to better support/handling different tag types
& prepare for LaTeX SVG image support.

* Copy over test fix from #2927.

* Add support for rendering LaTeX via SVGs.

Much of this is copied from #2927 so see that PR's commit history & the
PR corresponding to this commit for specific details.

* Ensure all thumbnails are opaque.

* Fix interactions to support new localization.

This fixes answer classification, submission, and viewing for drag &
drop, item selection, multiple choice, and text input interactions per
changes in the states structure to support lesson localization.

* Fix blurring for SVGs.

SVGs did not previous support blurring, & this change introduces a way
to leverage the existing bitmap blurrer to introduce blurring
functionality in a way that's consistent with bitmap thumbnails.

* Lint fixes post copying from #2927.

* Remove image loading annotation.

This will be added in a later branch in the chain.

* Add caching module to needed test suites.

* Re-add image load annotation for this PR.

* Add support for hiding the questions player.

* Add missing dep from #2927 to fix build.

* Add support for importing text protos as assets.

This actually provides Bazel-only support for converting text protos to
binary and including those as assets so that we can avoid checking in
binary protos to the codebase.

* Add gitignore for Android Studio Bazel plugin output.

* Import textproto versions of existing dev assets.

This imports local conversions of all existing dev assets as text proto
leveraging the Bazel-only conversion system to convert these to binary
protos and include them as assets.

This is a necessary step to both eventually replace JSON assets with
text proto, and to test that the new proto loading pipeline is working
as designed.

* Undo Espresso version change since it breaks Bazel tests.

* Fix tests.

Various attempts to fix existing tests + move some of the domain tests
over to actually using proto when running with Bazel.

App module tests are hanging currently for unknown reasons (only in
Bazel).

* Use correct Espresso core.

3.1.0 causes tests to hang indefinitely when run with Bazel.

* Add support for concept cards in revision cards.

* Move coroutine dispatchers.

This moves the coroutine dispatchers to a new threading subpackage. It
also simplifies the TestCoroutineDispatcher interface & implementations
(which required moving runUntilIdle to CoroutineExecutorServiceTest).

The test coroutine annotations were also moved to their own files.

* Refactor testing utilities build graph.

This introduces new Bazel libraries for:
- Test dispatchers
- Fake system/Oppia clocks
- Robolectric dependencies

* Introduce dedicated test for TestCoroutineDispatcher.

This also fixes some threading issues in the dispatcher, and clarifies
some of its API that was previously unclear (and can lead to subtle race
conditions).

* Add tests for TestCoroutineDispatcher.

This required a bunch of refactoring, adding the first examples of
dedicated Bazel test build files, and introducing a new test pattern for
sharing code between different implementations. Further, it refined the
API for TesCoroutineDispatcher & fixed some issues in the
implementations (especially Robolectric).

Tests verified as non-flaky in Robolectric across 1000 runs, and 0.2%
flaky across 1000 runs for Espresso (though that may be fixed; waiting
on a follow-up run to confirm stability).

* Workaround ktlint semicolon issue.

* Lint fixes.

* Fix test post-merge.

* Move CoroutineDispatcher to be part of threading.

* Lint fixes.

* Undo version upgrade.

* Fix broken tests.

* Lint fixes.

* Add a bit more proto loading test coverage.

* Comment fix.

* Lint fixes.

* Address earlier TODO.

* Post-merge restructure.

* Post-merge fixes.

This removes unneeded dependencies from PersistentCacheStore, including
Glide.

* Add tests for new tag handlers.

Also, add tests for HtmlParser, and clean up some existing tests.

* Fix broken test build.

* Post-merge lint fixes.

* Lint fixes.

* Address reviewer comment.

* Post-merge fix.

* Address pre-merge TODO.

* Disable local image loading.

Also, add specific LaTeX line in the first fractions interaction so that
the new SVG support can be tested.

* Fix typo.

* Docs + tests.

This adds more documentation & context for code added before without it.
It also adds a bunch of new testing coverage for changes. The tests are
particularly around the html part of the LaTeX loading pipeline, but not
the image parts.

More of both will be needed specifically for the image loading pipeline
changes.

* Docs + tests + refactor.

This adds documentation for all remaining components introduced in #2981,
adds some testing for UrlImageParser, and cleans up the image loading
pipeline to be a bit simpler & cleaner (though this will probably break
down-stream PRs relying on image transformations).

* Lint fixes.

* Fix lint failure & re-enable assets.

* Clean up + tests.

Add tests where reasonable given current testing limitations and
developing time availability, and remove some dead code. Add new testing
utility (GenericViewMatchers) + corresponding Bazel package.

* Consolidate testing module view matchers.

This moves two other view matchers that are part of the testing module
into the new Espresso package.

* Lint fixes.

* Post-merge fixes + docs.

Add TODOs for tests that can't easily be added. Fill in missing
documentation. Fix post-merge issues to ensure SVGs can actually be
blurred (will be verified after this commit).

* Add tests for structural changes.

Revamps StateFragmentTest to include a bunch of new interaction tests to
verify that the new structural changes are correct. These discovered
issues with the old asset converter that needed to be fixed, and new
textproto changes needed to be pulled in.

Removed a few now-unused (or should be unused) asset files.
ExplorationProgressControllerTest is now broken and has to be almost
entirely rewritten to support different explorations. The previous ones
couldn't reasonably be migrated without lots of manual work, so we
abandoned them.

* Rename test (& fix it).

Relevant fixes will be coming in a later commit. This is just committing
the file move.

* Fix/update json assets.

This includes fixes for existing content in textproto files, too, where
the previous conversion script had issues.

Assets that will no longer be included are removed (due to being too
hard to migrate).

The codebase will be broken at this point--thorough test changes are
needed, first.

* Fix a LOT of tests that break due to changes.

Fundamentally, this:
1. Migrates existing structural changes in tests for item selection,
text input, and drag and drop.
2. Introduces proto loading (when run on Bazel) for a few more tests,
including some UI tests.
3. Updates test suites to no longer depend on explorations that weren't
carried over in this change.
4. Cleans up a bunch of existing tests/line wrapping issues and other
things.

* Import structurally updates questions.

This includes proto questions even though they can't yet be imported.
Some tests needed adjustments due to fixes in the questions themselves.

* Fix post-merge test build failures.

* Add test for when practice tab is disabled.

* Fix new module location per reviewer comment.

* Add concept card tests for revision cards.

This required some small updates to one of the revision card test assets
(for both JSON & textproto variants).

* Enable proto loading for revision card testing.

* Post-merge lint fixes.

* Address reviewer comments.

Fix case sensitive checks for text input, and some minor cleanups in
drag & drop interaction view model.

* Fix broken Gradle test.

Another structural change: 'translation' is now the correct reference
for written translations rather than 'html'.

* Lint fixes.

* Lint fixes.

* Address reviewer comment.

Adds test with config change.

* Address reviewer comment.

Move CONCEPT_CARD_DIALOG_FRAGMENT_TEST to ConceptCardFragment's
Companion object.

* Fix broken test.

* Lint fixes.
  • Loading branch information
BenHenning authored Apr 24, 2021
1 parent 1e4c24c commit 69e1b7e
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.oppia.android.app.player.state.ConfettiConfig.MEDIUM_CONFETTI_BURST
import org.oppia.android.app.player.state.ConfettiConfig.MINI_CONFETTI_BURST
import org.oppia.android.app.player.state.listener.RouteToHintsAndSolutionListener
import org.oppia.android.app.player.stopplaying.StopStatePlayingSessionListener
import org.oppia.android.app.topic.conceptcard.ConceptCardFragment.Companion.CONCEPT_CARD_DIALOG_FRAGMENT_TAG
import org.oppia.android.app.utility.SplitScreenManager
import org.oppia.android.app.viewmodel.ViewModelProvider
import org.oppia.android.databinding.StateFragmentBinding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import org.oppia.android.app.player.state.listener.ShowHintAvailabilityListener
import org.oppia.android.app.player.state.listener.SubmitNavigationButtonListener
import org.oppia.android.app.recyclerview.BindableAdapter
import org.oppia.android.app.topic.conceptcard.ConceptCardFragment
import org.oppia.android.app.topic.conceptcard.ConceptCardFragment.Companion.CONCEPT_CARD_DIALOG_FRAGMENT_TAG
import org.oppia.android.app.utility.LifecycleSafeTimerFactory
import org.oppia.android.databinding.ContentItemBinding
import org.oppia.android.databinding.ContinueInteractionItemBinding
Expand Down Expand Up @@ -94,9 +95,6 @@ import javax.inject.Inject

private typealias AudioUiManagerRetriever = () -> AudioUiManager?

/** The fragment tag corresponding to the concept card dialog fragment. */
const val CONCEPT_CARD_DIALOG_FRAGMENT_TAG = "CONCEPT_CARD_FRAGMENT"

private const val CONGRATULATIONS_TEXT_VIEW_FADE_MILLIS: Long = 600
private const val CONGRATULATIONS_TEXT_VIEW_VISIBLE_MILLIS: Long = 800

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ private const val KEY_SKILL_ID = "SKILL_ID"
class ConceptCardFragment : InjectableDialogFragment() {

companion object {
/** The fragment tag corresponding to the concept card dialog fragment. */
const val CONCEPT_CARD_DIALOG_FRAGMENT_TAG = "CONCEPT_CARD_FRAGMENT"

/**
* Creates a new instance of a DialogFragment to display content
* @param skillId Used in TopicController to get correct concept card data.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import org.oppia.android.app.model.Hint
import org.oppia.android.app.model.Solution
import org.oppia.android.app.model.State
import org.oppia.android.app.model.UserAnswer
import org.oppia.android.app.player.state.CONCEPT_CARD_DIALOG_FRAGMENT_TAG
import org.oppia.android.app.player.state.ConfettiConfig.MINI_CONFETTI_BURST
import org.oppia.android.app.player.state.StatePlayerRecyclerViewAssembler
import org.oppia.android.app.player.state.listener.RouteToHintsAndSolutionListener
import org.oppia.android.app.player.stopplaying.RestartPlayingSessionListener
import org.oppia.android.app.player.stopplaying.StopStatePlayingSessionListener
import org.oppia.android.app.topic.conceptcard.ConceptCardFragment.Companion.CONCEPT_CARD_DIALOG_FRAGMENT_TAG
import org.oppia.android.app.utility.SplitScreenManager
import org.oppia.android.app.viewmodel.ViewModelProvider
import org.oppia.android.databinding.QuestionPlayerFragmentBinding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import android.view.Menu
import android.view.MenuItem
import org.oppia.android.R
import org.oppia.android.app.activity.InjectableAppCompatActivity
import org.oppia.android.app.topic.conceptcard.ConceptCardListener
import javax.inject.Inject

/** Activity for revision card. */
class RevisionCardActivity : InjectableAppCompatActivity(), ReturnToTopicClickListener {
class RevisionCardActivity :
InjectableAppCompatActivity(), ReturnToTopicClickListener, ConceptCardListener {

@Inject
lateinit var revisionCardActivityPresenter: RevisionCardActivityPresenter
Expand Down Expand Up @@ -60,4 +62,8 @@ class RevisionCardActivity : InjectableAppCompatActivity(), ReturnToTopicClickLi
override fun onReturnToTopicClicked() {
onBackPressed()
}

override fun dismissConceptCard() {
revisionCardActivityPresenter.dismissConceptCard()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ class RevisionCardActivityPresenter @Inject constructor(
}
}

/** Dismisses the concept card fragment if it's currently active in this activity. */
fun dismissConceptCard() = getReviewCardFragment()?.dismissConceptCard()

private fun subscribeToSubtopicTitle() {
subtopicLiveData.observe(
activity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ class RevisionCardFragment : InjectableDialogFragment() {
val subtopicId = args.getInt(SUBTOPIC_ID_ARGUMENT_KEY, -1)
return revisionCardFragmentPresenter.handleCreateView(inflater, container, topicId, subtopicId)
}

/** Dismisses the concept card fragment if it's currently active in this fragment. */
fun dismissConceptCard() = revisionCardFragmentPresenter.dismissConceptCard()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import org.oppia.android.app.fragment.FragmentScope
import org.oppia.android.app.model.EventLog
import org.oppia.android.app.topic.conceptcard.ConceptCardFragment
import org.oppia.android.app.topic.conceptcard.ConceptCardFragment.Companion.CONCEPT_CARD_DIALOG_FRAGMENT_TAG
import org.oppia.android.app.viewmodel.ViewModelProvider
import org.oppia.android.databinding.RevisionCardFragmentBinding
import org.oppia.android.domain.oppialogger.OppiaLogger
Expand All @@ -26,7 +28,7 @@ class RevisionCardFragmentPresenter @Inject constructor(
@DefaultResourceBucketName private val resourceBucketName: String,
@TopicHtmlParserEntityType private val entityType: String,
private val viewModelProvider: ViewModelProvider<RevisionCardViewModel>
) {
) : HtmlParser.CustomOppiaTagActionListener {

fun handleCreateView(
inflater: LayoutInflater,
Expand Down Expand Up @@ -55,14 +57,26 @@ class RevisionCardFragmentPresenter @Inject constructor(
fragment,
Observer {
view.text = htmlParserFactory.create(
resourceBucketName, entityType, topicId, imageCenterAlign = true
).parseOppiaHtml(it.pageContents.html, view)
resourceBucketName, entityType, topicId, imageCenterAlign = true,
customOppiaTagActionListener = this
).parseOppiaHtml(
it.pageContents.html, view, supportsLinks = true, supportsConceptCards = true
)
}
)

return binding.root
}

/** Dismisses the concept card fragment if it's currently active in this fragment. */
fun dismissConceptCard() {
fragment.childFragmentManager.findFragmentByTag(
CONCEPT_CARD_DIALOG_FRAGMENT_TAG
)?.let { dialogFragment ->
fragment.childFragmentManager.beginTransaction().remove(dialogFragment).commitNow()
}
}

private fun getReviewCardViewModel(): RevisionCardViewModel {
return viewModelProvider.getForFragment(fragment, RevisionCardViewModel::class.java)
}
Expand All @@ -74,4 +88,10 @@ class RevisionCardFragmentPresenter @Inject constructor(
oppiaLogger.createRevisionCardContext(topicId, subTopicId)
)
}

override fun onConceptCardLinkClicked(view: View, skillId: String) {
ConceptCardFragment
.newInstance(skillId)
.showNow(fragment.childFragmentManager, CONCEPT_CARD_DIALOG_FRAGMENT_TAG)
}
}
Loading

0 comments on commit 69e1b7e

Please sign in to comment.