11package org.ole.planet.myplanet.ui.exam
22
3+ import android.graphics.Color
4+ import android.graphics.Typeface
5+ import android.graphics.drawable.GradientDrawable
6+ import android.graphics.drawable.StateListDrawable
37import android.os.Bundle
48import android.text.Editable
59import android.text.TextUtils
610import android.text.TextWatcher
11+ import android.view.Gravity
712import android.view.LayoutInflater
813import android.view.View
914import android.view.ViewGroup
1015import android.widget.Button
1116import android.widget.CompoundButton
17+ import android.widget.LinearLayout
1218import android.widget.RadioButton
1319import android.widget.Toast
1420import androidx.core.content.ContextCompat
@@ -329,7 +335,7 @@ class ExamTakingFragment : BaseExamFragment(), View.OnClickListener, CompoundBut
329335 }
330336 question?.type.equals(" ratingScale" , ignoreCase = true ) -> {
331337 binding.llRatingScale.visibility = View .VISIBLE
332- setupRatingScale(ans)
338+ setupRatingScale(question, ans)
333339 }
334340 }
335341 binding.tvHeader.text = question?.header
@@ -379,28 +385,49 @@ class ExamTakingFragment : BaseExamFragment(), View.OnClickListener, CompoundBut
379385 }
380386
381387 private var selectedRatingButton: Button ? = null
382-
383- private fun setupRatingScale (oldAnswer : String ) {
384- val ratingButtons = listOf (
385- binding.rbRating1,
386- binding.rbRating2,
387- binding.rbRating3,
388- binding.rbRating4,
389- binding.rbRating5,
390- binding.rbRating6,
391- binding.rbRating7,
392- binding.rbRating8,
393- binding.rbRating9
394- )
395-
396- ratingButtons.forEachIndexed { index, button ->
388+ private var dynamicRatingButtons: List <Button > = emptyList()
389+
390+ private fun setupRatingScale (question : RealmExamQuestion ? , oldAnswer : String ) {
391+ val scaleMax = (question?.scaleMax ? : 0 ).let { if (it <= 0 ) 9 else it }
392+ binding.llRatingScale.removeAllViews()
393+ dynamicRatingButtons = emptyList()
394+
395+ val buttonSizePx = (60 * resources.displayMetrics.density).toInt()
396+ val marginPx = (8 * resources.displayMetrics.density).toInt()
397+ val buttonsPerRow = 3
398+ val buttons = mutableListOf<Button >()
399+ var currentRow: LinearLayout ? = null
400+
401+ val useGradient = scaleMax == 9
402+
403+ for (i in 1 .. scaleMax) {
404+ val positionInRow = (i - 1 ) % buttonsPerRow
405+ if (positionInRow == 0 ) {
406+ currentRow = LinearLayout (requireContext()).apply {
407+ orientation = LinearLayout .HORIZONTAL
408+ gravity = Gravity .CENTER
409+ layoutParams = LinearLayout .LayoutParams (
410+ LinearLayout .LayoutParams .WRAP_CONTENT ,
411+ LinearLayout .LayoutParams .WRAP_CONTENT
412+ ).also { it.bottomMargin = marginPx }
413+ }
414+ binding.llRatingScale.addView(currentRow)
415+ }
416+ val isLastInRow = positionInRow == buttonsPerRow - 1 || i == scaleMax
417+ val ratio = if (scaleMax > 1 ) (i - 1 ).toFloat() / (scaleMax - 1 ) else 0f
418+ val button = createRatingButton(i, ratio, buttonSizePx, if (isLastInRow) 0 else marginPx, useGradient)
419+ currentRow?.addView(button)
420+ buttons.add(button)
421+ }
422+
423+ dynamicRatingButtons = buttons
424+
425+ buttons.forEachIndexed { index, button ->
397426 button.setOnClickListener {
398427 selectedRatingButton?.isSelected = false
399-
400428 button.isSelected = true
401429 selectedRatingButton = button
402430 ans = (index + 1 ).toString()
403-
404431 updateNavButtons()
405432 }
406433 }
@@ -409,24 +436,62 @@ class ExamTakingFragment : BaseExamFragment(), View.OnClickListener, CompoundBut
409436 selectRatingValue(oldAnswer.toIntOrNull() ? : 1 )
410437 }
411438 }
412-
413- private fun selectRatingValue (value : Int ) {
414- val ratingButtons = listOf (
415- binding.rbRating1,
416- binding.rbRating2,
417- binding.rbRating3,
418- binding.rbRating4,
419- binding.rbRating5,
420- binding.rbRating6,
421- binding.rbRating7,
422- binding.rbRating8,
423- binding.rbRating9
424- )
425439
440+ private fun createRatingButton (number : Int , colorRatio : Float , sizePx : Int , marginEndPx : Int , useGradient : Boolean ): Button {
441+ val selectedColor = ContextCompat .getColor(requireContext(), R .color.colorPrimary)
442+ val cornerPx = 8 * resources.displayMetrics.density
443+ val strokePx = (2 * resources.displayMetrics.density).toInt()
444+
445+ val unselectedBg: Int
446+ val unselectedStroke: Int
447+ if (useGradient) {
448+ unselectedBg = interpolateColor(0xFFFFE9EA .toInt(), 0xFFE9FBE9 .toInt(), colorRatio)
449+ unselectedStroke = unselectedBg
450+ } else {
451+ unselectedBg = ContextCompat .getColor(requireContext(), R .color.card_bg)
452+ unselectedStroke = ContextCompat .getColor(requireContext(), R .color.daynight_textColor)
453+ }
454+
455+ fun makeShape (fillColor : Int , strokeColor : Int ) = GradientDrawable ().apply {
456+ shape = GradientDrawable .RECTANGLE
457+ cornerRadius = cornerPx
458+ setColor(fillColor)
459+ setStroke(strokePx, strokeColor)
460+ }
461+
462+ val stateList = StateListDrawable ().apply {
463+ addState(intArrayOf(android.R .attr.state_selected), makeShape(selectedColor, selectedColor))
464+ addState(intArrayOf(android.R .attr.state_pressed), makeShape(selectedColor, selectedColor))
465+ addState(intArrayOf(), makeShape(unselectedBg, unselectedStroke))
466+ }
467+
468+ return Button (requireContext()).apply {
469+ text = number.toString()
470+ textSize = 16f
471+ setTypeface(null , Typeface .BOLD )
472+ setTextColor(ContextCompat .getColorStateList(requireContext(), R .color.rating_button_text_color))
473+ background = stateList
474+ minHeight = 0
475+ minWidth = 0
476+ setPadding(0 , 0 , 0 , 0 )
477+ layoutParams = LinearLayout .LayoutParams (sizePx, sizePx).apply {
478+ marginEnd = marginEndPx
479+ }
480+ }
481+ }
482+
483+ private fun interpolateColor (start : Int , end : Int , ratio : Float ): Int {
484+ val r = (Color .red(start) + (Color .red(end) - Color .red(start)) * ratio).toInt()
485+ val g = (Color .green(start) + (Color .green(end) - Color .green(start)) * ratio).toInt()
486+ val b = (Color .blue(start) + (Color .blue(end) - Color .blue(start)) * ratio).toInt()
487+ return Color .rgb(r, g, b)
488+ }
489+
490+ private fun selectRatingValue (value : Int ) {
426491 selectedRatingButton?.isSelected = false
427-
428- if (value in 1 .. 9 ) {
429- val button = ratingButtons [value - 1 ]
492+ val buttons = dynamicRatingButtons
493+ if (value in 1 .. buttons.size ) {
494+ val button = buttons [value - 1 ]
430495 button.isSelected = true
431496 selectedRatingButton = button
432497 }
@@ -751,6 +816,7 @@ class ExamTakingFragment : BaseExamFragment(), View.OnClickListener, CompoundBut
751816 }
752817 answerTextWatcher?.let { binding.etAnswer.removeTextChangedListener(it) }
753818 selectedRatingButton = null
819+ dynamicRatingButtons = emptyList()
754820 _binding = null
755821 }
756822}
0 commit comments