Skip to content

Commit

Permalink
add hosts
Browse files Browse the repository at this point in the history
  • Loading branch information
Asutorufa committed Dec 13, 2022
1 parent db2a370 commit 68dd9e3
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class DnsFragment : PreferenceFragmentCompat() {
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false).apply {
duration = 500L
}
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)

preferenceManager.preferenceDataStore = (activity as MainActivity).dataStore

Expand Down
125 changes: 101 additions & 24 deletions app/src/main/kotlin/io/github/asutorufa/yuhaiin/HostsDialogFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,46 @@ package io.github.asutorufa.yuhaiin

import android.app.Dialog
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.view.MenuProvider
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.github.asutorufa.yuhaiin.database.Manager
import io.github.asutorufa.yuhaiin.databinding.HostsDialogBinding
import io.github.asutorufa.yuhaiin.databinding.ItemRecyclerHostsBinding

class HostsDialogFragment : DialogFragment() {

private val adapter = HostsListAdapter()
private val mainActivity by lazy { requireActivity() as MainActivity }

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

// enterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true)
// returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
}

override fun onPause() {
Log.d("appListFragment", "onPause: ${adapter.hostsMap}")
adapter.hostsMap.let {
Manager.profile.hosts = it
Manager.db.updateProfile(Manager.profile)
}
super.onPause()
}

override fun onCreateView(
inflater: LayoutInflater,
Expand All @@ -27,45 +54,98 @@ class HostsDialogFragment : DialogFragment() {
layoutManager = LinearLayoutManager(hostsDialogFragmentBinding.root.context)
adapter = this@HostsDialogFragment.adapter

this@HostsDialogFragment.adapter.setHostsList(buildList {
add(HostsList("1", "2"))
add(HostsList("3", "4"))
add(HostsList("5", "6"))
add(HostsList("7", "8"))
add(HostsList("9", "10"))
})
this@HostsDialogFragment.adapter.setHostsList(Manager.profile.hosts.toMutableMap())
}


mainActivity.addMenuProvider(menuProvider, viewLifecycleOwner, Lifecycle.State.RESUMED)
return hostsDialogFragmentBinding.root
}

private val menuProvider = object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) =
menuInflater.inflate(R.menu.hosts, menu)

override fun onMenuItemSelected(menuItem: MenuItem): Boolean =
when (menuItem.itemId) {
R.id.hosts_add -> {
val e = AppCompatEditText(requireContext()).apply { isSingleLine = true }
showAlertDialog(R.string.dns_hosts_add_from, e, null) {
val name = e.text.toString()
if (name.isEmpty()) return@showAlertDialog
try {
adapter.addHosts(name)
} catch (e: Exception) {
e.message?.let { mainActivity.showSnackBar(it) }
}
}
true
}

else -> false
}
}


fun showAlertDialog(
title: Int,
view: View?,
message: String?,
PositiveFun: () -> Unit
) =
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(title)
view?.let { setView(it) }
message?.let { setMessage(it) }
setPositiveButton(android.R.string.ok) { _, _ -> PositiveFun() }
setNegativeButton(android.R.string.cancel) { _, _ -> }
show()
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
super.onCreateDialog(savedInstanceState).apply {
requestWindowFeature(Window.FEATURE_NO_TITLE)
}
}


data class HostsList(val from: String, val to: String)

class HostsListAdapter : RecyclerView.Adapter<HostsListAdapter.HostsListViewHolder>() {

private var hosts: List<HostsList>? = null
private var hosts: ArrayList<String> = ArrayList()
lateinit var hostsMap: MutableMap<String, String>

fun setHostsList(hosts: List<HostsList>) {
this.hosts = hosts
fun addHosts(from: String) {
hostsMap[from] = from
hosts.add(from)
notifyItemInserted(itemCount - 1)
}

fun setHostsList(hosts: MutableMap<String, String>) {
hosts.forEach { (key, _) -> this.hosts.add(key) }
this.hostsMap = hosts
notifyItemRangeInserted(0, itemCount)
}

inner class HostsListViewHolder(private val itemBinding: ItemRecyclerHostsBinding) :
RecyclerView.ViewHolder(itemBinding.root), View.OnClickListener {

lateinit var info: HostsList

fun bind(hosts: HostsList) {
this.info = hosts
itemBinding.fromText.setText(hosts.from)
itemBinding.toText.setText(hosts.to)
private lateinit var hostsFrom: String

fun bind(hostsFrom: String) {
this.hostsFrom = hostsFrom
itemBinding.from.setEndIconOnClickListener {
Log.d("end icon click", "end icon click")
val index = hosts.indexOf(hostsFrom)
hostsMap.remove(hostsFrom)
hosts.remove(hostsFrom)
notifyItemRemoved(index)
}
itemBinding.fromText.setText(hostsFrom)
itemBinding.toText.setText(hostsMap[hostsFrom])
itemBinding.toText.doAfterTextChanged {
hostsMap[hostsFrom] = itemBinding.toText.text.toString()
Log.d("hosts dialog", "bind: $hostsMap")
}
itemView.setOnClickListener(this)
}

Expand All @@ -82,12 +162,9 @@ class HostsListAdapter : RecyclerView.Adapter<HostsListAdapter.HostsListViewHold
)
}

override fun getItemCount(): Int = hosts?.size ?: 0
override fun getItemCount(): Int = hosts.size

override fun onBindViewHolder(holder: HostsListViewHolder, position: Int) {
hosts?.let {
holder.bind(it[position])
}
}
override fun onBindViewHolder(holder: HostsListViewHolder, position: Int) =
hosts.let { holder.bind(it[position]) }

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ object Converters {
return gson.toJson(list)
}


@TypeConverter
fun fromMapString(value: String?): Map<String, String> {
val listType: Type = object : TypeToken<Map<String, String>?>() {}.type
return gson.fromJson(value, listType)
}

@TypeConverter
fun fromMap(list: Map<String, String>?): String {
return gson.toJson(list)
}

@TypeConverter
fun stringToDNS(value: String?): DNS {
val dnsType: Type = object : TypeToken<DNS?>() {}.type
Expand All @@ -35,7 +47,7 @@ object Converters {
val bypassType: Type = object : TypeToken<Bypass?>() {}.type
return gson.fromJson(value, bypassType)
}

@TypeConverter
fun fromBypass(b: Bypass?): String {
return gson.toJson(b)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,10 @@ data class Profile(
name = "bypass",
defaultValue = Bypass.DefaultJson
) var bypass: Bypass = Bypass.Default,

@ColumnInfo(
name = "hosts",
defaultValue = "{}"
) var hosts: Map<String, String> = mapOf()
)

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase

@Database(
entities = [Profile::class, LastProfile::class],
version = 9,
version = 10,
exportSchema = false
)
@TypeConverters(Converters::class)
Expand Down Expand Up @@ -44,7 +44,7 @@ abstract class YuhaiinDatabase : RoomDatabase() {
.allowMainThreadQueries()
.addMigrations(
MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6,
MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9
MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9, MIGRATION_9_10
)
.build()
}
Expand Down Expand Up @@ -87,5 +87,10 @@ abstract class YuhaiinDatabase : RoomDatabase() {
database.execSQL("ALTER TABLE profile ADD COLUMN tun_driver INTEGER NOT NULL DEFAULT 0")
}
}
private val MIGRATION_9_10 = object : Migration(9, 10) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE profile ADD COLUMN hosts TEXT NOT NULL DEFAULT '{}'")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.content.getSystemService
import com.google.gson.Gson
import io.github.asutorufa.yuhaiin.BuildConfig
import io.github.asutorufa.yuhaiin.IYuhaiinVpnBinder
import io.github.asutorufa.yuhaiin.MainActivity
Expand Down Expand Up @@ -311,6 +312,7 @@ class YuhaiinVpnService : VpnService() {
remote = convertDNS(profile.remoteDns)
local = convertDNS(profile.localDns)
bootstrap = convertDNS(profile.bootstrapDns)
hosts = Gson().toJson(profile.hosts).toByteArray()
}
})
}
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/layout/item_recycler_hosts.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@
app:layout_constraintWidth_percent="0.49"
android:layout_height="match_parent"
android:hint="From"
app:endIconMode="custom"
app:endIconDrawable="@drawable/delete"
android:layout_width="0dp">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/fromText"
android:focusable="false"
android:clickable="false"
android:focusableInTouchMode="false"
android:inputType="none"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Expand All @@ -27,6 +32,7 @@
app:layout_constraintWidth_percent="0.49"
android:layout_height="match_parent"
android:hint="To"
app:endIconMode="clear_text"
android:layout_width="0dp">

<com.google.android.material.textfield.TextInputEditText
Expand All @@ -35,4 +41,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>


</androidx.constraintlayout.widget.ConstraintLayout>
10 changes: 10 additions & 0 deletions app/src/main/res/menu/hosts.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">

<item
android:id="@+id/hosts_add"
android:title="@string/dns_hosts_add_from"
android:icon="@drawable/add"
app:showAsAction="ifRoom" />
</menu>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<string name="adv_dns_port_title">DNS Port</string>
<string name="dns_hosts_key">hosts_key</string>
<string name="dns_hosts_title">Hosts</string>
<string name="dns_hosts_add_from">Add From</string>

<string name="dns_hijacking">dns_hijacking</string>

Expand Down
Binary file modified yuhaiin/yuhaiin-sources.jar
Binary file not shown.
Binary file modified yuhaiin/yuhaiin.aar
Binary file not shown.

0 comments on commit 68dd9e3

Please sign in to comment.