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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,31 @@ import android.app.Application
import android.content.Context
import dagger.Binds
import dagger.Module
import dagger.Provides
import org.oppia.android.app.R
import org.oppia.android.app.activity.ActivityComponentImpl
import org.oppia.android.util.parser.html.WorkedExampleAnswerLabelStringId
import org.oppia.android.util.parser.html.WorkedExampleQuestionLabelStringId

/** Provides core infrastructure needed to support all other dependencies in the app. */
@Module(subcomponents = [ActivityComponentImpl::class])
interface ApplicationModule {
@Binds
fun provideContext(application: Application): Context

// Dagger doesn't support mixing binds & provides methods, so string resource ID providers are
// defined in a companion module.
@Module
companion object {
@Provides
@WorkedExampleQuestionLabelStringId
@JvmStatic
fun provideWorkedExampleQuestionLabelStringId(): Int =
R.string.worked_example_question_label

@Provides
@WorkedExampleAnswerLabelStringId
@JvmStatic
fun provideWorkedExampleAnswerLabelStringId(): Int = R.string.worked_example_answer_label
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ kt_android_library(
deps = [
"//app",
"//domain/src/main/java/org/oppia/android/domain/oppialogger:startup_listener",
"//utility/src/main/java/org/oppia/android/util/parser/html:html_parser",
],
)

Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
<string name="concept_card_one_button_text">Concept Card 1</string>
<string name="concept_card_two_button_text">Concept Card 2</string>
<string name="revision_card_toolbar_title">Study Guide</string>
<string name="worked_example_question_label">Question:</string>
<string name="worked_example_answer_label">Answer:</string>
<string name="unsaved_exploration_dialog_title">Leave to Topic Page?</string>
<string name="unsaved_exploration_dialog_description">Your progress will not be saved.</string>
<string name="unsaved_exploration_dialog_leave_button">Leave</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class FeatureFlagsFragmentTest {

// Note to developers: if you add/remove a feature flag, please update the expected count.
onView(withId(R.id.feature_flags_recycler_view))
.check(RecyclerViewMatcher.hasItemCount(count = 20))
.check(RecyclerViewMatcher.hasItemCount(count = 21))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ class StudyGuideFragmentTest {
@Before
fun setUp() {
TestPlatformParameterModule.forceLoadLessonProtosFromAssets(true)
TestPlatformParameterModule.forceEnableWorkedExamples(true)
ApplicationProvider.getApplicationContext<TestApplication>().inject(this)
testCoroutineDispatchers.registerIdlingResource()
}
Expand Down Expand Up @@ -274,6 +275,29 @@ class StudyGuideFragmentTest {
}
}

@Test
fun testStudyGuide_testTopicSubtopic1_secondSectionShowsOnlyValidWorkedExample() {
runWithLaunchedActivityAndAddedFragment(
TEST_TOPIC_ID_0,
subtopicIndex = 1,
subtopicListSize = 1
) {
val workedExampleContent = atPositionOnView(
recyclerViewId = R.id.study_guide_section_recycler_view,
position = 3,
targetViewId = R.id.study_guide_section_content_text
)
onView(workedExampleContent)
.check(matches(withText(containsString("Question:\nWhat is one half as a fraction?"))))
onView(workedExampleContent)
.check(matches(withText(containsString("Answer:\nOne half is 1/2."))))
onView(workedExampleContent)
.check(matches(not(withText(containsString("This answer should be ignored.")))))
onView(workedExampleContent)
.check(matches(not(withText(containsString("This question should be ignored.")))))
}
}

@Test
fun testStudyGuide_clickConceptCardLinkText_opensConceptCard() {
runWithLaunchedActivityAndAddedFragment(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,8 @@ feature_flag_definition {
remote_server_name: "android_enable_study_guides"
default_is_enabled: false
}
feature_flag_definition {
id: WORKED_EXAMPLES
remote_server_name: "android_enable_worked_examples"
default_is_enabled: false
}
2 changes: 1 addition & 1 deletion domain/src/main/assets/dev/test_topic_id_0_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
},
"content": {
"content_id": "section_content_3",
"html": "<p>This section reviews a related skill: <oppia-noninteractive-skillreview skill_id-with-value=\"&amp;quot;test_skill_id_0&amp;quot;\" text-with-value=\"&amp;quot;test_skill_id_0 concept card&amp;quot;\"></oppia-noninteractive-skillreview>.</p>"
"html": "<p>This section reviews a related skill: <oppia-noninteractive-skillreview skill_id-with-value=\"&amp;quot;test_skill_id_0&amp;quot;\" text-with-value=\"&amp;quot;test_skill_id_0 concept card&amp;quot;\"></oppia-noninteractive-skillreview>.</p><p>Worked examples:</p><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;&amp;lt;strong&amp;gt;What is one half as a fraction?&amp;lt;/strong&amp;gt;&amp;quot;\" answer-with-value=\"&amp;quot;&amp;lt;em&amp;gt;One half is 1/2.&amp;lt;/em&amp;gt;&amp;quot;\"></oppia-noninteractive-workedexample><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;&amp;quot;\" answer-with-value=\"&amp;quot;This answer should be ignored.&amp;quot;\"></oppia-noninteractive-workedexample><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;This question should be ignored.&amp;quot;\" answer-with-value=\"&amp;quot;&amp;quot;\"></oppia-noninteractive-workedexample><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;Malformed question\" answer-with-value=\"&amp;quot;This answer should be ignored.&amp;quot;\"></oppia-noninteractive-workedexample>"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion domain/src/main/assets/dev/test_topic_id_0_1.textproto
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ sections {
content_id: "section_heading_2"
}
content {
html: "<p>This section reviews a related skill: <oppia-noninteractive-skillreview skill_id-with-value=\"&amp;quot;test_skill_id_0&amp;quot;\" text-with-value=\"&amp;quot;test_skill_id_0 concept card&amp;quot;\"></oppia-noninteractive-skillreview>.</p>"
html: "<p>This section reviews a related skill: <oppia-noninteractive-skillreview skill_id-with-value=\"&amp;quot;test_skill_id_0&amp;quot;\" text-with-value=\"&amp;quot;test_skill_id_0 concept card&amp;quot;\"></oppia-noninteractive-skillreview>.</p><p>Worked examples:</p><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;&amp;lt;strong&amp;gt;What is one half as a fraction?&amp;lt;/strong&amp;gt;&amp;quot;\" answer-with-value=\"&amp;quot;&amp;lt;em&amp;gt;One half is 1/2.&amp;lt;/em&amp;gt;&amp;quot;\"></oppia-noninteractive-workedexample><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;&amp;quot;\" answer-with-value=\"&amp;quot;This answer should be ignored.&amp;quot;\"></oppia-noninteractive-workedexample><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;This question should be ignored.&amp;quot;\" answer-with-value=\"&amp;quot;&amp;quot;\"></oppia-noninteractive-workedexample><oppia-noninteractive-workedexample question-with-value=\"&amp;quot;Malformed question\" answer-with-value=\"&amp;quot;This answer should be ignored.&amp;quot;\"></oppia-noninteractive-workedexample>"
content_id: "section_content_3"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import org.oppia.android.util.platformparameter.EnableSpotlightUi
import org.oppia.android.util.platformparameter.EnableStudyGuides
import org.oppia.android.util.platformparameter.EnableTopicInfoTab
import org.oppia.android.util.platformparameter.EnableTopicPracticeTab
import org.oppia.android.util.platformparameter.EnableWorkedExamples
import org.oppia.android.util.platformparameter.LoadImagesFromAssets
import org.oppia.android.util.platformparameter.LoadLessonProtosFromAssets
import org.oppia.android.util.platformparameter.PlatformParameterValue
Expand Down Expand Up @@ -137,6 +138,11 @@ class FeatureFlagBindingModule {
fun provideEnableStudyGuides(processState: PlatformParameterProcessState) =
processState.retrieveFeatureFlag(FeatureFlagId.STUDY_GUIDES)

@Provides
@EnableWorkedExamples
fun provideEnableWorkedExamples(processState: PlatformParameterProcessState) =
processState.retrieveFeatureFlag(FeatureFlagId.WORKED_EXAMPLES)

private companion object {
private fun PlatformParameterProcessState.retrieveFeatureFlag(
featureFlagId: FeatureFlagId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.oppia.android.util.platformparameter.EnableSpotlightUi
import org.oppia.android.util.platformparameter.EnableStudyGuides
import org.oppia.android.util.platformparameter.EnableTopicInfoTab
import org.oppia.android.util.platformparameter.EnableTopicPracticeTab
import org.oppia.android.util.platformparameter.EnableWorkedExamples
import org.oppia.android.util.platformparameter.PlatformParameterValue

// TODO(#5835): Remove this module.
Expand Down Expand Up @@ -171,4 +172,12 @@ interface FeatureFlagsMapBindingModule {
fun bindStudyGuides(
@EnableStudyGuides param: PlatformParameterValue<Boolean>
): PlatformParameterValue<Boolean>

@Binds
@IntoMap
@FeatureFlags
@FeatureFlagIdKey(FeatureFlagId.WORKED_EXAMPLES)
fun bindWorkedExamples(
@EnableWorkedExamples param: PlatformParameterValue<Boolean>
): PlatformParameterValue<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class FeatureFlagsLoggerTest {

@Test
fun testLogFeatureFlags_correctNumberOfFeatureFlagsIsLogged() {
val expectedFeatureFlagCount = 18
val expectedFeatureFlagCount = 19

featureFlagsLogger.logAllFeatureFlags(TEST_SESSION_ID)
testCoroutineDispatchers.runCurrent()
Expand Down Expand Up @@ -171,6 +171,7 @@ class FeatureFlagsLoggerTest {
@Iteration("edge_to_edge", "index=15", "flagId=EDGE_TO_EDGE")
@Iteration("lesson_progress_visualization", "index=16", "flagId=LESSON_PROGRESS_VISUALIZATION")
@Iteration("study_guides", "index=17", "flagId=STUDY_GUIDES")
@Iteration("worked_examples", "index=18", "flagId=WORKED_EXAMPLES")
fun testLogFeatureFlags_allFeatureFlagIdsAreLogged() {
featureFlagsLogger.logAllFeatureFlags(TEST_SESSION_ID)

Expand Down
3 changes: 3 additions & 0 deletions model/src/main/proto/platform_parameter.proto
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ enum FeatureFlagId {
// Corresponds to a feature that enables study guides, an enhanced version of revision cards that
// introduces multiple sections with section headers.
STUDY_GUIDES = 23;

// Corresponds to whether worked examples should be rendered in rich-text content.
WORKED_EXAMPLES = 24;
}

// Corresponds to a compile-time definition of a platform parameter which is a mechanism by which to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.oppia.android.app.model.FeatureFlagId.SPOTLIGHT_UI
import org.oppia.android.app.model.FeatureFlagId.STUDY_GUIDES
import org.oppia.android.app.model.FeatureFlagId.TOPIC_INFO_TAB
import org.oppia.android.app.model.FeatureFlagId.TOPIC_PRACTICE_TAB
import org.oppia.android.app.model.FeatureFlagId.WORKED_EXAMPLES
import org.oppia.android.domain.platformparameter.FeatureFlagBindingModule
import org.oppia.android.domain.platformparameter.FeatureFlagsMapBindingModule
import org.oppia.android.domain.platformparameter.PlatformParameterBindingModule
Expand Down Expand Up @@ -175,6 +176,10 @@ class TestPlatformParameterModule {
TestPlatformParameterConfigRetriever.setFlagOverride(STUDY_GUIDES, value)
}

fun forceEnableWorkedExamples(value: Boolean) {
TestPlatformParameterConfigRetriever.setFlagOverride(WORKED_EXAMPLES, value)
}

fun reset() {
TestPlatformParameterConfigRetriever.reset()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,20 @@ class StudyGuideTestHelper @Inject constructor() {
"<oppia-noninteractive-skillreview " +
"skill_id-with-value=\"&amp;quot;test_skill_id_0&amp;quot;\" " +
"text-with-value=\"&amp;quot;test_skill_id_0 concept card&amp;quot;\">" +
"</oppia-noninteractive-skillreview>.</p>"
"</oppia-noninteractive-skillreview>.</p><p>Worked examples:</p>" +
"<oppia-noninteractive-workedexample question-with-value=\"&amp;quot;" +
"&amp;lt;strong&amp;gt;What is one half as a fraction?&amp;lt;/strong&amp;gt;" +
"&amp;quot;\" answer-with-value=\"&amp;quot;&amp;lt;em&amp;gt;One half is 1/2." +
"&amp;lt;/em&amp;gt;&amp;quot;\"></oppia-noninteractive-workedexample>" +
"<oppia-noninteractive-workedexample question-with-value=\"&amp;quot;&amp;quot;\" " +
"answer-with-value=\"&amp;quot;This answer should be ignored.&amp;quot;\">" +
"</oppia-noninteractive-workedexample><oppia-noninteractive-workedexample " +
"question-with-value=\"&amp;quot;This question should be ignored.&amp;quot;\" " +
"answer-with-value=\"&amp;quot;&amp;quot;\"></oppia-noninteractive-workedexample>" +
"<oppia-noninteractive-workedexample " +
"question-with-value=\"&amp;quot;Malformed question\" " +
"answer-with-value=\"&amp;quot;This answer should be ignored.&amp;quot;\">" +
"</oppia-noninteractive-workedexample>"
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ kt_android_library(
":tag_handlers",
"//third_party:androidx_core_core-ktx",
"//third_party:javax_inject_javax_inject",
"//utility:resources",
"//utility/src/main/java/org/oppia/android/util/locale:oppia_locale",
"//utility/src/main/java/org/oppia/android/util/logging:console_logger",
"//utility/src/main/java/org/oppia/android/util/parser/image:url_image_parser",
Expand All @@ -30,6 +31,7 @@ kt_android_library(
"LiTagHandler.kt",
"MathTagHandler.kt",
"PolicyPageTagHandler.kt",
"WorkedExampleTagHandler.kt",
],
visibility = ["//utility:__subpackages__"],
deps = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class ConceptCardTagHandler(
openIndex: Int,
closeIndex: Int,
output: Editable,
imageRetriever: CustomHtmlContentHandler.ImageRetriever?
imageRetriever: CustomHtmlContentHandler.ImageRetriever?,
customHtmlParser: CustomHtmlContentHandler.CustomHtmlParser
) {
// Replace the custom tag with a clickable piece of text based on the tag's customizations.
val skillId = attributes.getJsonStringValue(CUSTOM_CONCEPT_CARD_SKILL_ID)
Expand Down Expand Up @@ -58,7 +59,10 @@ class ConceptCardTagHandler(
fun onConceptCardLinkClicked(view: View, skillId: String)
}

override fun getContentDescription(attributes: Attributes): String? {
override fun getContentDescription(
attributes: Attributes,
customHtmlParser: CustomHtmlContentHandler.CustomHtmlParser
): String? {
val skillId = attributes.getJsonStringValue(CUSTOM_CONCEPT_CARD_SKILL_ID)
return if (!skillId.isNullOrBlank()) {
"$skillId concept card"
Expand Down
Loading
Loading