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 View #188

Closed
Closed
89 changes: 89 additions & 0 deletions app/src/main/java/org/oppia/app/player/state/CustomCheckbox.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.oppia.app.player.state

import android.content.Context
import android.text.Html
import android.text.Spannable
import android.text.Spanned
import android.view.View
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import org.oppia.app.R
import org.oppia.util.data.UrlImageParser
import android.content.res.ColorStateList
import android.os.Build
import android.view.Gravity

// TODO(#190): Move this to a custom.inputinteractionview.
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
/** Custom Checkbox for MultipleSelectionInputInteractionView. */
class CustomCheckbox : CheckBox {
private var mContext: Context
private var optionContents: String? = null

constructor(context: Context, optionContents: String) : super(context) {
this.mContext = context
this.optionContents = optionContents
initViews()
}

//update default attributes of MultipleSelectionInputInteractionView here
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
fun initViews() {
veena14cs marked this conversation as resolved.
Show resolved Hide resolved

val paddingPixel = 2
val density = resources.displayMetrics.density
val paddingDp = (paddingPixel * density).toInt()

gravity = Gravity.LEFT

setTextColor(ContextCompat.getColor(context, R.color.oppiaDarkBlue))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setButtonTintList(colorStateList);
}
setHighlightColor(ContextCompat.getColor(context, R.color.oppiaDarkBlue))
textSize = 16f
setPadding(paddingDp, paddingDp, paddingDp, paddingDp)
id = View.generateViewId()
text = convertHtmlToString(optionContents, rootView).toString()

setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
val msg = "You have " + (if (isChecked) "checked" else "unchecked") + " this Check it Checkbox."
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
})
}

var colorStateList = ColorStateList(
arrayOf(
intArrayOf(android.R.attr.state_enabled) //enabled
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
),
intArrayOf(ContextCompat.getColor(context, R.color.oppiaDarkBlue))
)

fun convertHtmlToString(rawResponse: Any?, rdbtn: View): Spanned {

veena14cs marked this conversation as resolved.
Show resolved Hide resolved
var htmlContent = rawResponse as String;
var result: Spanned
var CUSTOM_TAG = "oppia-noninteractive-image"
var HTML_TAG = "img"
var CUSTOM_ATTRIBUTE = "filepath-with-value"
var HTML_ATTRIBUTE = "src"

if (htmlContent!!.contains(CUSTOM_TAG)) {

htmlContent = htmlContent.replace(CUSTOM_TAG, HTML_TAG, false);
htmlContent = htmlContent.replace(CUSTOM_ATTRIBUTE, HTML_ATTRIBUTE, false);
htmlContent = htmlContent.replace(""", "")
}

var imageGetter = UrlImageParser(rdbtn as TextView, context)
val html: Spannable
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
html = Html.fromHtml(htmlContent, Html.FROM_HTML_MODE_LEGACY, imageGetter, null) as Spannable
} else {
html = Html.fromHtml(htmlContent, imageGetter, null) as Spannable
}
result = html
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.oppia.app.player.state

import android.content.Context
import android.content.res.ColorStateList
import android.os.Build
import android.text.Html
import android.text.Spannable
import android.text.Spanned
import android.view.Gravity
import android.view.View
import android.widget.RadioButton
import android.widget.TextView
import androidx.core.content.ContextCompat
import org.oppia.app.R
import org.oppia.util.data.UrlImageParser

// TODO(#190): Move this to a custom.inputinteractionview.
/** Custom Checkbox for MultipleSelectionInputInteractionView. */
class CustomRadioButton : RadioButton {
private var mContext: Context
private var optionContents: String? = null

constructor(context: Context, optionContents: String) : super(context) {
this.mContext = context
this.optionContents = optionContents
initViews()
}

//update default attributes of ItemSelectionInputInteractionView here
fun initViews() {
veena14cs marked this conversation as resolved.
Show resolved Hide resolved

val paddingPixel = 2
val density = resources.displayMetrics.density
val paddingDp = (paddingPixel * density).toInt()

gravity = Gravity.LEFT

setTextColor(ContextCompat.getColor(context, R.color.oppiaDarkBlue))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setButtonTintList(colorStateList);
}
setHighlightColor(ContextCompat.getColor(context, R.color.oppiaDarkBlue))
textSize = 16f
setPadding(paddingDp, paddingDp, paddingDp, paddingDp)
id = View.generateViewId()
text = convertHtmlToString(optionContents, rootView).toString()
}

var colorStateList = ColorStateList(
arrayOf(
intArrayOf(android.R.attr.state_enabled) //enabled
),
intArrayOf(ContextCompat.getColor(context, R.color.oppiaDarkBlue))
)

fun convertHtmlToString(rawResponse: Any?, rdbtn: View): Spanned {

var htmlContent = rawResponse as String;
var result: Spanned
var CUSTOM_TAG = "oppia-noninteractive-image"
var HTML_TAG = "img"
var CUSTOM_ATTRIBUTE = "filepath-with-value"
var HTML_ATTRIBUTE = "src"

if (htmlContent!!.contains(CUSTOM_TAG)) {

htmlContent = htmlContent.replace(CUSTOM_TAG, HTML_TAG, false);
htmlContent = htmlContent.replace(CUSTOM_ATTRIBUTE, HTML_ATTRIBUTE, false);
htmlContent = htmlContent.replace(""", "")
}

var imageGetter = UrlImageParser(rdbtn as TextView, context)
val html: Spannable
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
html = Html.fromHtml(htmlContent, Html.FROM_HTML_MODE_LEGACY, imageGetter, null) as Spannable
} else {
html = Html.fromHtml(htmlContent, imageGetter, null) as Spannable
}
result = html
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
package org.oppia.app.player.state

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.state_fragment.view.*
import org.oppia.app.application.ApplicationContext
import org.oppia.app.databinding.StateFragmentBinding
import org.oppia.app.fragment.FragmentScope
import org.oppia.app.viewmodel.ViewModelProvider
import org.oppia.data.backends.gae.model.GaeCustomizationArgs
import javax.inject.Inject

/** The presenter for [StateFragment]. */
@FragmentScope
class StateFragmentPresenter @Inject constructor(
@ApplicationContext private val context: Context,
private val fragment: Fragment,
private val viewModelProvider: ViewModelProvider<StateViewModel>
) {
private lateinit var binding: StateFragmentBinding

fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? {
val binding = StateFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false)
binding = StateFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false)
binding.let {
it.stateFragment = fragment as StateFragment
it.viewModel = getStateViewModel()
}
showInputInteractions()
return binding.root
}

Expand All @@ -31,4 +43,66 @@ class StateFragmentPresenter @Inject constructor(
fun setAudioFragmentVisible(isVisible: Boolean) {
getStateViewModel().setAudioFragmentVisible(isVisible)
}

private fun showInputInteractions() {

veena14cs marked this conversation as resolved.
Show resolved Hide resolved
//Todo(Veena): Remove static initialization and use values from constructor for gaeCustomizationArgsMap and interactionInstanceId
var gaeCustomizationArgsMap = HashMap<String, GaeCustomizationArgs>()
var interactionInstanceId = "MultipleChoiceInput"
var sampleData: GaeCustomizationArgs =
GaeCustomizationArgs(true, "<p>The numerator.</p>, <p>The denominator.</p>, <p>I can't remember!</p>]")
gaeCustomizationArgsMap?.put("choices", sampleData)
interactionInstanceId = "MultipleChoiceInput"

// Todo(veena): Keep the below code for actual implementation
val gaeCustomizationArgs: Any? = gaeCustomizationArgsMap!!.get("choices")?.value

if (interactionInstanceId.equals("MultipleChoiceInput")) {
val gaeCustomArgsInString: String = gaeCustomizationArgs.toString().replace("[", "").replace("]", "")
var items = gaeCustomArgsInString.split(",").toTypedArray()
addRadioButtons(items)
} else if (interactionInstanceId.equals("ItemSelectionInput") || interactionInstanceId.equals("SingleChoiceInput")) {
val gaeCustomArgsInString: String = gaeCustomizationArgs.toString().replace("[", "").replace("]", "")
var items = gaeCustomArgsInString.split(",").toTypedArray()
addCheckbox(items)
} else {
//Do no show any view
}
}

fun addCheckbox(optionsArray: Array<String>) {
for (row in 0..0) {
for (i in 0..optionsArray.size - 1) {
val cb = CustomCheckbox(context, optionsArray[i])
binding.root.interactionContainer.addView(cb)
}
}
}

fun addRadioButtons(optionsArray: Array<String>) {
for (row in 0..0) {
val rg = RadioGroup(context)
rg.orientation = LinearLayout.VERTICAL

for (i in 0..optionsArray.size - 1) {
val rdbtn = CustomRadioButton(context, optionsArray[i])

rg.setOnCheckedChangeListener(object : RadioGroup.OnCheckedChangeListener {
override fun onCheckedChanged(group: RadioGroup, checkedId: Int) {
for (i in 0 until group.childCount) {
val btn = group.getChildAt(i) as RadioButton
if (btn.id == checkedId) {
val text = btn.text
Toast.makeText(context, "" + text, Toast.LENGTH_LONG).show()
return
}
}
}
})
rg.addView(rdbtn)
}
binding.root.interactionRadioGroup.addView(rg)
}
}

}
22 changes: 19 additions & 3 deletions app/src/main/res/layout/state_fragment.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
Expand All @@ -15,20 +15,36 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility="@{viewModel.isAudioFragmentVisible? View.VISIBLE: View.GONE}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent">
Copy link
Contributor

Choose a reason for hiding this comment

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

Correct this code indentation.

<fragment
android:id="@+id/audio_fragment"
class="org.oppia.app.player.audio.AudioFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/interactionContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@color/white" android:orientation="vertical"
android:padding="10dp"
app:layout_constraintBottom_toTopOf="@+id/dummy_audio_button"
app:layout_constraintTop_toBottomOf="@+id/linearLayout" tools:layout_editor_absoluteX="8dp">
veena14cs marked this conversation as resolved.
Show resolved Hide resolved
<RadioGroup
android:id="@+id/interactionRadioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp">
</RadioGroup>
</LinearLayout>
<Button
android:id="@+id/dummy_audio_button"
android:layout_width="wrap_content"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
<color name="white">#FFFFFF</color>
<!-- AUDIO COMPONENT -->
<color name="audioComponentBackground">@color/oppiaDarkBlue</color>

<color name="blue_100">#0F0086FB</color>
<color name="blue_200">#6B0086FB</color>
</resources>
3 changes: 2 additions & 1 deletion utility/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ dependencies {
'androidx.appcompat:appcompat:1.0.2',
'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha03',
'com.google.dagger:dagger:2.24',
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version",
'com.github.bumptech.glide:glide:4.9.0',
)
testImplementation(
'androidx.test.ext:junit:1.1.1',
Expand Down
Loading