Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #153/#154 : MultipleChoice/ItemSelection Interaction #258

Closed
wants to merge 75 commits into from
Closed
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
453e858
customization_args issues fix
nikitamarysolomanpvt Oct 18, 2019
8130312
nit
nikitamarysolomanpvt Oct 18, 2019
2f378ef
nit
nikitamarysolomanpvt Oct 18, 2019
296e868
nit
nikitamarysolomanpvt Oct 18, 2019
ba0ba3c
nit
nikitamarysolomanpvt Oct 19, 2019
e65da93
Merge branch 'customization-args-fixes' into merge-fix
veena14cs Oct 21, 2019
f227ed5
Update StateFragmentPresenter.kt
veena14cs Oct 21, 2019
e7b7124
added xmls
veena14cs Oct 21, 2019
0e67155
Update RecyclerViewMatcher.kt
veena14cs Oct 21, 2019
4167caf
Update RecyclerViewMatcher.kt
veena14cs Oct 21, 2019
92e6a80
working on interaction
veena14cs Oct 22, 2019
5e27966
added interactions
veena14cs Oct 22, 2019
e5bdc57
working on text case
veena14cs Oct 22, 2019
2de2d66
Merge branch 'content-card' into multiple-single-input-interaction
veena14cs Oct 22, 2019
fb62097
run test case
veena14cs Oct 22, 2019
b588d7c
nit
veena14cs Oct 22, 2019
0008d5a
renamed views.
veena14cs Oct 22, 2019
ffba169
Update InteractionAdapter.kt
veena14cs Oct 22, 2019
7c4e694
Update StateAdapter.kt
veena14cs Oct 22, 2019
b1a0101
java doc comments.
veena14cs Oct 22, 2019
f19829c
Update RecyclerViewMatcher.kt
veena14cs Oct 22, 2019
18d1672
Update AndroidManifest.xml
veena14cs Oct 22, 2019
46aef2d
Update InteractionAdapter.kt
veena14cs Oct 23, 2019
79a2366
Update InteractionAdapter.kt
veena14cs Oct 23, 2019
d0a4aa6
Update InteractionAdapter.kt
veena14cs Oct 23, 2019
99184b2
Update InteractionAdapter.kt
veena14cs Oct 23, 2019
40a1f6a
Update SelectionInteractionViewModel.kt
veena14cs Oct 23, 2019
eab1559
nit
veena14cs Oct 23, 2019
381da01
Update selection_interaction_item.xml
veena14cs Oct 23, 2019
b143f7b
nit
veena14cs Oct 23, 2019
0562b61
Update StateAdapter.kt
veena14cs Oct 23, 2019
7ea8db0
Update StateAdapter.kt
veena14cs Oct 23, 2019
4c92057
Update StateFragmentPresenter.kt
veena14cs Oct 23, 2019
4c38a3d
Delete SelectionContentViewModel.kt
veena14cs Oct 23, 2019
29273ae
Update InteractionAdapter.kt
veena14cs Oct 23, 2019
50bfbdd
Update InteractionAdapter.kt
veena14cs Oct 23, 2019
6b35a81
Update StateAdapter.kt
veena14cs Oct 23, 2019
a08a2d1
Update StateAdapter.kt
veena14cs Oct 23, 2019
5bdd1ba
fixed issues
veena14cs Oct 24, 2019
ebdb637
Fixed issues.
veena14cs Oct 24, 2019
69c91fc
update
veena14cs Oct 24, 2019
90c4635
Merge branch 'content-card' into multiple-single-input-interaction
veena14cs Oct 24, 2019
01ad3a4
Update welcome.json
veena14cs Oct 24, 2019
1dd48a2
Update selection_interaction_item.xml
veena14cs Oct 24, 2019
e566dbb
Update multiple_choice_interaction_items.xml
veena14cs Oct 24, 2019
0d180cb
Update item_selection_interaction_items.xml
veena14cs Oct 24, 2019
ef7117b
update Kdoc
veena14cs Oct 24, 2019
b52e96f
Update InteractionAdapter.kt
veena14cs Oct 24, 2019
d7b130a
Merge branch 'content-card' into multiple-single-input-interaction
veena14cs Oct 25, 2019
e6531b7
Update StateAdapter.kt
veena14cs Oct 25, 2019
92e1216
working on test
veena14cs Oct 25, 2019
a638a08
Merge branch 'content-card' into multiple-single-input-interaction
veena14cs Oct 25, 2019
c3c03cd
add new exploration
veena14cs Oct 25, 2019
03aaa69
adding test id
veena14cs Oct 25, 2019
979ebda
Update InteractionAdapter.kt
veena14cs Oct 25, 2019
04852e9
Update InteractionAdapter.kt
veena14cs Oct 25, 2019
5c48a97
Update InteractionAdapter.kt
veena14cs Oct 25, 2019
2ba69b7
fixes
veena14cs Oct 25, 2019
5e74aaf
updated
veena14cs Oct 25, 2019
3e8dce7
udated kdoc
veena14cs Oct 25, 2019
5e9abab
Update StateAdapter.kt
veena14cs Oct 25, 2019
c0626a5
Update StateAdapter.kt
veena14cs Oct 25, 2019
19740a9
Update StateAdapter.kt
veena14cs Oct 25, 2019
cf55bc4
Update StateFragmentPresenter.kt
veena14cs Oct 25, 2019
d9a4c23
Update StateFragmentPresenter.kt
veena14cs Oct 25, 2019
df1941c
Update StateFragmentPresenter.kt
veena14cs Oct 25, 2019
d6ffa52
Update StateFragmentPresenter.kt
veena14cs Oct 25, 2019
37989b9
Update StateFragmentPresenter.kt
veena14cs Oct 25, 2019
7bb49c2
Update StateFragmentPresenter.kt
veena14cs Oct 25, 2019
21da67f
update
veena14cs Oct 25, 2019
54a37d1
fixes
veena14cs Oct 25, 2019
224b073
Update StateAdapter.kt
veena14cs Oct 25, 2019
72f677b
Update StateSelectionInteractionTest.kt
veena14cs Oct 26, 2019
4fbeef3
created custom selectionview
veena14cs Oct 26, 2019
7772fa2
update
veena14cs Oct 26, 2019
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
17 changes: 17 additions & 0 deletions app/src/main/java/org/oppia/app/home/HomeFragmentPresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.oppia.util.logging.Logger
import javax.inject.Inject

private const val EXPLORATION_ID = TEST_EXPLORATION_ID_5
private const val EXPLORATION_ID_1 = TEST_EXPLORATION_ID_6

/** The controller for [HomeFragment]. */
@FragmentScope
Expand Down Expand Up @@ -52,6 +53,7 @@ class HomeFragmentPresenter @Inject constructor(
}

fun playExplorationButton(v: View) {
explorationDataController.stopPlayingExploration()
Copy link
Contributor Author

@veena14cs veena14cs Oct 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stopPlayingExploration() is added to test with different exploration.

explorationDataController.startPlayingExploration(
EXPLORATION_ID
).observe(fragment, Observer<AsyncResult<Any?>> { result ->
Expand All @@ -65,4 +67,19 @@ class HomeFragmentPresenter @Inject constructor(
}
})
}
fun playExplorationButton_1(v: View) {
explorationDataController.stopPlayingExploration()
explorationDataController.startPlayingExploration(
EXPLORATION_ID_1
).observe(fragment, Observer<AsyncResult<Any?>> { result ->
when {
result.isPending() -> logger.d("HomeFragment", "Loading exploration")
result.isFailure() -> logger.e("HomeFragment", "Failed to load exploration", result.getErrorOrNull()!!)
else -> {
logger.d("HomeFragment", "Successfully loaded exploration")
routeToExplorationListener.routeToExploration(EXPLORATION_ID_1)
}
}
})
}
}
167 changes: 167 additions & 0 deletions app/src/main/java/org/oppia/app/player/state/InteractionAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package org.oppia.app.player.state

import android.text.Spannable
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.databinding.library.baseAdapters.BR
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.item_selection_interaction_items.view.item_selection_contents_text_view
import kotlinx.android.synthetic.main.item_selection_interaction_items.view.checkbox_container
import kotlinx.android.synthetic.main.item_selection_interaction_items.view.item_selection_checkbox
import kotlinx.android.synthetic.main.multiple_choice_interaction_items.view.multiple_choice_content_text_view
import kotlinx.android.synthetic.main.multiple_choice_interaction_items.view.multiple_choice_radio_button
import kotlinx.android.synthetic.main.multiple_choice_interaction_items.view.radio_container
import org.oppia.app.R
import org.oppia.app.databinding.ItemSelectionInteractionItemsBinding
import org.oppia.app.databinding.MultipleChoiceInteractionItemsBinding
import org.oppia.app.model.InteractionObject
import org.oppia.app.model.StringList
import org.oppia.app.player.state.itemviewmodel.CustomizationArgsInteractionViewModel
import org.oppia.app.player.state.itemviewmodel.SelectionContentViewModel
import org.oppia.app.player.state.listener.InteractionAnswerRetriever
import org.oppia.util.parser.HtmlParser

private const val VIEW_TYPE_RADIO_BUTTONS = 1
private const val VIEW_TYPE_CHECKBOXES = 2
private const val INTERACTION_ADAPTER_TAG = "Interaction Adapter"

/**
* Adapter to bind the interactions to the [RecyclerView]. It handles MultipleChoiceInput
* and ItemSelectionInput interaction views.
* */
class InteractionAdapter(
private val htmlParserFactory: HtmlParser.Factory,
private val entityType: String,
private val explorationId: String,
private val itemList: MutableList<SelectionContentViewModel>,
private val customizationArgs: CustomizationArgsInteractionViewModel
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), InteractionAnswerRetriever {
veena14cs marked this conversation as resolved.
Show resolved Hide resolved

private var itemSelectedPosition = -1
private var selectedAnswerIndex = -1
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
private var selectedHtmlStringList = mutableListOf<String>()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
VIEW_TYPE_RADIO_BUTTONS -> {
val inflater = LayoutInflater.from(parent.context)
val binding =
DataBindingUtil.inflate<MultipleChoiceInteractionItemsBinding>(
inflater,
R.layout.multiple_choice_interaction_items,
parent,
/* attachToParent= */ false
)
MultipleChoiceViewHolder(binding)
}
VIEW_TYPE_CHECKBOXES -> {
val inflater = LayoutInflater.from(parent.context)
val binding =
DataBindingUtil.inflate<ItemSelectionInteractionItemsBinding>(
inflater,
R.layout.item_selection_interaction_items,
parent,
/* attachToParent= */ false
)
ItemSelectionViewHolder(binding)
}
else -> throw IllegalArgumentException("Invalid view type")
}
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder.itemViewType) {
VIEW_TYPE_RADIO_BUTTONS -> (holder as MultipleChoiceViewHolder).bind(
itemList[position].htmlContent,
position,
itemSelectedPosition
)
VIEW_TYPE_CHECKBOXES -> (holder as ItemSelectionViewHolder).bind(
itemList[position]
)
}
}

// Determines the appropriate ViewType according to the interaction type.
override fun getItemViewType(position: Int): Int {
return if (customizationArgs.interactionId == "ItemSelectionInput") {
if (customizationArgs.maxAllowableSelectionCount > 1) {
VIEW_TYPE_CHECKBOXES
} else {
VIEW_TYPE_RADIO_BUTTONS
}
} else {
VIEW_TYPE_RADIO_BUTTONS
}
}

override fun getItemCount(): Int {
return itemList.size
}

private inner class ItemSelectionViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
internal fun bind(selectionContentViewModel: SelectionContentViewModel) {
binding.setVariable(BR.htmlContent, selectionContentViewModel.htmlContent)
binding.executePendingBindings()
val htmlResult: Spannable = htmlParserFactory.create(entityType, explorationId).parseOppiaHtml(
selectionContentViewModel.htmlContent,
binding.root.item_selection_contents_text_view
)
binding.root.item_selection_contents_text_view.text = htmlResult
binding.root.item_selection_checkbox.isChecked = selectionContentViewModel.isAnswerSelected
binding.root.checkbox_container.setOnClickListener {
if (binding.root.item_selection_checkbox.isChecked) {
itemList[adapterPosition].isAnswerSelected = false
selectedHtmlStringList.remove(binding.root.item_selection_contents_text_view.text.toString())
} else {
if (selectedHtmlStringList.size != customizationArgs.maxAllowableSelectionCount) {
itemList[adapterPosition].isAnswerSelected = true
selectedHtmlStringList.add(binding.root.item_selection_contents_text_view.text.toString())
} else {
Log.d(
INTERACTION_ADAPTER_TAG,
"You cannot select more than ${customizationArgs.maxAllowableSelectionCount} options"
)
}
}
notifyDataSetChanged()
}
}
}

private inner class MultipleChoiceViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
internal fun bind(rawString: String, position: Int, selectedPosition: Int) {
binding.setVariable(BR.htmlContent, rawString)
binding.executePendingBindings()
val htmlResult: Spannable = htmlParserFactory.create(entityType, explorationId).parseOppiaHtml(
rawString,
binding.root.multiple_choice_content_text_view
)
binding.root.multiple_choice_content_text_view.text = htmlResult
binding.root.multiple_choice_radio_button.isChecked = selectedPosition == position
binding.root.radio_container.setOnClickListener {
itemSelectedPosition = adapterPosition
selectedAnswerIndex = adapterPosition
notifyDataSetChanged()
}
}
}

override fun getPendingAnswer(): InteractionObject {
val interactionObjectBuilder = InteractionObject.newBuilder()
if (customizationArgs.interactionId == "ItemSelectionInput") {
if (selectedHtmlStringList.size >= 0) {
interactionObjectBuilder.setOfHtmlString = StringList.newBuilder().addAllHtml(selectedHtmlStringList).build()
} else {
if (selectedAnswerIndex >= 0) {
interactionObjectBuilder.nonNegativeInt = selectedAnswerIndex
}

}
}
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
return interactionObjectBuilder.build()
}
}
44 changes: 43 additions & 1 deletion app/src/main/java/org/oppia/app/player/state/StateAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import androidx.databinding.library.baseAdapters.BR
import kotlinx.android.synthetic.main.content_item.view.*
import kotlinx.android.synthetic.main.content_item.view.content_text_view
import kotlinx.android.synthetic.main.selection_interaction_item.view.selection_interaction_recyclerview
import kotlinx.android.synthetic.main.state_button_item.view.*
import org.oppia.app.R
import org.oppia.app.databinding.ContentItemBinding
import org.oppia.app.databinding.SelectionInteractionItemBinding
import org.oppia.app.player.state.itemviewmodel.StateButtonViewModel
import org.oppia.app.player.state.listener.ButtonInteractionListener
import org.oppia.app.databinding.StateButtonItemBinding
import org.oppia.app.player.state.itemviewmodel.ContentViewModel
import org.oppia.app.player.state.itemviewmodel.CustomizationArgsInteractionViewModel
import org.oppia.app.player.state.itemviewmodel.SelectionContentViewModel
import org.oppia.util.parser.HtmlParser

@Suppress("unused")
Expand All @@ -26,6 +30,7 @@ private const val VIEW_TYPE_NUMERIC_INPUT_INTERACTION = 3
@Suppress("unused")
private const val VIEW_TYPE_TEXT_INPUT_INTERACTION = 4
private const val VIEW_TYPE_STATE_BUTTON = 5
const val VIEW_TYPE_SELECTION_INTERACTION = 6

/** Adapter to inflate different items/views inside [RecyclerView]. The itemList consists of various ViewModels. */
class StateAdapter(
Expand Down Expand Up @@ -64,6 +69,17 @@ class StateAdapter(
)
ContentViewHolder(binding)
}
VIEW_TYPE_SELECTION_INTERACTION -> {
val inflater = LayoutInflater.from(parent.context)
val binding =
DataBindingUtil.inflate<SelectionInteractionItemBinding>(
inflater,
R.layout.selection_interaction_item,
parent,
/* attachToParent= */false
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
)
SelectionInteractionViewHolder(binding)
}
else -> throw IllegalArgumentException("Invalid view type")
}
}
Expand All @@ -76,12 +92,16 @@ class StateAdapter(
VIEW_TYPE_CONTENT -> {
(holder as ContentViewHolder).bind((itemList[position] as ContentViewModel).htmlContent)
}
VIEW_TYPE_SELECTION_INTERACTION -> {
(holder as SelectionInteractionViewHolder).bind((itemList[position] as CustomizationArgsInteractionViewModel))
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

override fun getItemViewType(position: Int): Int {
return when (itemList[position]) {
is ContentViewModel -> VIEW_TYPE_CONTENT
is CustomizationArgsInteractionViewModel -> VIEW_TYPE_SELECTION_INTERACTION
is StateButtonViewModel -> {
stateButtonViewModel = itemList[position] as StateButtonViewModel
VIEW_TYPE_STATE_BUTTON
Expand Down Expand Up @@ -124,4 +144,26 @@ class StateAdapter(
binding.executePendingBindings()
}
}

inner class SelectionInteractionViewHolder(
val binding: ViewDataBinding
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
) : RecyclerView.ViewHolder(binding.root) {
internal fun bind(customizationArgs: CustomizationArgsInteractionViewModel) {
val items: Array<String>?
val choiceContentList: MutableList<SelectionContentViewModel> = ArrayList()
binding.executePendingBindings()
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
val gaeCustomArgsInString = customizationArgs.choiceItems.toString().replace("[", "").replace("]", "")
items = gaeCustomArgsInString.split(",").toTypedArray()
for (values in items) {
val selectionContentViewModel = SelectionContentViewModel()
selectionContentViewModel.htmlContent = values
selectionContentViewModel.isAnswerSelected = false
choiceContentList.add(selectionContentViewModel)
}
val interactionAdapter =
InteractionAdapter(htmlParserFactory, entityType, explorationId, choiceContentList, customizationArgs)
binding.root.selection_interaction_recyclerview.adapter = interactionAdapter
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.oppia.app.player.audio.AudioFragment
import org.oppia.app.player.audio.CellularDataDialogFragment
import org.oppia.app.player.exploration.ExplorationActivity
import org.oppia.app.player.state.itemviewmodel.ContentViewModel
import org.oppia.app.player.state.itemviewmodel.CustomizationArgsInteractionViewModel
import org.oppia.app.player.state.itemviewmodel.StateButtonViewModel
import org.oppia.app.player.state.listener.ButtonInteractionListener
import org.oppia.app.viewmodel.ViewModelProvider
Expand All @@ -37,6 +38,7 @@ import javax.inject.Inject
const val STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY = "STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY"
private const val TAG_CELLULAR_DATA_DIALOG = "CELLULAR_DATA_DIALOG"
private const val TAG_AUDIO_FRAGMENT = "AUDIO_FRAGMENT"
private const val TAG_STATE_FRAGMENT = "STATE_FRAGMENT"

private const val CONTINUE = "Continue"
private const val END_EXPLORATION = "EndExploration"
Expand Down Expand Up @@ -176,6 +178,7 @@ class StateFragmentPresenter @Inject constructor(
itemList.clear()
currentEphemeralState = result
checkAndAddContentItem()
checkAndAddInteraction()
updateDummyStateName()

val interactionId = result.state.interaction.id
Expand Down Expand Up @@ -352,6 +355,46 @@ class StateFragmentPresenter @Inject constructor(
itemList.add(contentViewModel)
stateAdapter.notifyDataSetChanged()
}
private fun checkAndAddInteraction() {
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
if (currentEphemeralState.stateTypeCase.number == EphemeralState.PENDING_STATE_FIELD_NUMBER) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the enum directly:

if (currentEphemeralState.stateTypeCase == EphemeralState.TypeCase.PENDING_STATE)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is giving error to TypeCase as unresolved reference.

when (currentEphemeralState.state.interaction.id) {
MULTIPLE_CHOICE_INPUT -> {
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
addMultipleChoiceInputItem()
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
}
ITEM_SELECT_INPUT -> {
addMultipleChoiceInputItem()
}
}
}
}

private fun addMultipleChoiceInputItem() {
val customizationArgsMap: Map<String, InteractionObject> =
currentEphemeralState.state.interaction.customizationArgsMap
val multipleChoiceInputInteractionViewModel = CustomizationArgsInteractionViewModel()
val allKeys: Set<String> = customizationArgsMap.keys

for (key in allKeys) {
logger.d(TAG_STATE_FRAGMENT, key)
}
when {
customizationArgsMap.contains("choices") -> {
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
when {
customizationArgsMap.contains("maxAllowableSelectionCount") -> {
multipleChoiceInputInteractionViewModel.maxAllowableSelectionCount =
currentEphemeralState.state.interaction.customizationArgsMap["maxAllowableSelectionCount"]!!.signedInt
multipleChoiceInputInteractionViewModel.minAllowableSelectionCount =
currentEphemeralState.state.interaction.customizationArgsMap["minAllowableSelectionCount"]!!.signedInt
}
}
multipleChoiceInputInteractionViewModel.interactionId = currentEphemeralState.state.interaction.id
multipleChoiceInputInteractionViewModel.choiceItems =
currentEphemeralState.state.interaction.customizationArgsMap["choices"]!!.setOfHtmlString.htmlList
}
}
itemList.add(multipleChoiceInputInteractionViewModel)
stateAdapter.notifyDataSetChanged()
}

private fun updateNavigationButtonVisibility(
interactionId: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.oppia.app.player.state.itemviewmodel

import androidx.lifecycle.ViewModel
import org.oppia.app.fragment.FragmentScope
import javax.inject.Inject

/** [ViewModel] for multiple or item-selection input choice list. */
@FragmentScope
class CustomizationArgsInteractionViewModel : ViewModel() {

var choiceItems: MutableList<String>? = null
var interactionId: String = ""
var maxAllowableSelectionCount: Int = 0
var minAllowableSelectionCount: Int = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.oppia.app.player.state.itemviewmodel

import androidx.lifecycle.ViewModel
import org.oppia.app.fragment.FragmentScope
import javax.inject.Inject

/** [ViewModel] for MultipleChoiceInput values or ItemSelectionInput values. */
@FragmentScope
class SelectionContentViewModel : ViewModel() {
var htmlContent: String =""
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
var isAnswerSelected = false
}
Loading