Skip to content

Commit

Permalink
Updated checkbox for preference
Browse files Browse the repository at this point in the history
  • Loading branch information
aanorbel committed Nov 27, 2023
1 parent 940bdc1 commit c3dc5c0
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 209 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package org.openobservatory.ooniprobe.activity;

import static org.openobservatory.ooniprobe.activity.overview.OverviewViewModel.SELECT_ALL;
import static org.openobservatory.ooniprobe.activity.overview.OverviewViewModel.SELECT_NONE;
import static org.openobservatory.ooniprobe.activity.overview.OverviewViewModel.SELECT_SOME;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.View;
import android.view.Window;
Expand All @@ -12,6 +17,8 @@
import androidx.core.text.TextUtilsCompat;
import androidx.core.view.ViewCompat;

import com.google.android.material.checkbox.MaterialCheckBox;

import org.openobservatory.engine.BaseNettest;
import org.openobservatory.ooniprobe.R;
import org.openobservatory.ooniprobe.activity.overview.OverviewTestsExpandableListViewAdapter;
Expand Down Expand Up @@ -40,6 +47,8 @@ public class OverviewActivity extends AbstractActivity {
@Inject
OverviewViewModel viewModel;

OverviewTestsExpandableListViewAdapter adapter;

private OONIDescriptor<BaseNettest> descriptor;

public static Intent newIntent(Context context, OONIDescriptor<BaseNettest> descriptor) {
Expand Down Expand Up @@ -76,8 +85,35 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
binding.lastTime.setText(DateUtils.getRelativeTimeSpanString(lastResult.start_time.getTime()));
}

OverviewTestsExpandableListViewAdapter adapter = new OverviewTestsExpandableListViewAdapter(descriptor.getOverviewExpandableListViewData());
adapter = new OverviewTestsExpandableListViewAdapter(descriptor.overviewExpandableListViewData(preferenceManager), viewModel);
binding.expandableListView.setAdapter(adapter);

viewModel.getSelectedAllBtnStatus().observe(this, this::selectAllBtnStatusObserver);
binding.switchTests.addOnCheckedStateChangedListener((checkBox, state) -> {
switch (state) {
case MaterialCheckBox.STATE_CHECKED -> {
viewModel.setSelectedAllBtnStatus(SELECT_ALL);
adapter.notifyDataSetChanged();
}
case MaterialCheckBox.STATE_UNCHECKED -> {
viewModel.setSelectedAllBtnStatus(SELECT_NONE);
adapter.notifyDataSetChanged();
}
case MaterialCheckBox.STATE_INDETERMINATE -> {
viewModel.setSelectedAllBtnStatus(SELECT_SOME);
adapter.notifyDataSetChanged();
}
}
});

if (adapter.isSelectedAllItems()) {
binding.switchTests.setCheckedState(MaterialCheckBox.STATE_CHECKED);
} else if (adapter.isNotSelectedAnyGroupItem()) {
binding.switchTests.setCheckedState(MaterialCheckBox.STATE_UNCHECKED);
} else {
binding.switchTests.setCheckedState(MaterialCheckBox.STATE_INDETERMINATE);
}
binding.switchTests.setEnabled(descriptor.hasPreferencePrefix());
// Expand all groups
for (int i = 0; i < adapter.getGroupCount(); i++) {
binding.expandableListView.expandGroup(i);
Expand All @@ -86,6 +122,23 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
setUpOnCLickListeners();
}

private void selectAllBtnStatusObserver(String selectAllBtnStatus) {
if (!TextUtils.isEmpty(selectAllBtnStatus)) {
switch (selectAllBtnStatus) {
case SELECT_ALL -> {
binding.switchTests.setCheckedState(MaterialCheckBox.STATE_CHECKED);
}
case SELECT_NONE -> {
binding.switchTests.setCheckedState(MaterialCheckBox.STATE_UNCHECKED);
}
case SELECT_SOME -> {
binding.switchTests.setCheckedState(MaterialCheckBox.STATE_INDETERMINATE);
}
}
adapter.notifyDataSetChanged();
}
}

public void setThemeColor(int color) {
Window window = getWindow();
window.setStatusBarColor(color);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import android.view.ViewGroup
import android.widget.BaseExpandableListAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.SwitchCompat
import com.google.android.material.checkbox.MaterialCheckBox
import org.openobservatory.ooniprobe.R
import org.openobservatory.ooniprobe.common.OONITests
import org.openobservatory.ooniprobe.test.test.AbstractTest

class OverviewTestsExpandableListViewAdapter(
private val items: List<TestGroupItem>,
private val viewModel: OverviewViewModel,
) : BaseExpandableListAdapter() {

private val selectedGroups = HashSet<Int>()

override fun getGroupCount(): Int = items.size

override fun getChildrenCount(groupPosition: Int): Int = items[groupPosition].inputs?.size ?: 0
Expand All @@ -39,21 +40,68 @@ class OverviewTestsExpandableListViewAdapter(
val view = convertView ?: LayoutInflater.from(parent.context)
.inflate(R.layout.overview_test_group_list_item, parent, false)
val groupItem = getGroup(groupPosition)
val groupTextView: TextView = view.findViewById(R.id.group_name)
val groupIndicator = view.findViewById<ImageView>(R.id.group_indicator)

groupTextView.text = groupItem.name
when (viewModel.descriptor.value?.name) {
OONITests.EXPERIMENTAL.label -> {
view.findViewById<TextView>(R.id.group_name).text = groupItem.name
}

else -> {
val testSuite = AbstractTest.getTestByName(groupItem.name)
view.findViewById<TextView>(R.id.group_name).text =
parent.context.resources.getText(testSuite.labelResId)
when(testSuite.iconResId){
0 -> view.findViewById<ImageView>(R.id.group_icon).visibility = View.GONE
else -> {
view.findViewById<ImageView>(R.id.group_icon).apply {
visibility = View.VISIBLE
setImageResource(testSuite.iconResId)
}
}
}
}
}

val groupCheckBox = view.findViewById<MaterialCheckBox>(R.id.groupCheckBox)

val groupCheckBox: SwitchCompat = view.findViewById(R.id.groupCheckBox)
groupCheckBox.isChecked = selectedGroups.contains(groupPosition)
val selectedAllBtnStatus = viewModel.selectedAllBtnStatus.value
if (selectedAllBtnStatus == OverviewViewModel.SELECT_ALL) {
groupItem.selected = true
} else if (selectedAllBtnStatus == OverviewViewModel.SELECT_NONE) {
groupItem.selected = false
}

groupCheckBox.setOnClickListener {
if (groupCheckBox.isChecked) {
selectedGroups.add(groupPosition)
if (groupItem.selected) {
groupItem.selected = false
viewModel.disableTest(groupItem.name)
notifyDataSetChanged()
if (isNotSelectedAnyGroupItem()) {
viewModel.setSelectedAllBtnStatus(OverviewViewModel.SELECT_NONE)
} else {
viewModel.setSelectedAllBtnStatus(OverviewViewModel.SELECT_SOME)
}
} else {
selectedGroups.remove(groupPosition)
groupItem.selected = true
viewModel.enableTest(groupItem.name)
notifyDataSetChanged()

if (isSelectedAllItems()) {
viewModel.setSelectedAllBtnStatus(OverviewViewModel.SELECT_ALL)
} else {
viewModel.setSelectedAllBtnStatus(OverviewViewModel.SELECT_SOME)
}
}
}

groupCheckBox.isChecked = groupItem.selected
// Disable experimental or webconnectivity test
viewModel.descriptor.value?.run {
groupCheckBox.isEnabled = hasPreferencePrefix()
}


if (groupItem.inputs?.isNotEmpty() == true) {
if (isExpanded) {
groupIndicator.setImageResource(R.drawable.expand_less)
Expand Down Expand Up @@ -88,7 +136,21 @@ class OverviewTestsExpandableListViewAdapter(
return true
}

fun getSelectedGroups(): Set<Int> {
return selectedGroups
fun isNotSelectedAnyGroupItem(): Boolean {
for (groupItem in items) {
if (groupItem.selected) {
return false
}
}
return true
}

fun isSelectedAllItems(): Boolean {
for (groupItem in items) {
if (!groupItem.selected) {
return false
}
}
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import org.openobservatory.engine.BaseNettest
import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel
import org.openobservatory.ooniprobe.common.OONIDescriptor
import org.openobservatory.ooniprobe.common.PreferenceManager
import org.openobservatory.ooniprobe.common.disableTest
import org.openobservatory.ooniprobe.common.enableTest
import javax.inject.Inject

class TestGroupItem(
Expand Down Expand Up @@ -33,15 +35,40 @@ class OverviewViewModel() : ViewModel() {
selectedAllBtnStatus.postValue(selectedStatus)
when (selectedStatus) {
SELECT_ALL -> {
// enableTest(testName)
descriptor.value?.nettests?.forEach {
enableTest(it.name)
}
}

SELECT_NONE -> {
// disableTest(testName)
descriptor.value?.nettests?.forEach {
disableTest(it.name)
}
}
}
}

fun disableTest(name: String) {
descriptor.value?.let {
preferenceManager.disableTest(
name = name,
prefix = it.preferencePrefix(),
autoRun = true
)
}
}

fun enableTest(name: String) {
descriptor.value?.let {
preferenceManager.enableTest(
name = name,
prefix = it.preferencePrefix(),
autoRun = true
)
}
}


fun updateDescriptor(descriptor: OONIDescriptor<BaseNettest>) {
this.descriptor.postValue(descriptor)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import org.openobservatory.engine.BaseDescriptor
import org.openobservatory.engine.BaseNettest
import org.openobservatory.ooniprobe.R
import org.openobservatory.ooniprobe.activity.overview.TestGroupItem
import org.openobservatory.ooniprobe.activity.runtests.RunTestsActivity
import org.openobservatory.ooniprobe.activity.runtests.models.ChildItem
import org.openobservatory.ooniprobe.activity.runtests.models.GroupItem
import org.openobservatory.ooniprobe.test.suite.AbstractSuite
import org.openobservatory.ooniprobe.test.suite.DynamicTestSuite
import org.openobservatory.ooniprobe.test.test.*
import java.io.Serializable
Expand All @@ -29,9 +27,6 @@ open class OONIDescriptor<T : BaseNettest>(
var longRunningTests: List<T>? = null
) : Serializable, BaseDescriptor<T>(name = name, nettests = nettests) {

val overviewExpandableListViewData: MutableList<TestGroupItem> =
nettests.map { TestGroupItem(false, it.name, it.inputs) }.toMutableList()

/**
* Checks if any of the nettests are enabled based on the preferences stored in the provided [PreferenceManager].
*
Expand All @@ -42,7 +37,7 @@ open class OONIDescriptor<T : BaseNettest>(
return nettests.any {
preferenceManager.resolveStatus(
name = it.name,
prefix = preferencePrefix()
prefix = preferencePrefix(),
)
}
}
Expand All @@ -57,7 +52,29 @@ open class OONIDescriptor<T : BaseNettest>(
}

/**
* Converts the current descriptor to a [GroupItem] to be used in the [RunTestsActivity].
* Converts the current [MutableList] of [TestGroupItem] representing `tests` to be used in the [OverviewActivity].
*
* @return [MutableList] of [TestGroupItem] representing `tests`.
*/
fun overviewExpandableListViewData(preferenceManager: PreferenceManager): MutableList<TestGroupItem> =
(nettests + longRunningTests.orEmpty()).map {
TestGroupItem(
selected = when (name) {
OONITests.EXPERIMENTAL.label -> preferenceManager.isExperimentalOn
OONITests.WEBSITES.label -> preferenceManager.countEnabledCategory() > 0
else -> preferenceManager.resolveStatus(
name = it.name,
prefix = preferencePrefix(),
autoRun = true,
)
},
name = it.name,
inputs = it.inputs,
)
}.toMutableList()

/**
* Converts the current descriptor to a [GroupItem] to be used in the [].
*
* @return [GroupItem] representing the current descriptor.
*/
Expand All @@ -73,11 +90,23 @@ open class OONIDescriptor<T : BaseNettest>(
dataUsage = this.dataUsage,
nettests = this.nettests.map { nettest ->
ChildItem(
selected = when (this.name == OONITests.EXPERIMENTAL.label) {
true -> preferenceManager.isExperimentalOn
false -> preferenceManager.resolveStatus(nettest.name)
selected = when (name) {
OONITests.EXPERIMENTAL.label -> preferenceManager.isExperimentalOn
OONITests.WEBSITES.label -> preferenceManager.countEnabledCategory() > 0
else -> preferenceManager.resolveStatus(
name = nettest.name,
prefix = preferencePrefix(),
)
}, name = nettest.name, inputs = nettest.inputs
)
}.run {
this + (longRunningTests?.map { nettest ->
ChildItem(
selected = false,
name = nettest.name,
inputs = nettest.inputs,
)
} ?: listOf())
})
}

Expand Down Expand Up @@ -119,9 +148,20 @@ open class OONIDescriptor<T : BaseNettest>(
*
* @return String representing the preference prefix.
*/
private fun preferencePrefix(): String {
fun preferencePrefix(): String {
return OONITests.values().find { it.label == name }?.let { "" } ?: "descriptor_id_"
}

/**
* Checks if the current descriptor has a preference prefix.
* This is used to determine if the current descriptor is [OONITests.WEBSITES] which uses categories
* or [OONITests.EXPERIMENTAL] which doesn't support indivitual preferences for nettest.
*
* @return Boolean Returns true if the current descriptor has a preference prefix, false otherwise.
*/
fun hasPreferencePrefix(): Boolean {
return !(name == OONITests.EXPERIMENTAL.label || name == OONITests.WEBSITES.label)
}
}

/**
Expand Down Expand Up @@ -264,7 +304,7 @@ enum class OONITests(
description = when (label) {
EXPERIMENTAL.label -> context.getString(
description,
experimentalLinks
experimentalLinks,
)

else -> context.getString(description)
Expand Down
Loading

0 comments on commit c3dc5c0

Please sign in to comment.