mirror of
https://github.com/karasevm/PrivateDNSAndroid.git
synced 2025-06-28 12:19:57 +00:00
Option to edit the server (#29)
* Option to edit the server * Empty List of Severs notified
This commit is contained in:
parent
5fe2354e7d
commit
470f8445f9
8 changed files with 129 additions and 30 deletions
2
.idea/vcs.xml
generated
2
.idea/vcs.xml
generated
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -14,7 +14,7 @@ import com.google.common.net.InternetDomainName
|
|||
import ru.karasevm.privatednstoggle.databinding.DialogAddBinding
|
||||
|
||||
|
||||
class AddServerDialogFragment : DialogFragment() {
|
||||
class AddServerDialogFragment(private val position: Int?, private val label: String?, private val server: String?) : DialogFragment() {
|
||||
// Use this instance of the interface to deliver action events
|
||||
private lateinit var listener: NoticeDialogListener
|
||||
|
||||
|
@ -29,6 +29,8 @@ class AddServerDialogFragment : DialogFragment() {
|
|||
* Each method passes the DialogFragment in case the host needs to query it. */
|
||||
interface NoticeDialogListener {
|
||||
fun onDialogPositiveClick(label: String? ,server: String)
|
||||
fun onDialogPositiveClick(label: String?, server: String, position: Int)
|
||||
fun onDeleteItemClicked(position: Int)
|
||||
}
|
||||
|
||||
// Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
|
||||
|
@ -59,22 +61,47 @@ class AddServerDialogFragment : DialogFragment() {
|
|||
val view = binding.root
|
||||
// Inflate and set the layout for the dialog
|
||||
// Pass null as the parent view because its going in the dialog layout
|
||||
builder.setTitle(R.string.add_server)
|
||||
.setView(view)
|
||||
// Add action buttons
|
||||
.setPositiveButton(
|
||||
R.string.menu_add
|
||||
) { _, _ ->
|
||||
listener.onDialogPositiveClick(
|
||||
binding.editTextServerHint.text.toString().trim(),
|
||||
binding.editTextServerAddr.text.toString().trim()
|
||||
)
|
||||
}
|
||||
.setNegativeButton(
|
||||
R.string.cancel
|
||||
) { _, _ ->
|
||||
dialog?.cancel()
|
||||
}
|
||||
if (position != null) {
|
||||
binding.editTextServerHint.setText(label)
|
||||
binding.editTextServerAddr.setText(server)
|
||||
builder.setTitle(R.string.edit_server).setView(view)
|
||||
.setPositiveButton(
|
||||
R.string.menu_save
|
||||
) { _, _ ->
|
||||
listener.onDialogPositiveClick(
|
||||
binding.editTextServerHint.text.toString().trim(),
|
||||
binding.editTextServerAddr.text.toString().trim(),
|
||||
position)
|
||||
}
|
||||
.setNegativeButton(
|
||||
R.string.cancel
|
||||
) { _, _ ->
|
||||
dialog?.cancel()
|
||||
}
|
||||
.setNeutralButton(
|
||||
R.string.delete
|
||||
) { _, _ ->
|
||||
listener.onDeleteItemClicked(position)
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.setTitle(R.string.add_server)
|
||||
.setView(view)
|
||||
// Add action buttons
|
||||
.setPositiveButton(
|
||||
R.string.menu_add
|
||||
) { _, _ ->
|
||||
listener.onDialogPositiveClick(
|
||||
binding.editTextServerHint.text.toString().trim(),
|
||||
binding.editTextServerAddr.text.toString().trim()
|
||||
)
|
||||
}
|
||||
.setNegativeButton(
|
||||
R.string.cancel
|
||||
) { _, _ ->
|
||||
dialog?.cancel()
|
||||
}
|
||||
}
|
||||
builder.create()
|
||||
} ?: throw IllegalStateException("Activity cannot be null")
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class DNSServerDialogFragment : DialogFragment() {
|
|||
items.add(0, resources.getString(R.string.dns_auto))
|
||||
items.add(0, resources.getString(R.string.dns_off))
|
||||
|
||||
adapter = RecyclerAdapter(items, false)
|
||||
adapter = RecyclerAdapter(items, false) {}
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package ru.karasevm.privatednstoggle
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.ClipDescription.MIMETYPE_TEXT_PLAIN
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.IPackageManager
|
||||
|
@ -17,6 +15,7 @@ import android.os.Bundle
|
|||
import android.permission.IPermissionManager
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
@ -139,27 +138,41 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
|||
binding.recyclerView.layoutManager = linearLayoutManager
|
||||
|
||||
sharedPrefs = PreferenceHelper.defaultPreference(this)
|
||||
clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
gson = GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create()
|
||||
|
||||
items = sharedPrefs.dns_servers
|
||||
if (items[0] == "") {
|
||||
items.removeAt(0)
|
||||
}
|
||||
adapter = RecyclerAdapter(items, true)
|
||||
|
||||
updateEmptyView()
|
||||
adapter = RecyclerAdapter(items, true) { updateEmptyView() }
|
||||
adapter.onItemClick = { position ->
|
||||
val newFragment = DeleteServerDialogFragment(position)
|
||||
newFragment.show(supportFragmentManager, "delete_server")
|
||||
val data = items[position].split(" : ")
|
||||
val label: String?
|
||||
val server: String
|
||||
if (data.size == 2) {
|
||||
label = data[0]
|
||||
server = data[1]
|
||||
}
|
||||
else {
|
||||
label = null
|
||||
server = data[0]
|
||||
}
|
||||
val newFragment = AddServerDialogFragment(position, label, server)
|
||||
newFragment.show(supportFragmentManager, "edit_server")
|
||||
}
|
||||
adapter.onItemsChanged = { swappedItems ->
|
||||
items = swappedItems
|
||||
sharedPrefs.dns_servers = swappedItems
|
||||
updateEmptyView()
|
||||
}
|
||||
adapter.onDragStart = { viewHolder ->
|
||||
itemTouchHelper.startDrag(viewHolder)
|
||||
}
|
||||
binding.floatingActionButton.setOnClickListener {
|
||||
val newFragment = AddServerDialogFragment()
|
||||
val newFragment = AddServerDialogFragment(null, null, null)
|
||||
newFragment.show(supportFragmentManager, "add_server")
|
||||
}
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
@ -235,9 +248,19 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateEmptyView() {
|
||||
if (items.isEmpty()) {
|
||||
binding.emptyView.visibility = View.VISIBLE
|
||||
binding.emptyViewHint.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.emptyView.visibility = View.GONE
|
||||
binding.emptyViewHint.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private var saveResultLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
val data: Intent? = result.data
|
||||
data?.data?.also { uri ->
|
||||
val jsonData = gson.toJson(sharedPrefs.export())
|
||||
|
@ -262,7 +285,7 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
|||
|
||||
private var importResultLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
val data: Intent? = result.data
|
||||
data?.data?.also { uri ->
|
||||
val contentResolver = applicationContext.contentResolver
|
||||
|
@ -336,6 +359,11 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
|||
Shizuku.removeRequestPermissionResultListener(this::onRequestPermissionResult)
|
||||
}
|
||||
|
||||
override fun onDeleteItemClicked(position: Int) {
|
||||
val newFragment = DeleteServerDialogFragment(position)
|
||||
newFragment.show(supportFragmentManager, "delete_server")
|
||||
}
|
||||
|
||||
override fun onDialogPositiveClick(label: String?, server: String) {
|
||||
if (server.isEmpty()) {
|
||||
Toast.makeText(this, R.string.server_length_error, Toast.LENGTH_SHORT).show()
|
||||
|
@ -358,6 +386,21 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
|||
sharedPrefs.dns_servers = items
|
||||
}
|
||||
|
||||
override fun onDialogPositiveClick(label: String?, server: String, position: Int) {
|
||||
if (server.isEmpty()) {
|
||||
Toast.makeText(this, R.string.server_length_error, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
if (label.isNullOrEmpty()) {
|
||||
items[position] = server
|
||||
} else {
|
||||
items[position] = "$label : $server"
|
||||
}
|
||||
adapter.notifyItemChanged(position)
|
||||
sharedPrefs.dns_servers = items
|
||||
binding.recyclerView.adapter?.notifyItemChanged(position)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to grant WRITE_SECURE_SETTINGS permission with Shizuku
|
||||
*/
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.widget.TextView
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import java.util.Collections
|
||||
|
||||
class RecyclerAdapter(private val items: MutableList<String>, private val showDragHandle: Boolean) :
|
||||
class RecyclerAdapter(private val items: MutableList<String>, private val showDragHandle: Boolean, private val onDataChanged: () -> Unit) :
|
||||
RecyclerView.Adapter<RecyclerAdapter.ViewHolder>() {
|
||||
|
||||
var onItemClick: ((Int) -> Unit)? = null
|
||||
|
@ -77,6 +77,7 @@ class RecyclerAdapter(private val items: MutableList<String>, private val showDr
|
|||
clear()
|
||||
addAll(newItems)
|
||||
}
|
||||
onDataChanged()
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,30 @@
|
|||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/topAppBarLayout" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_servers_added"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.45" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_view_hint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/empty_hint"
|
||||
android:textColor="@color/material_dynamic_neutral50"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/empty_view" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/floating_action_button"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<string name="dns_unknown">Unknown</string>
|
||||
<string name="add_server">Add Server</string>
|
||||
<string name="menu_add">Add</string>
|
||||
<string name="menu_save">Save</string>
|
||||
<string name="menu_privacy_policy">Privacy Policy</string>
|
||||
<string name="select_server">Select Server</string>
|
||||
<string name="done">Done</string>
|
||||
|
@ -43,4 +44,7 @@
|
|||
<string name="menu_export_to_file">To file</string>
|
||||
<string name="export_failure">Saving failed</string>
|
||||
<string name="export_success">Saved successfully</string>
|
||||
<string name="edit_server">Edit server</string>
|
||||
<string name="no_servers_added">No Servers Added</string>
|
||||
<string name="empty_hint">Tap on the button below to add one</string>
|
||||
</resources>
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.5.0'
|
||||
classpath 'com.android.tools.build:gradle:8.5.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue