Skip to content

Commit

Permalink
feat: add support for dividers in run test screen
Browse files Browse the repository at this point in the history
  • Loading branch information
aanorbel committed Jun 28, 2024
1 parent 451a147 commit 10016f9
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.openobservatory.ooniprobe.activity.runtests.adapter.RunTestsExpandabl
import org.openobservatory.ooniprobe.activity.runtests.models.ChildItem
import org.openobservatory.ooniprobe.activity.runtests.models.GroupItem
import org.openobservatory.ooniprobe.common.AbstractDescriptor
import org.openobservatory.ooniprobe.common.OONIDescriptor
import org.openobservatory.ooniprobe.common.OONITests
import org.openobservatory.ooniprobe.common.PreferenceManager
import org.openobservatory.ooniprobe.common.disableTest
Expand Down Expand Up @@ -82,10 +83,20 @@ class RunTestsActivity : AbstractActivity() {
intent.extras?.getSerializable(TESTS) as List<AbstractDescriptor<BaseNettest>>?
descriptors?.let { _descriptors ->

adapter = RunTestsExpandableListViewAdapter(
_descriptors.map { descriptor ->
val groupedItemList = mutableListOf<Any>()

_descriptors.groupBy { it.javaClass }.forEach { (type, itemList) ->
if (type == OONIDescriptor::class.java){
groupedItemList.add("OONI Tests".uppercase())
} else {
groupedItemList.add("OONI RUN Links".uppercase())
}
groupedItemList.addAll(itemList.map { descriptor ->
descriptor.toRunTestsGroupItem(preferenceManager = preferenceManager)
},
})
}
adapter = RunTestsExpandableListViewAdapter(
groupedItemList,
viewModel
)

Expand Down Expand Up @@ -137,22 +148,25 @@ class RunTestsActivity : AbstractActivity() {
*/
private fun updatePreferences() {
for (i in 0 until adapter.groupCount) {
val group = adapter.getGroup(i)
when (group.name) {
OONITests.EXPERIMENTAL.label -> {
val testNames = OONITests.EXPERIMENTAL.nettests.map { it.name };
when(group.nettests.filter { testNames.contains(it.name) }.map { it.selected }.all { it }) {
true -> preferenceManager.enableTest(OONITests.EXPERIMENTAL.label)
false -> preferenceManager.disableTest(OONITests.EXPERIMENTAL.label)
}
}
else -> group.nettests.forEach { nettest ->
when(nettest.selected) {
true -> preferenceManager.enableTest(nettest.name, group.preferencePrefix())
false -> preferenceManager.disableTest(nettest.name, group.preferencePrefix())
}
}
}
when(val group = adapter.getGroup(i)) {
is GroupItem ->{
when (group.name) {
OONITests.EXPERIMENTAL.label -> {
val testNames = OONITests.EXPERIMENTAL.nettests.map { it.name };
when(group.nettests.filter { testNames.contains(it.name) }.map { it.selected }.all { it }) {
true -> preferenceManager.enableTest(OONITests.EXPERIMENTAL.label)
false -> preferenceManager.disableTest(OONITests.EXPERIMENTAL.label)
}
}
else -> group.nettests.forEach { nettest ->
when(nettest.selected) {
true -> preferenceManager.enableTest(nettest.name, group.preferencePrefix())
false -> preferenceManager.disableTest(nettest.name, group.preferencePrefix())
}
}
}
}
}
}
}

Expand Down Expand Up @@ -197,22 +211,30 @@ class RunTestsActivity : AbstractActivity() {
private fun getChildItemsSelectedIdList(): List<String> {
val childItemSelectedIdList: MutableList<String> = ArrayList()
for (i in 0 until adapter.groupCount) {
val secondLevelItemList: List<ChildItem> = adapter.getGroup(i).nettests
secondLevelItemList
.asSequence()
.filter { it.selected }
.mapTo(childItemSelectedIdList) { it.name }
when(val group = adapter.getGroup(i)) {
is GroupItem ->{
val secondLevelItemList: List<ChildItem> = group.nettests
secondLevelItemList
.asSequence()
.filter { it.selected }
.mapTo(childItemSelectedIdList) { it.name }
}
}
}
return childItemSelectedIdList
}

private fun getGroupItemsAtLeastOneChildEnabled(): List<GroupItem> {
val items: MutableList<GroupItem> = ArrayList()
for (i in 0 until adapter.groupCount) {
if (adapter.getGroup(i).nettests.any { it.selected }) {
items.add(adapter.getGroup(i).apply {
nettests = nettests.filter { it.selected }
})
when(val group = adapter.getGroup(i)) {
is GroupItem ->{
if (group.nettests.any { it.selected }) {
items.add(group.apply {
nettests = nettests.filter { it.selected }
})
}
}
}
}
return items
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.view.ViewGroup
import android.widget.BaseExpandableListAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import org.openobservatory.ooniprobe.R
import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel
import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel.Companion.SELECT_ALL
Expand All @@ -22,7 +23,7 @@ import org.openobservatory.ooniprobe.test.test.AbstractTest
* @param viewModel RunTestsViewModel object.
*/
class RunTestsExpandableListViewAdapter(
private val groupedListData: List<GroupItem>,
private val groupedListData: List<Any>,
private val viewModel: RunTestsViewModel
) : BaseExpandableListAdapter() {
/**
Expand All @@ -36,21 +37,26 @@ class RunTestsExpandableListViewAdapter(
* @param groupPosition Position of the group in the list.
* @return Number of children in the group.
*/
override fun getChildrenCount(groupPosition: Int): Int = groupedListData[groupPosition].nettests.size
override fun getChildrenCount(groupPosition: Int): Int = when (val group = groupedListData[groupPosition]) {
is GroupItem -> group.nettests.size
else -> 0
}

/**
* @param groupPosition Position of the group in the list.
* @return GroupItem object.
*/
override fun getGroup(groupPosition: Int): GroupItem = groupedListData[groupPosition]
override fun getGroup(groupPosition: Int): Any = groupedListData[groupPosition]

/**
* @param groupPosition Position of the group in the list.
* @param childPosition Position of the child in the group.
* @return ChildItem object.
*/
override fun getChild(groupPosition: Int, childPosition: Int): ChildItem =
groupedListData[groupPosition].nettests[childPosition]
override fun getChild(groupPosition: Int, childPosition: Int): ChildItem = when (val group = groupedListData[groupPosition]) {
is GroupItem -> group.nettests[childPosition]
else -> throw IllegalArgumentException("GroupItem expected")
}

/**
* @param groupPosition Position of the group in the list.
Expand Down Expand Up @@ -78,69 +84,79 @@ class RunTestsExpandableListViewAdapter(
* @return View object.
*/
override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup): View? {
var convertView =
convertView ?: LayoutInflater.from(parent.context).inflate(R.layout.run_tests_group_list_item, parent, false)

val groupItem = getGroup(groupPosition)
convertView.findViewById<TextView>(R.id.group_name).text = groupItem.title
val icon = convertView.findViewById<ImageView>(R.id.group_icon)
icon.setImageResource(groupItem.getDisplayIcon(parent.context))
icon.setColorFilter(groupItem.color)
val groupSelectionIndicator = convertView.findViewById<ImageView>(R.id.group_select_indicator)
val selectedAllBtnStatus = viewModel.selectedAllBtnStatus.getValue()
if (selectedAllBtnStatus == SELECT_ALL) {
groupItem.selected = true
for (childItem in groupItem.nettests) {
childItem.selected = true
}
} else if (selectedAllBtnStatus == SELECT_NONE) {
groupItem.selected = false
for (childItem in groupItem.nettests) {
childItem.selected = false
}
} else if (isSelectAllChildItems(groupItem.nettests)) {
groupItem.selected = true
}
if (groupItem.selected) {
if (isSelectAllChildItems(groupItem.nettests)) {
groupSelectionIndicator.setImageResource(R.drawable.check_box)
} else {
groupSelectionIndicator.setImageResource(R.drawable.check_box_outline_blank)
}
} else {
groupSelectionIndicator.setImageResource(R.drawable.check_box_outline_blank)
}
groupSelectionIndicator.setOnClickListener {
if (groupItem.selected && isSelectAllChildItems(groupItem.nettests)) {
groupItem.selected = false
for (childItem in groupItem.nettests) {
childItem.selected = false

when(groupItem){
is GroupItem -> {
var convertView = LayoutInflater.from(parent.context).inflate(R.layout.run_tests_group_list_item, parent, false)
convertView.findViewById<TextView>(R.id.group_name).text = groupItem.title
val icon = convertView.findViewById<ImageView>(R.id.group_icon)
icon.setImageResource(groupItem.getDisplayIcon(parent.context))
icon.setColorFilter(groupItem.color)
val groupSelectionIndicator = convertView.findViewById<ImageView>(R.id.group_select_indicator)
val selectedAllBtnStatus = viewModel.selectedAllBtnStatus.getValue()
if (selectedAllBtnStatus == SELECT_ALL) {
groupItem.selected = true
for (childItem in groupItem.nettests) {
childItem.selected = true
}
} else if (selectedAllBtnStatus == SELECT_NONE) {
groupItem.selected = false
for (childItem in groupItem.nettests) {
childItem.selected = false
}
} else if (isSelectAllChildItems(groupItem.nettests)) {
groupItem.selected = true
}
if (isNotSelectedAnyGroupItem(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_NONE)
if (groupItem.selected) {
if (isSelectAllChildItems(groupItem.nettests)) {
groupSelectionIndicator.setImageResource(R.drawable.check_box)
} else {
groupSelectionIndicator.setImageResource(R.drawable.check_box_outline_blank)
}
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
groupSelectionIndicator.setImageResource(R.drawable.check_box_outline_blank)
}
} else {
groupItem.selected = true
for (childItem in groupItem.nettests) {
childItem.selected = true
groupSelectionIndicator.setOnClickListener {
if (groupItem.selected && isSelectAllChildItems(groupItem.nettests)) {
groupItem.selected = false
for (childItem in groupItem.nettests) {
childItem.selected = false
}
if (isNotSelectedAnyGroupItem(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_NONE)
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
}
} else {
groupItem.selected = true
for (childItem in groupItem.nettests) {
childItem.selected = true
}
if (isSelectedAllItems(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_ALL)
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
}
}
notifyDataSetChanged()
}
if (isSelectedAllItems(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_ALL)
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
convertView.findViewById<ImageView>(R.id.group_indicator)?.let { groupIndicator ->
if (isExpanded) {
groupIndicator.setImageResource(R.drawable.expand_less)
} else {
groupIndicator.setImageResource(R.drawable.expand_more)
}
}
return convertView
}
notifyDataSetChanged()
}
convertView.findViewById<ImageView>(R.id.group_indicator)?.let { groupIndicator ->
if (isExpanded) {
groupIndicator.setImageResource(R.drawable.expand_less)
} else {
groupIndicator.setImageResource(R.drawable.expand_more)
else -> {
return LayoutInflater.from(parent.context).inflate(R.layout.run_tests_group_divider, parent, false).apply {
findViewById<TextView>(R.id.name).text = groupItem.toString()
}
}
}
return convertView
}

/**
Expand Down Expand Up @@ -181,27 +197,31 @@ class RunTestsExpandableListViewAdapter(
false -> R.drawable.check_box_outline_blank
}
)
setOnClickListener {
if (childItem.selected) {
childItem.selected = false
if (isNotSelectedAnyChildItems(groupItem.nettests)) {
groupItem.selected = false
}
if (isNotSelectedAnyItems(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_NONE)
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
}
} else {
childItem.selected = true
groupItem.selected = true
if (isSelectedAllItems(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_ALL)
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
when (groupItem) {
is GroupItem -> {
setOnClickListener {
if (childItem.selected) {
childItem.selected = false
if (isNotSelectedAnyChildItems(groupItem.nettests)) {
groupItem.selected = false
}
if (isNotSelectedAnyItems(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_NONE)
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
}
} else {
childItem.selected = true
groupItem.selected = true
if (isSelectedAllItems(groupedListData)) {
viewModel.setSelectedAllBtnStatus(SELECT_ALL)
} else {
viewModel.setSelectedAllBtnStatus(SELECT_SOME)
}
}
notifyDataSetChanged()
}
}
notifyDataSetChanged()
}
}
return convertView
Expand All @@ -218,8 +238,8 @@ class RunTestsExpandableListViewAdapter(
* @param groupItemsList List of GroupItem objects.
* @return True if no group item in the list is selected.
*/
private fun isNotSelectedAnyGroupItem(groupItemsList: List<GroupItem>): Boolean {
for (groupItem in groupItemsList) {
private fun isNotSelectedAnyGroupItem(groupItemsList: List<Any>): Boolean {
for (groupItem in groupItemsList.filterIsInstance<GroupItem>()) {
if (groupItem.selected) {
return false
}
Expand Down Expand Up @@ -257,8 +277,8 @@ class RunTestsExpandableListViewAdapter(
* @param groupItemList List of GroupItem objects.
* @return True if all group items in the list are selected.
*/
private fun isSelectedAllItems(groupItemList: List<GroupItem>?): Boolean {
for (groupItem in groupItemList!!) {
private fun isSelectedAllItems(groupItemList: List<Any>): Boolean {
for (groupItem in groupItemList.filterIsInstance<GroupItem>()) {
if (!groupItem.selected) {
return false
}
Expand All @@ -273,8 +293,8 @@ class RunTestsExpandableListViewAdapter(
* @param groupItemList List of GroupItem objects.
* @return True if no group item in the list is selected.
*/
private fun isNotSelectedAnyItems(groupItemList: List<GroupItem>?): Boolean {
for (groupItem in groupItemList!!) {
private fun isNotSelectedAnyItems(groupItemList: List<Any>): Boolean {
for (groupItem in groupItemList.filterIsInstance<GroupItem>()) {
if (groupItem.selected) {
return false
}
Expand Down
Loading

0 comments on commit 10016f9

Please sign in to comment.