Skip to content

Commit

Permalink
feat (OONI Run v2): Add support for revisions.
Browse files Browse the repository at this point in the history
  • Loading branch information
aanorbel committed Apr 10, 2024
1 parent 50448c9 commit d39b748
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 51 deletions.
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@
android:parentActivityName=".activity.MainActivity"
android:screenOrientation="userPortrait"
android:theme="@style/Theme.MaterialComponents.Light.DarkActionBar.App.NoActionBar" />

<activity
android:name=".activity.overview.RevisionsViewActivity"
android:launchMode="singleTop"
android:parentActivityName=".activity.OverviewActivity"
android:screenOrientation="userPortrait"/>
<activity
android:name=".activity.ResultDetailActivity"
android:launchMode="singleTop"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.openobservatory.ooniprobe.activity.customwebsites.CustomWebsiteActivity;
import org.openobservatory.ooniprobe.activity.overview.OverviewTestsExpandableListViewAdapter;
import org.openobservatory.ooniprobe.activity.overview.OverviewViewModel;
import org.openobservatory.ooniprobe.activity.overview.RevisionsFragment;
import org.openobservatory.ooniprobe.activity.reviewdescriptorupdates.ReviewDescriptorUpdatesActivity;
import org.openobservatory.ooniprobe.common.AbstractDescriptor;
import org.openobservatory.ooniprobe.common.OONITests;
Expand All @@ -48,7 +49,6 @@

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;

Expand Down Expand Up @@ -163,7 +163,16 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
if (descriptor instanceof InstalledDescriptor) {
binding.uninstallLink.setVisibility(View.VISIBLE);
binding.automaticUpdatesContainer.setVisibility(View.VISIBLE);
binding.automaticUpdatesSwitch.setChecked(((InstalledDescriptor) descriptor).getTestDescriptor().isAutoUpdate());
InstalledDescriptor installedDescriptor = (InstalledDescriptor) descriptor;
binding.automaticUpdatesSwitch.setChecked(installedDescriptor.getTestDescriptor().isAutoUpdate());

try {
if (Integer.parseInt(installedDescriptor.getTestDescriptor().getRevision()) > 1) {
getSupportFragmentManager().beginTransaction().add(binding.revisionsContainer.getId(), RevisionsFragment.newInstance(installedDescriptor.getDescriptor().getPreviousRevision())).commit();
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
binding.uninstallLink.setVisibility(View.GONE);
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ class AddDescriptorActivity : AbstractActivity() {
}

binding.btnCancel.setOnClickListener {
Toast.makeText(this@AddDescriptorActivity, "Link installation cancelled", Toast.LENGTH_LONG).show()
finish()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package org.openobservatory.ooniprobe.activity.overview

import android.content.Context
import android.content.Intent
import android.graphics.Paint
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.gson.Gson
import org.openobservatory.engine.OONIRunDescriptor
import org.openobservatory.ooniprobe.R
import org.openobservatory.ooniprobe.activity.AbstractActivity
import org.openobservatory.ooniprobe.activity.reviewdescriptorupdates.DescriptorUpdateFragment
import org.openobservatory.ooniprobe.common.toTestDescriptor
import org.openobservatory.ooniprobe.databinding.FragmentDescriptorUpdateBinding
import org.openobservatory.ooniprobe.databinding.FragmentRevisionsBinding
import org.openobservatory.ooniprobe.databinding.ItemTextBinding
import org.openobservatory.ooniprobe.model.database.TestDescriptor
import java.text.SimpleDateFormat
import java.time.format.DateTimeFormatter
import java.util.Locale


class RevisionsFragment : Fragment() {

companion object {

const val ARG_PREVIOUS_REVISIONS = "previous-revisions"

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param previousRevisions Previous revisions in JSON format.
* @return A new instance of fragment RevisionsFragment.
*/
@JvmStatic
fun newInstance(previousRevisions: String) =
RevisionsFragment().apply {
arguments = Bundle().apply {
putString(ARG_PREVIOUS_REVISIONS, previousRevisions)
}
}
}

private var revisions = emptyList<OONIRunDescriptor>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

arguments?.let {
revisions = Gson().fromJson(
it.getString(ARG_PREVIOUS_REVISIONS), Array<OONIRunDescriptor>::class.java
).toList()
}
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = FragmentRevisionsBinding.inflate(inflater, container, false)

with(binding.list) {
layoutManager = LinearLayoutManager(context)
adapter = RevisionsRecyclerViewAdapter(revisions, object : OnItemClickListener {
override fun onItemClick(position: Int) {
ActivityCompat.startActivity(
requireActivity(),
RevisionsViewActivity.newIntent(
requireContext(),
revisions[position].toTestDescriptor()
),
null
)
}
})
}

return binding.root
}

}

/**
* Interface for handling item clicks in the RecyclerView.
*/
interface OnItemClickListener {
/**
* Called when an item in the RecyclerView is clicked.
*
* @param position The position of the clicked item.
*/
fun onItemClick(position: Int)
}

/**
* RecyclerView adapter for displaying a list of revisions.
*
* @param values The list of revisions to display.
* @param onClickListener The click listener for handling item clicks.
*/
class RevisionsRecyclerViewAdapter(
private val values: List<OONIRunDescriptor>,
private val onClickListener: OnItemClickListener,
) : RecyclerView.Adapter<RevisionsRecyclerViewAdapter.ViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
ItemTextBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = values[position]
holder.binding.root.setPadding(0, 10, 0, 10)
holder.binding.textView.apply {
text = SimpleDateFormat(
"MMMM d, yyyy HH:mm:ss z",
Locale.ENGLISH
).format(item.dateCreated)
setTextColor(
ContextCompat.getColor(holder.binding.root.context, R.color.color_blue6)
)
paintFlags = paintFlags or Paint.UNDERLINE_TEXT_FLAG
setOnClickListener { onClickListener.onItemClick(position) }
}
}

override fun getItemCount(): Int = values.size

inner class ViewHolder(var binding: ItemTextBinding) : RecyclerView.ViewHolder(binding.root)
}

/**
* Activity for displaying a single revision.
*/
class RevisionsViewActivity : AbstractActivity() {

companion object {
private const val ARG_REVISION = "revision"

/**
* Create an intent for starting this activity.
*
* @param context The context from which to create the intent.
* @param revision The revision to display.
* @return The intent for starting this activity.
*/
fun newIntent(context: Context, revision: TestDescriptor) =
Intent(context, RevisionsViewActivity::class.java).putExtra(ARG_REVISION, revision)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = FragmentDescriptorUpdateBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
val descriptorExtra = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(ARG_REVISION, TestDescriptor::class.java)
} else {
intent.getSerializableExtra(ARG_REVISION) as TestDescriptor?
}

supportActionBar?.title = descriptorExtra?.dateCreated?.let { date ->
SimpleDateFormat(
"MMMM d, yyyy HH:mm:ss z",
Locale.ENGLISH
).format(date)
}

descriptorExtra?.let { descriptor ->
binding.testsLabel.text = "TESTS"
DescriptorUpdateFragment.bindData(this@RevisionsViewActivity, descriptor, binding)
.apply {
supportActionBar?.setBackgroundDrawable(ColorDrawable(color))
window.statusBarColor = color
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@ class ReviewDescriptorUpdatesActivity : AbstractActivity() {
if ((currPos + 1) != binding.viewpager.adapter?.itemCount) {
binding.viewpager.currentItem = currPos + 1
} else {
setResult(RESULT_OK, Intent().putExtra(RESULT_MESSAGE, "Link(s) updated"))
setResult(
RESULT_OK,
Intent().putExtra(RESULT_MESSAGE, "Link(s) updated")
)
finish()
}
true
Expand Down Expand Up @@ -201,24 +204,10 @@ private const val DESCRIPTOR = "descriptor"
*/
class DescriptorUpdateFragment : Fragment() {

private lateinit var binding: FragmentDescriptorUpdateBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentDescriptorUpdateBinding.inflate(inflater, container, false)
return binding.root
}
companion object {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
arguments?.takeIf { it.containsKey(DESCRIPTOR) }?.apply {
val descriptor: TestDescriptor =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getSerializable(DESCRIPTOR, TestDescriptor::class.java)!!
} else {
getSerializable(DESCRIPTOR) as TestDescriptor
}
@JvmStatic
fun bindData(context: Context, descriptor: TestDescriptor, binding: FragmentDescriptorUpdateBinding): InstalledDescriptor {
val absDescriptor = InstalledDescriptor(descriptor)
binding.apply {
title.text = absDescriptor.title
Expand All @@ -229,7 +218,7 @@ class DescriptorUpdateFragment : Fragment() {
).format(descriptor.dateCreated)
}"
description.text = absDescriptor.description // Use markdown
icon.setImageResource(absDescriptor.getDisplayIcon(requireContext()))
icon.setImageResource(absDescriptor.getDisplayIcon(context))
val adapter =
ReviewDescriptorExpandableListAdapter(nettests = absDescriptor.nettests)
expandableListView.setAdapter(adapter)
Expand All @@ -238,6 +227,30 @@ class DescriptorUpdateFragment : Fragment() {
expandableListView.expandGroup(i)
}
}
return absDescriptor
}
}

private lateinit var binding: FragmentDescriptorUpdateBinding

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentDescriptorUpdateBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
arguments?.takeIf { it.containsKey(DESCRIPTOR) }?.apply {
val descriptor: TestDescriptor =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getSerializable(DESCRIPTOR, TestDescriptor::class.java)!!
} else {
getSerializable(DESCRIPTOR) as TestDescriptor
}
bindData(requireContext(), descriptor, binding)
}
}
}
Expand Down
Loading

0 comments on commit d39b748

Please sign in to comment.