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

[New Designs] Update Chose websites view #630

Merged
merged 13 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@
android:label="@string/Settings_Websites_CustomURL_Title"
android:exported="false"
android:parentActivityName=".activity.PreferenceActivity"
android:screenOrientation="userPortrait">
android:screenOrientation="userPortrait"
android:theme="@style/Theme.MaterialComponents.Light.DarkActionBar.App.NoActionBar">
<intent-filter>
<action android:name="${applicationId}.activity.CustomWebsiteActivity" />

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.openobservatory.ooniprobe.activity

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 android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import org.openobservatory.ooniprobe.fragment.ConfirmDialogFragment
import org.openobservatory.ooniprobe.R
import org.openobservatory.ooniprobe.adapters.CustomWebsiteRecyclerViewAdapter
import org.openobservatory.ooniprobe.adapters.ItemRemovedListener
import org.openobservatory.ooniprobe.common.PreferenceManager
import org.openobservatory.ooniprobe.databinding.ActivityCustomwebsiteBinding
import org.openobservatory.ooniprobe.model.database.Url
import org.openobservatory.ooniprobe.test.suite.WebsitesSuite
import java.io.Serializable
import javax.inject.Inject

class CustomWebsiteActivity : AbstractActivity(), ConfirmDialogFragment.OnClickListener {
@Inject
lateinit var preferenceManager: PreferenceManager
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(object : ItemRemovedListener {
override fun onItemRemoved(position: Int) {
binding.bottomBar.title = getString(
R.string.OONIRun_URLs, adapter.itemCount.toString()
)
}
})
binding.bottomBar.setOnMenuItemClickListener { item: MenuItem? ->
val items = adapter.getItems()
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
)
true
}
binding.add.setOnClickListener { add() }

binding.urlContainer.adapter = adapter
add()
// TODO(aanorbel): Fix: Configuration change triggers loss of data.
aanorbel marked this conversation as resolved.
Show resolved Hide resolved
}

override fun onBackPressed() {
val base = getString(R.string.http)
val edited = adapter.itemCount > 0 && adapter.getItems()[0] != base
if (edited) {
ConfirmDialogFragment(
title = "Are you sure?",
message = "Your URLs will not be saved when you leave this screen. Are you sure you want to do that?",
).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)
}
}

fun add() {
adapter.addAll(listOf(getString(R.string.http)))
binding.bottomBar.title = getString(
R.string.OONIRun_URLs, adapter.itemCount.toString()
)
adapter.notifyDataSetChanged()
scrollToBottom()
}

private fun scrollToBottom() {
binding.urlContainer.scrollToPosition(adapter.itemCount - 1)
binding.urlsList.post { binding.urlsList.fullScroll(View.FOCUS_DOWN) }
}

override fun onConfirmDialogClick(
serializable: Serializable?, parcelable: Parcelable?, buttonClicked: Int
) {
if (buttonClicked == DialogInterface.BUTTON_POSITIVE) super.onBackPressed()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.openobservatory.ooniprobe.adapters

import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.openobservatory.ooniprobe.databinding.EdittextUrlBinding
import java.lang.Boolean.TRUE


class CustomWebsiteRecyclerViewAdapter(private val onItemRemovedListener: ItemRemovedListener) :
RecyclerView.Adapter<CustomWebsiteRecyclerViewAdapter.ViewHolder>() {
private val mItems: MutableList<String>
private val mVisibility: MutableList<Boolean>

/**
* Initialize the dataset of the Adapter.
*/
init {
mItems = ArrayList()
mVisibility = ArrayList()
}

fun addAll(items: List<String>?) {
mItems.addAll(items ?: listOf())
mVisibility.addAll(mItems.map { TRUE })
mVisibility[0] = mItems.size > 1
}

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

override fun onBindViewHolder(
holder: ViewHolder, position: Int
) {
holder.binding.editText.setText(mItems[position])
holder.binding.delete.visibility =
if (mVisibility[position]) View.VISIBLE else View.INVISIBLE
holder.binding.delete.setOnClickListener {
mItems.removeAt(holder.adapterPosition)
mVisibility.removeAt(holder.adapterPosition)
mVisibility[0] = mItems.size > 1
notifyDataSetChanged()
onItemRemovedListener.onItemRemoved(holder.adapterPosition)
}
holder.binding.editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
mItems[holder.adapterPosition] = charSequence.toString()
}

override fun afterTextChanged(editable: Editable) {}
})
}

override fun getItemCount(): Int = mItems.size
fun getItems(): List<String> = mItems

class ViewHolder(val binding: EdittextUrlBinding) : RecyclerView.ViewHolder(binding.root)
}

interface ItemRemovedListener {
fun onItemRemoved(position: Int)
}
Loading
Loading