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 #138: Topic train fragment Low-fi UI (Part 4) #204

Merged
merged 41 commits into from
Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8cdfb33
All xml files for topic-train except layout folder
Oct 3, 2019
afd8196
Skill item related files
Oct 3, 2019
87977ab
TopicTrainFragment implementation
Oct 3, 2019
456d129
Topic Train Test Case
Oct 3, 2019
d21f52b
Introduce QuestionPlayer Activity/Fragment
Oct 4, 2019
e39fa93
Domain layer code integration
Oct 5, 2019
9ff0ff5
Resolve merge conflict develop
Oct 5, 2019
685bd2d
Merge remote-tracking branch 'upstream/topic-train-low-fi-part-3' int…
Oct 5, 2019
1cd605f
Start button activated
Oct 5, 2019
e30e58a
Start button activated
Oct 5, 2019
b1cef82
Separate ViewModel for item
Oct 5, 2019
23e4d27
Managing configuration changes
Oct 5, 2019
7fe1f87
Checkbox state save
Oct 5, 2019
3d0315a
Nit changes
Oct 5, 2019
6c5387f
Fixing HomeActivityController
Oct 6, 2019
5b2dc90
Managing configuration change in checkboxes
Oct 6, 2019
b9b9683
Proper route to QuestionPlayer
Oct 6, 2019
b578d34
Merge remote-tracking branch 'upstream/topic-train-low-fi-part-3' int…
Oct 6, 2019
37a4837
QuestionPlayerActivity test case
Oct 6, 2019
6321130
Nit changes
Oct 6, 2019
de7568a
Merge remote-tracking branch 'upstream/topic-train-low-fi-part-3' int…
Oct 6, 2019
7bb449b
More test cases
Oct 7, 2019
06f03b9
Nit changes
Oct 7, 2019
dcdb082
Resolve merge conflicts
Oct 7, 2019
6968d06
Merge remote-tracking branch 'upstream/topic-train-low-fi-part-3' int…
Oct 7, 2019
81eee40
EOF added
Oct 7, 2019
9f2ad98
Resolve merge conflicts
Oct 8, 2019
45b1b18
Test nit changes
Oct 8, 2019
04125a0
Merge remote-tracking branch 'upstream/develop' into topic-train-low-…
Oct 9, 2019
d9f586d
Test case updated
Oct 9, 2019
1208a4a
Merge remote-tracking branch 'upstream/develop' into topic-train-low-…
Oct 10, 2019
b7fb1e4
Updated RecyclerViewMatcher
Oct 10, 2019
9e81bb5
Nit change
Oct 10, 2019
5274077
Test added
Oct 11, 2019
ba680a3
Merge remote-tracking branch 'upstream/develop' into topic-train-low-…
Oct 11, 2019
3d03e47
Merge remote-tracking branch 'upstream/develop' into topic-train-low-…
Oct 15, 2019
1b446ff
Nit changes
Oct 15, 2019
2e9a334
Nit changes
Oct 15, 2019
79b11ff
Merge remote-tracking branch 'upstream/develop' into topic-train-low-…
Oct 18, 2019
5b9d0dd
Test cases
Oct 18, 2019
8a5f22f
Test case updated
Oct 18, 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
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dependencies {
'androidx.constraintlayout:constraintlayout:1.1.3',
'androidx.core:core-ktx:1.0.2',
'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha03',
'androidx.recyclerview:recyclerview:1.0.0',
'com.google.dagger:dagger:2.24',
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version",
"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1",
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/java/org/oppia/app/topic/train/SkillInterface.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.oppia.app.topic.train

/** Interface to update the selectedSkillList in [TopicTrainFragmentPresenter]. */
interface SkillInterface {
/** This skill will get added to selectedSkillList in [TopicTrainFragmentPresenter] */
fun skillSelected(skill: String)
/** This skill will get removed from selectedSkillList in [TopicTrainFragmentPresenter] */
fun skillUnselected(skill: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.oppia.app.topic.train;

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.topic_train_skill_view.view.*
import org.oppia.app.R
import org.oppia.app.databinding.TopicTrainSkillViewBinding

/** Adapter to bind skills to [RecyclerView] inside [TopicTrainFragment]. **/
class SkillSelectionAdapter(
private val skillList: List<String>,
private val skillInterface: SkillInterface
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding =
DataBindingUtil.inflate<TopicTrainSkillViewBinding>(
inflater,
R.layout.topic_train_skill_view,
parent,
false
)
return SkillViewHolder(binding)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as SkillViewHolder).bind(skillList[position], position)
}

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

private inner class SkillViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
internal fun bind(rawString: String?, position: Int) {
binding.setVariable(BR.skill, rawString)
binding.root.skill_check_box.setOnCheckedChangeListener { buttonView, isChecked ->
val skill = skillList[position]
if (isChecked) {
skillInterface.skillSelected(skill)
} else {
skillInterface.skillUnselected(skill)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ class TopicTrainFragment : InjectableFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return topicTrainFragmentPresenter.handleCreateView(inflater, container)
}

fun submitButtonClicked(){
// List of selected skills when submit button is clicked.
val skillList = topicTrainFragmentPresenter.getSelectedSkillList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,61 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import org.oppia.app.databinding.TopicTrainFragmentBinding
import org.oppia.app.fragment.FragmentScope
import org.oppia.app.viewmodel.ViewModelProvider
import javax.inject.Inject

/** The presenter for [TopicTrainFragment]. */
@FragmentScope
class TopicTrainFragmentPresenter @Inject constructor(
private val fragment: Fragment
) {
private val fragment: Fragment,
private val viewModelProvider: ViewModelProvider<TopicTrainViewModel>
) : SkillInterface {
private val selectedSkillList = ArrayList<String>()

fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? {
val skillAdapter = SkillSelectionAdapter(dummySkillList(), this)

val binding = TopicTrainFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false)
binding.skillRecyclerView.apply {
adapter = skillAdapter
layoutManager = LinearLayoutManager(context)
}
binding.let {
it.viewModel = getTopicTrainViewModel()
it.lifecycleOwner = fragment
}
return binding.root
}

private fun getTopicTrainViewModel(): TopicTrainViewModel {
return viewModelProvider.getForFragment(fragment, TopicTrainViewModel::class.java)
}

override fun skillSelected(skill: String) {
selectedSkillList.add(skill)
getTopicTrainViewModel().selectedSkillList(selectedSkillList)
}

override fun skillUnselected(skill: String) {
selectedSkillList.remove(skill)
getTopicTrainViewModel().selectedSkillList(selectedSkillList)
}

private fun dummySkillList(): List<String> {
val skillList = ArrayList<String>()
skillList.add("Identify the Parts of a Fraction")
skillList.add("Writing Fractions")
skillList.add("Equivalent Fractions")
skillList.add("Mixed Numbers and Improper Fractions")
skillList.add("Comparing Fractions")
skillList.add("Adding and Subtracting Fractions")
skillList.add("Multiplying Fractions")
skillList.add("Dividing Fractions")
return skillList
}

fun getSelectedSkillList() = selectedSkillList
}
16 changes: 16 additions & 0 deletions app/src/main/java/org/oppia/app/topic/train/TopicTrainViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.oppia.app.topic.train

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

/** [ViewModel] for showing skills in train fragment. */
@FragmentScope
class TopicTrainViewModel @Inject constructor() : ViewModel() {
var isSubmitButtonActive = ObservableField<Boolean>(false)

fun selectedSkillList(selectedSkillList: ArrayList<String>) {
isSubmitButtonActive.set(selectedSkillList.isNotEmpty())
}
}
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/state_button_primary_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="@dimen/state_previous_next_button_radius"/>
<solid
android:color="@color/colorPrimary"/>
</shape>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="@android:color/transparent"/>
</shape>
59 changes: 53 additions & 6 deletions app/src/main/res/layout/topic_train_fragment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,64 @@
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
<variable
name="topicTrainFragment"
type="org.oppia.app.topic.train.TopicTrainFragment"/>
<variable
name="viewModel"
type="org.oppia.app.topic.train.TopicTrainViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/dummy_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is dummy TextView for testing"
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="32dp">
<TextView
android:id="@+id/master_skills_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/topic_train_master_these_skills"
android:textColor="@color/oppiaPrimaryText"
android:textSize="20sp"/>
<TextView
android:id="@+id/skills_description_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/topic_train_skills_description"
android:textColor="@color/oppiaSecondaryText"
android:textSize="16sp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/skill_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
<Button
android:id="@+id/topic_train_start_button"
style="@style/StateButtonInactive"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:background="@{viewModel.isSubmitButtonActive() ? @drawable/state_button_primary_background :@drawable/state_button_transparent_background}"
android:clickable="@{viewModel.isSubmitButtonActive()}"
android:onClick="@{(v) -> topicTrainFragment.submitButtonClicked()}"
android:text="@string/topic_train_start"
android:textColor="@{viewModel.isSubmitButtonActive()? @color/white : @color/submitButtonInactive}"/>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
28 changes: 28 additions & 0 deletions app/src/main/res/layout/topic_train_skill_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="skill"
type="java.lang.String"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/skill_check_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:drawablePadding="4dp"
android:gravity="center_vertical"
android:text="@{skill}"
android:textColor="@color/oppiaPrimaryText"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
4 changes: 4 additions & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@
<color name="ic_launcher_background">#26A69A</color>
<!-- OPPIA COLORS -->
<color name="oppiaDarkBlue">#2D4A9D</color>
<color name="oppiaPrimaryText">#333333</color>
<color name="oppiaSecondaryText">#666666</color>
<!-- BASIC COLORS -->
<color name="white">#FFFFFF</color>
<!-- AUDIO COMPONENT -->
<color name="audioComponentBackground">@color/oppiaDarkBlue</color>
<!-- SUBMIT BUTTON INACTIVE -->
<color name="submitButtonInactive">#56000000</color>
</resources>
1 change: 1 addition & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
<dimen name="audio_fragment_corner_radius">8dp</dimen>
<dimen name="audio_fragment_margin">32dp</dimen>
<dimen name="cellular_data_dialog_padding">24dp</dimen>
<dimen name="state_previous_next_button_radius">4dp</dimen>
</resources>
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@
<string name="cellular_data_alert_dialog_title">Currently on Cellular Data</string>
<string name="cellular_data_alert_dialog_description">Streaming audio may use a lot of cellular data.</string>
<string name="cellular_data_alert_dialog_checkbox">Don\'t show this message again</string>
<string name="topic_train_master_these_skills">Master These Skills</string>
<string name="topic_train_skills_description">Select or unselect skills that you want to practice</string>
<string name="topic_train_start">Start</string>
</resources>
27 changes: 27 additions & 0 deletions app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,31 @@
<item name="android:windowEnterAnimation">@anim/slide_up</item>
<item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

<!-- STATE BUTTON ACTIVE STYLE -->
<style name="StateButtonActive" parent="TextAppearance.AppCompat.Widget.Button">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">@drawable/state_button_primary_background</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingBottom">8dp</item>
<item name="android:paddingStart">16dp</item>
<item name="android:paddingEnd">16dp</item>
<item name="android:textAllCaps">true</item>
<item name="android:textColor">@color/white</item>
<item name="android:textSize">14sp</item>
<item name="android:clickable">true</item>
</style>

<!-- STATE BUTTON INACTIVE STYLE -->
<style name="StateButtonInactive" parent="TextAppearance.AppCompat.Widget.Button">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">8dp</item>
<item name="android:textAllCaps">true</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:textColor">#56000000</item>
<item name="android:textSize">14sp</item>
<item name="android:clickable">false</item>
</style>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import android.app.Application
import android.content.Context
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.scrollTo
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isClickable
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
Expand All @@ -13,10 +17,11 @@ import dagger.Component
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.CoroutineDispatcher
import org.hamcrest.Matchers.not
import org.junit.Test
import org.junit.runner.RunWith
import org.oppia.app.R
import org.oppia.app.topic.TopicActivity
import org.oppia.app.home.HomeActivity
import org.oppia.util.threading.BackgroundDispatcher
import org.oppia.util.threading.BlockingDispatcher
import javax.inject.Singleton
Expand All @@ -26,9 +31,13 @@ import javax.inject.Singleton
class TopicTrainFragmentTest {

@Test
rt4914 marked this conversation as resolved.
Show resolved Hide resolved
fun testTopicTrainFragment_loadFragment_textIsDisplayed() {
ActivityScenario.launch(TopicActivity::class.java).use {
onView(withId(R.id.dummy_text_view)).check(matches(withText("This is dummy TextView for testing")))
fun testTopicTrainFragment_loadFragment_selectSkills_submitButtonIsActivated() {
Copy link
Member

Choose a reason for hiding this comment

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

Other cases worth testing:

  • Verifying that when no skills are selected, the button is not clickable
  • Verifying that the button's clickable state becomes disabled after selecting & deselecting skills
  • Verifying that clicking the submit button properly forwards the list of skills to an outgoing activity
  • Verifying that the list of selected skills stay selected upon a configuration change
  • Verifying that the submit button activation status stays correct for both enabled/disabled cases upon a configuration change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added all these working test-cases

ActivityScenario.launch(HomeActivity::class.java).use {
onView(withId(R.id.master_skills_text_view)).check(matches(withText(R.string.topic_train_master_these_skills)))
onView(withId(R.id.topic_train_start_button)).check(matches(not(isClickable())))
onView(withText("Writing Fractions")).check(matches(isNotChecked())).perform(scrollTo(), click())
onView(withText("Equivalent Fractions")).check(matches(isNotChecked())).perform(scrollTo(), click())
onView(withId(R.id.topic_train_start_button)).check(matches(isClickable()))
rt4914 marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down