-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[New Designs] Update Chose websites view (#630)
Fixes ooni/probe#2592 ## Proposed Changes - Updated `CustomWebsiteActivity` to use new theme. - Change List item builder to use `RecyclerView`. Tasks - [x] Implement designs on light theme. - [x] Convert list item builder to use `RecyclerView`. - [x] Fix dark theme - [x] Implement modal properly | Light | Dark| |-|-| |![Screenshot_20231104_110235](https://github.com/ooni/probe-android/assets/17911892/b4c8dca7-2c6a-4d55-9df4-f194a67b98a6))| ![Screenshot_20231104_110254](https://github.com/ooni/probe-android/assets/17911892/60ade191-40bb-4b0b-a5fa-aa93540bd112) | |![Screenshot_20231104_110336](https://github.com/ooni/probe-android/assets/17911892/2df8c97a-23ff-4771-970b-59044de00386)| ![Screenshot_20231104_110407](https://github.com/ooni/probe-android/assets/17911892/291af536-72e3-4774-a5ca-8301334543a0) | | ![Screenshot_20231104_110429](https://github.com/ooni/probe-android/assets/17911892/a7423372-5acd-45b8-aa0a-ae2ef4e4b62c) | ![Screenshot_20231104_110441](https://github.com/ooni/probe-android/assets/17911892/15047e19-9c3e-4cbe-a1c1-ceaa8783da8a) | --------- Co-authored-by: Simone Basso <bassosimone@gmail.com>
- Loading branch information
1 parent
5aac551
commit 706eef1
Showing
15 changed files
with
488 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 0 additions & 124 deletions
124
app/src/main/java/org/openobservatory/ooniprobe/activity/CustomWebsiteActivity.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
.../main/java/org/openobservatory/ooniprobe/activity/customwebsites/CustomWebsiteActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package org.openobservatory.ooniprobe.activity.customwebsites | ||
|
||
import android.content.DialogInterface | ||
import android.os.Bundle | ||
import android.os.Parcelable | ||
import android.util.Patterns | ||
import android.view.Menu | ||
import android.view.MenuInflater | ||
import android.view.MenuItem | ||
import androidx.activity.viewModels | ||
import androidx.recyclerview.widget.LinearLayoutManager | ||
import org.openobservatory.ooniprobe.R | ||
import org.openobservatory.ooniprobe.activity.AbstractActivity | ||
import org.openobservatory.ooniprobe.activity.RunningActivity | ||
import org.openobservatory.ooniprobe.activity.customwebsites.adapter.CustomWebsiteRecyclerViewAdapter | ||
import org.openobservatory.ooniprobe.activity.customwebsites.adapter.ItemChangedListener | ||
import org.openobservatory.ooniprobe.common.PreferenceManager | ||
import org.openobservatory.ooniprobe.databinding.ActivityCustomwebsiteBinding | ||
import org.openobservatory.ooniprobe.fragment.ConfirmDialogFragment | ||
import org.openobservatory.ooniprobe.model.database.Url | ||
import org.openobservatory.ooniprobe.test.suite.WebsitesSuite | ||
import java.io.Serializable | ||
import javax.inject.Inject | ||
|
||
/** This activity allows a user to test a custom website. */ | ||
class CustomWebsiteActivity : AbstractActivity(), ConfirmDialogFragment.OnClickListener { | ||
@Inject | ||
lateinit var preferenceManager: PreferenceManager | ||
|
||
val viewModel: CustomWebsiteViewModel by viewModels() | ||
|
||
private lateinit var adapter: CustomWebsiteRecyclerViewAdapter | ||
private lateinit var binding: ActivityCustomwebsiteBinding | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
activityComponent.inject(this) | ||
binding = ActivityCustomwebsiteBinding.inflate( | ||
layoutInflater | ||
) | ||
setContentView(binding.root) | ||
setSupportActionBar(binding.toolbar) | ||
supportActionBar?.setDisplayHomeAsUpEnabled(true) | ||
val layoutManager = LinearLayoutManager(this) | ||
binding.urlContainer.layoutManager = layoutManager | ||
adapter = CustomWebsiteRecyclerViewAdapter( | ||
onItemChangedListener = object : ItemChangedListener { | ||
override fun onItemRemoved(position: Int) { | ||
binding.bottomBar.title = getString( | ||
R.string.OONIRun_URLs, adapter.itemCount.toString() | ||
) | ||
viewModel.onItemRemoved(position) | ||
} | ||
|
||
override fun onItemUpdated(position: Int, item: String) { | ||
viewModel.updateUrlAt(position, item) | ||
} | ||
}, | ||
) | ||
viewModel.urls.observe(this) { urls -> | ||
binding.bottomBar.title = getString( | ||
R.string.OONIRun_URLs, urls.size.toString() | ||
) | ||
} | ||
|
||
binding.bottomBar.setOnMenuItemClickListener { item: MenuItem? -> runTests() } | ||
binding.add.setOnClickListener { add() } | ||
|
||
binding.urlContainer.adapter = adapter | ||
if (viewModel.urls.value == null) { | ||
add() | ||
} | ||
} | ||
|
||
override fun onResume() { | ||
super.onResume() | ||
viewModel.urls.value?.let { urls -> | ||
adapter.submitList(urls) | ||
binding.urlContainer.post { adapter.notifyDataSetChanged() } | ||
} | ||
} | ||
|
||
/** | ||
* This function will run the tests if the list of urls is not empty. | ||
* If the list is empty, it will not run the tests. | ||
* This function will also sanitize the url and remove any new lines. | ||
* It will also check if the url is valid and not too long. | ||
* If the url is not valid or too long, it will not be added to the tests. | ||
*/ | ||
private fun runTests(): Boolean { | ||
val items = viewModel.urls.value ?: listOf() | ||
if (items.isEmpty()) { | ||
return false | ||
} | ||
val urls = ArrayList<String>(items.size) | ||
for (value in items) { | ||
val sanitizedUrl = value.replace("\\r\\n|\\r|\\n".toRegex(), " ") | ||
//https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer | ||
if (Patterns.WEB_URL.matcher(sanitizedUrl) | ||
.matches() && sanitizedUrl.length < 2084 | ||
) urls.add( | ||
Url.checkExistingUrl(sanitizedUrl).toString() | ||
) | ||
} | ||
val suite = WebsitesSuite() | ||
suite.getTestList(preferenceManager)[0].inputs = urls | ||
RunningActivity.runAsForegroundService( | ||
this@CustomWebsiteActivity, suite.asArray(), { finish() }, preferenceManager | ||
) | ||
return true | ||
} | ||
|
||
/** | ||
* This function will show a dialog if the user has edited the list of urls. | ||
* If the user has edited the list of urls, it will show a dialog asking if the user wants to save the changes. | ||
* If the user has not edited the list of urls, it will just call super.onBackPressed() | ||
*/ | ||
override fun onBackPressed() { | ||
val base = getString(R.string.http) | ||
val edited = adapter.itemCount > 0 && viewModel.urls.value?.get(0) != base | ||
if (edited) { | ||
ConfirmDialogFragment( | ||
title = getString(R.string.Modal_CustomURL_Title_NotSaved), | ||
message = getString(R.string.Modal_CustomURL_NotSaved), | ||
).show(supportFragmentManager, null) | ||
} else { | ||
super.onBackPressed() | ||
} | ||
} | ||
|
||
override fun onSupportNavigateUp(): Boolean { | ||
onBackPressed() | ||
return true | ||
} | ||
|
||
override fun onCreateOptionsMenu(menu: Menu): Boolean { | ||
val inflater: MenuInflater = menuInflater | ||
inflater.inflate(R.menu.close, menu) | ||
return true | ||
} | ||
|
||
override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||
return when (item.itemId) { | ||
R.id.close_button -> { | ||
onSupportNavigateUp() | ||
true | ||
} | ||
|
||
else -> super.onOptionsItemSelected(item) | ||
} | ||
} | ||
|
||
/** | ||
* This function will add a new url to the list of urls. | ||
* It will also scroll to the bottom of the list. | ||
*/ | ||
fun add() { | ||
viewModel.addUrl(getString(R.string.http)) | ||
binding.urlContainer.layoutManager?.scrollToPosition(adapter.itemCount - 1) | ||
} | ||
|
||
/** | ||
* This function will be called when the user clicks on a button in the dialog. | ||
* If the user clicks on the positive button, it will call super.onBackPressed() | ||
*/ | ||
override fun onConfirmDialogClick( | ||
serializable: Serializable?, parcelable: Parcelable?, buttonClicked: Int | ||
) { | ||
if (buttonClicked == DialogInterface.BUTTON_POSITIVE) super.onBackPressed() | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
...main/java/org/openobservatory/ooniprobe/activity/customwebsites/CustomWebsiteViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package org.openobservatory.ooniprobe.activity.customwebsites | ||
|
||
import androidx.lifecycle.MutableLiveData | ||
import androidx.lifecycle.ViewModel | ||
|
||
/** | ||
* This class is used to store the data for the CustomWebsiteActivity. | ||
* The data is stored in a ViewModel so that it can survive configuration changes (like rotation). | ||
* This class shound not be injected to the activity using a DI framework. | ||
* Dagger forces the recreation of the [ViewModel] on configuration | ||
* as oposed to using `by viewModels()` which remembers the last state. | ||
*/ | ||
class CustomWebsiteViewModel : ViewModel() { | ||
|
||
val urls = MutableLiveData<MutableList<String>>() | ||
|
||
/** | ||
* This function will add a new url to the list of urls. | ||
* If the list is null, it will create a new list. | ||
*/ | ||
fun addUrl(url: String) { | ||
val currentUrls = urls.value ?: ArrayList() | ||
currentUrls.add(url) | ||
urls.value = currentUrls | ||
} | ||
|
||
/** | ||
* This function will remove a url from the list of urls. | ||
* If the list is null, it will not do anything. | ||
*/ | ||
fun onItemRemoved(position: Int) { | ||
val currentList = urls.value ?: mutableListOf() | ||
if (position < currentList.size) { | ||
currentList.removeAt(position) | ||
urls.value = currentList | ||
} | ||
} | ||
|
||
/** | ||
* This function will update the url at the given position. | ||
* If the list is null, it will not do anything. | ||
*/ | ||
fun updateUrlAt(position: Int, newUrl: String) { | ||
val currentList = urls.value ?: mutableListOf() | ||
if (position < currentList.size) { | ||
currentList[position] = newUrl | ||
urls.value = currentList | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.