1. added DNS form. iteration 1.

This commit is contained in:
vadym 2020-06-25 13:09:24 -07:00
parent aec660bff0
commit 3db311c4d2
18 changed files with 486 additions and 39 deletions

View File

@ -18,7 +18,10 @@
android:name=".PeerListActivity" android:name=".PeerListActivity"
android:label="@string/title_activity_peer_list" android:label="@string/title_activity_peer_list"
android:theme="@style/AppTheme.NoActionBar" /> android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".DNSListActivity"
android:label="@string/title_activity_dns_list"
android:theme="@style/AppTheme.NoActionBar" />
<service <service
android:name=".YggdrasilTunService" android:name=".YggdrasilTunService"
android:enabled="true" android:enabled="true"

View File

@ -0,0 +1,109 @@
package io.github.chronosx88.yggdrasil
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.Gravity
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.ListView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import io.github.chronosx88.yggdrasil.models.DNSInfo
import io.github.chronosx88.yggdrasil.models.config.SelectDNSInfoListAdapter
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.ping
import kotlinx.coroutines.*
import java.net.*
import kotlin.concurrent.thread
class DNSListActivity : AppCompatActivity() {
companion object {
val allDNS = arrayListOf(
DNSInfo(
InetAddress.getByName("[301:2522::53]"),
"CZ",
"DNS implementation for Yggdrasil. https://github.com/Revertron/wyrd"),
DNSInfo(InetAddress.getByName("[301:2923::53]"),
"SK",
"DNS implementation for Yggdrasil. https://github.com/Revertron/wyrd"),
DNSInfo(InetAddress.getByName("[300:4523::53]"),
"DE",
"DNS implementation for Yggdrasil. https://github.com/Revertron/wyrd"),
DNSInfo(InetAddress.getByName("[303:8b1a::53]"),
"RU",
"DNS implementation for Yggdrasil. https://github.com/Revertron/wyrd")
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dns_list)
setSupportActionBar(findViewById(R.id.toolbar))
findViewById<FloatingActionButton>(R.id.fab).setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
var extras = intent.extras
var dnsList = findViewById<ListView>(R.id.dnsList)
var adapter = SelectDNSInfoListAdapter(this, arrayListOf(), mutableSetOf())
dnsList.adapter = adapter
thread(start = true) {
try {
var cd = MainActivity.deserializeStringList2DNSInfoSet(
extras!!.getStringArrayList(MainActivity.DNS_LIST)!!
)
for (d in cd) {
var ping = ping(d.address, 53)
d.ping = ping
}
for (dns in allDNS) {
if (cd.contains(dns)) {
continue
}
var ping = ping(dns.address, 53)
dns.ping = ping
adapter.addItem(dns)
runOnUiThread(
Runnable
{
adapter.sort()
}
)
}
} catch (e: Throwable) {
e.printStackTrace()
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.save, menu)
val item = menu.findItem(R.id.saveItem) as MenuItem
item.setActionView(R.layout.menu_save)
val saveButton = item
.actionView.findViewById<Button>(R.id.saveButton)
saveButton.setOnClickListener {
val result = Intent(this, MainActivity::class.java)
var adapter = findViewById<ListView>(R.id.dnsList).adapter as SelectDNSInfoListAdapter
val selectedDNS = adapter.getSelectedDNS()
if(selectedDNS.size>0) {
result.putExtra(MainActivity.DNS_LIST, MainActivity.serializeDNSInfoSet2StringList(selectedDNS))
setResult(Activity.RESULT_OK, result)
finish()
} else {
val text = "Select at least one DNS"
val duration = Toast.LENGTH_SHORT
val toast = Toast.makeText(applicationContext, text, duration)
toast.setGravity(Gravity.CENTER, 0, 0)
toast.show()
}
}
return true
}
}

View File

@ -13,7 +13,9 @@ import android.widget.*
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.gson.Gson import com.google.gson.Gson
import io.github.chronosx88.yggdrasil.models.DNSInfo
import io.github.chronosx88.yggdrasil.models.PeerInfo import io.github.chronosx88.yggdrasil.models.PeerInfo
import io.github.chronosx88.yggdrasil.models.config.DNSInfoListAdapter
import io.github.chronosx88.yggdrasil.models.config.PeerInfoListAdapter import io.github.chronosx88.yggdrasil.models.config.PeerInfoListAdapter
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.HashSet import kotlin.collections.HashSet
@ -31,9 +33,13 @@ class MainActivity : AppCompatActivity() {
const val STATUS_STOP = 9 const val STATUS_STOP = 9
const val IPv6: String = "IPv6" const val IPv6: String = "IPv6"
const val PEERS: String = "PEERS" const val PEERS: String = "PEERS"
const val DNS: String = "DNS"
const val PEER_LIST_CODE = 1000 const val PEER_LIST_CODE = 1000
const val DNS_LIST_CODE = 2000
const val PEER_LIST = "PEERS_LIST" const val PEER_LIST = "PEERS_LIST"
const val DNS_LIST = "DNS_LIST"
const val CURRENT_PEERS = "CURRENT_PEERS_v1.1" const val CURRENT_PEERS = "CURRENT_PEERS_v1.1"
const val CURRENT_DNS = "CURRENT_DNS_v1.1"
const val START_VPN = "START_VPN" const val START_VPN = "START_VPN"
private const val TAG="Yggdrasil" private const val TAG="Yggdrasil"
private const val VPN_REQUEST_CODE = 0x0F private const val VPN_REQUEST_CODE = 0x0F
@ -48,6 +54,16 @@ class MainActivity : AppCompatActivity() {
return out return out
} }
@JvmStatic
fun deserializeStringList2DNSInfoSet(list: List<String>): MutableSet<DNSInfo> {
var gson = Gson()
var out = mutableSetOf<DNSInfo>()
for(s in list) {
out.add(gson.fromJson(s, DNSInfo::class.java))
}
return out
}
@JvmStatic @JvmStatic
fun deserializeStringSet2PeerInfoSet(list: Set<String>): MutableSet<PeerInfo> { fun deserializeStringSet2PeerInfoSet(list: Set<String>): MutableSet<PeerInfo> {
var gson = Gson() var gson = Gson()
@ -58,6 +74,16 @@ class MainActivity : AppCompatActivity() {
return out return out
} }
@JvmStatic
fun deserializeStringSet2DNSInfoSet(list: Set<String>): MutableSet<DNSInfo> {
var gson = Gson()
var out = mutableSetOf<DNSInfo>()
for(s in list) {
out.add(gson.fromJson(s, DNSInfo::class.java))
}
return out
}
@JvmStatic @JvmStatic
fun serializePeerInfoSet2StringList(list: Set<PeerInfo>): ArrayList<String> { fun serializePeerInfoSet2StringList(list: Set<PeerInfo>): ArrayList<String> {
var gson = Gson() var gson = Gson()
@ -67,10 +93,21 @@ class MainActivity : AppCompatActivity() {
} }
return out return out
} }
@JvmStatic
fun serializeDNSInfoSet2StringList(list: Set<DNSInfo>): ArrayList<String> {
var gson = Gson()
var out = ArrayList<String>()
for(p in list) {
out.add(gson.toJson(p))
}
return out
}
} }
private var startVpnFlag = false private var startVpnFlag = false
private var currentPeers = setOf<PeerInfo>() private var currentPeers = setOf<PeerInfo>()
private var currentDNS = setOf<DNSInfo>()
private var isStarted = false private var isStarted = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -82,7 +119,7 @@ class MainActivity : AppCompatActivity() {
PreferenceManager.getDefaultSharedPreferences(this.baseContext) PreferenceManager.getDefaultSharedPreferences(this.baseContext)
currentPeers = deserializeStringSet2PeerInfoSet(preferences.getStringSet(CURRENT_PEERS, HashSet())!!) currentPeers = deserializeStringSet2PeerInfoSet(preferences.getStringSet(CURRENT_PEERS, HashSet())!!)
val adapter = PeerInfoListAdapter(this, ArrayList(currentPeers)) val adapter = PeerInfoListAdapter(this, currentPeers.sortedWith(compareBy { it.ping }))
listView.adapter = adapter listView.adapter = adapter
val editPeersButton = findViewById<Button>(R.id.edit) val editPeersButton = findViewById<Button>(R.id.edit)
editPeersButton.setOnClickListener { editPeersButton.setOnClickListener {
@ -90,10 +127,25 @@ class MainActivity : AppCompatActivity() {
showToast("Service is running. Please stop service before edit Peers list") showToast("Service is running. Please stop service before edit Peers list")
return@setOnClickListener return@setOnClickListener
} }
val intent = Intent(this, PeerListActivity::class.java) val intent = Intent(this@MainActivity, PeerListActivity::class.java)
intent.putStringArrayListExtra(PEER_LIST, serializePeerInfoSet2StringList(currentPeers)) intent.putStringArrayListExtra(PEER_LIST, serializePeerInfoSet2StringList(currentPeers))
startActivityForResult(intent, PEER_LIST_CODE) startActivityForResult(intent, PEER_LIST_CODE)
} }
val listViewDNS = findViewById<ListView>(R.id.dns)
currentDNS = deserializeStringSet2DNSInfoSet(preferences.getStringSet(CURRENT_DNS, HashSet())!!)
val adapterDns = DNSInfoListAdapter(this, currentDNS.sortedWith(compareBy { it.ping }))
listViewDNS.adapter = adapterDns
val editDnsButton = findViewById<Button>(R.id.editDNS)
editDnsButton.setOnClickListener {
if(!isStarted){
showToast("Service is not running. DNS ping will not be run")
return@setOnClickListener
}
val intent = Intent(this@MainActivity, DNSListActivity::class.java)
intent.putStringArrayListExtra(DNS_LIST, serializeDNSInfoSet2StringList(currentDNS))
startActivityForResult(intent, DNS_LIST_CODE)
}
if(intent.extras!==null) { if(intent.extras!==null) {
startVpnFlag = intent.extras!!.getBoolean(START_VPN, false) startVpnFlag = intent.extras!!.getBoolean(START_VPN, false)
} }
@ -123,6 +175,7 @@ class MainActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == VPN_REQUEST_CODE && resultCode== Activity.RESULT_OK){ if (requestCode == VPN_REQUEST_CODE && resultCode== Activity.RESULT_OK){
if(currentPeers.isEmpty()){ if(currentPeers.isEmpty()){
showToast("No peers selected!") showToast("No peers selected!")
@ -134,8 +187,10 @@ class MainActivity : AppCompatActivity() {
intent.putExtra(PARAM_PINTENT, pi) intent.putExtra(PARAM_PINTENT, pi)
intent.putExtra(COMMAND, START) intent.putExtra(COMMAND, START)
intent.putStringArrayListExtra(PEERS, serializePeerInfoSet2StringList(currentPeers)) intent.putStringArrayListExtra(PEERS, serializePeerInfoSet2StringList(currentPeers))
intent.putStringArrayListExtra(DNS, serializeDNSInfoSet2StringList(currentDNS))
startService(intent) startService(intent)
} }
if (requestCode == PEER_LIST_CODE && resultCode== Activity.RESULT_OK){ if (requestCode == PEER_LIST_CODE && resultCode== Activity.RESULT_OK){
if(data!!.extras!=null){ if(data!!.extras!=null){
var currentPeers = data.extras!!.getStringArrayList(PEER_LIST) var currentPeers = data.extras!!.getStringArrayList(PEER_LIST)
@ -152,7 +207,7 @@ class MainActivity : AppCompatActivity() {
PreferenceManager.getDefaultSharedPreferences(this.baseContext) PreferenceManager.getDefaultSharedPreferences(this.baseContext)
preferences.edit().putStringSet(CURRENT_PEERS, HashSet(currentPeers)).apply() preferences.edit().putStringSet(CURRENT_PEERS, HashSet(currentPeers)).apply()
if(isStarted){ if(isStarted){
//TODO implement UpdateConfig methon in native interface and apply peer changes //TODO implement UpdateConfig method in native interface and apply peer changes
stopVpn() stopVpn()
val i = baseContext.packageManager val i = baseContext.packageManager
.getLaunchIntentForPackage(baseContext.packageName) .getLaunchIntentForPackage(baseContext.packageName)
@ -165,6 +220,36 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
if (requestCode == DNS_LIST_CODE && resultCode== Activity.RESULT_OK){
if(data!!.extras!=null){
var currentDNS = data.extras!!.getStringArrayList(DNS_LIST)
if(currentDNS==null || currentDNS.size==0){
showToast("No DNS selected!")
} else {
this.currentDNS = deserializeStringList2DNSInfoSet(currentDNS)
val adapter = DNSInfoListAdapter(this, this.currentDNS.sortedWith(compareBy { it.ping }))
val listView = findViewById<ListView>(R.id.dns)
listView.adapter = adapter
//save to shared preferences
val preferences =
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
preferences.edit().putStringSet(CURRENT_DNS, HashSet(currentDNS)).apply()
if(isStarted){
//TODO implement UpdateConfig method in native interface and apply peer changes
stopVpn()
val i = baseContext.packageManager
.getLaunchIntentForPackage(baseContext.packageName)
i!!.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
i.putExtra(START_VPN, true)
finish()
startActivity(i)
}
}
}
}
when (resultCode) { when (resultCode) {
STATUS_START -> print("service started") STATUS_START -> print("service started")
STATUS_FINISH -> { STATUS_FINISH -> {

View File

@ -18,6 +18,7 @@ import com.hbb20.CCPCountry
import io.github.chronosx88.yggdrasil.models.PeerInfo import io.github.chronosx88.yggdrasil.models.PeerInfo
import io.github.chronosx88.yggdrasil.models.Status import io.github.chronosx88.yggdrasil.models.Status
import io.github.chronosx88.yggdrasil.models.config.SelectPeerInfoListAdapter import io.github.chronosx88.yggdrasil.models.config.SelectPeerInfoListAdapter
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.ping
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -44,19 +45,6 @@ class PeerListActivity : AppCompatActivity() {
} }
} }
fun ping(address: InetAddress, port:Int): Int {
val start = System.currentTimeMillis()
val socket = Socket()
try {
socket.connect(InetSocketAddress(address, port), 5000)
socket.close()
} catch (e: Exception) {
//silently pass
return Int.MAX_VALUE
}
return (System.currentTimeMillis() - start).toInt()
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_peer_list) setContentView(R.layout.activity_peer_list)
@ -67,8 +55,7 @@ class PeerListActivity : AppCompatActivity() {
} }
var extras = intent.extras var extras = intent.extras
var peerList = findViewById<ListView>(R.id.peerList) var peerList = findViewById<ListView>(R.id.peerList)
var allPeers = arrayListOf<PeerInfo>() var adapter = SelectPeerInfoListAdapter(this, arrayListOf(), mutableSetOf())
var adapter = SelectPeerInfoListAdapter(this, allPeers, mutableSetOf())
peerList.adapter = adapter peerList.adapter = adapter
GlobalScope.launch { GlobalScope.launch {
@ -103,7 +90,7 @@ class PeerListActivity : AppCompatActivity() {
var ping = ping(address, url.port) var ping = ping(address, url.port)
peerInfo.ping = ping peerInfo.ping = ping
adapter.addItem(peerInfo) adapter.addItem(peerInfo)
if(peerList.adapter.count % 5 == 0) { if(adapter.count % 5 == 0) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
adapter.sort() adapter.sort()
} }
@ -128,7 +115,7 @@ class PeerListActivity : AppCompatActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present. // Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.save_peers, menu) menuInflater.inflate(R.menu.save, menu)
val item = menu.findItem(R.id.saveItem) as MenuItem val item = menu.findItem(R.id.saveItem) as MenuItem
item.setActionView(R.layout.menu_save) item.setActionView(R.layout.menu_save)
val saveButton = item val saveButton = item

View File

@ -7,6 +7,7 @@ import android.os.ParcelFileDescriptor
import android.system.OsConstants import android.system.OsConstants
import com.google.gson.Gson import com.google.gson.Gson
import dummy.ConduitEndpoint import dummy.ConduitEndpoint
import io.github.chronosx88.yggdrasil.models.DNSInfo
import io.github.chronosx88.yggdrasil.models.PeerInfo import io.github.chronosx88.yggdrasil.models.PeerInfo
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
@ -53,18 +54,21 @@ class YggdrasilTunService : VpnService() {
} }
if (intent?.getStringExtra(MainActivity.COMMAND) == MainActivity.START) { if (intent?.getStringExtra(MainActivity.COMMAND) == MainActivity.START) {
val peers = MainActivity.deserializeStringList2PeerInfoSet(intent.getStringArrayListExtra(MainActivity.PEERS)) val peers = MainActivity.deserializeStringList2PeerInfoSet(intent.getStringArrayListExtra(MainActivity.PEERS))
val dns = MainActivity.deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS))
val pi: PendingIntent = intent.getParcelableExtra(MainActivity.PARAM_PINTENT) val pi: PendingIntent = intent.getParcelableExtra(MainActivity.PARAM_PINTENT)
ygg = Yggdrasil() ygg = Yggdrasil()
setupTunInterface(pi, peers) setupTunInterface(pi, peers, dns)
} }
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)
} }
private fun setupTunInterface(pi: PendingIntent, peers: Set<PeerInfo>) { private fun setupTunInterface(
pi: PendingIntent,
peers: Set<PeerInfo>,
dns: MutableSet<DNSInfo>
) {
pi.send(MainActivity.STATUS_START) pi.send(MainActivity.STATUS_START)
val builder = Builder()
var configJson = Mobile.generateConfigJSON() var configJson = Mobile.generateConfigJSON()
val gson = Gson() val gson = Gson()
var config = gson.fromJson(String(configJson), Map::class.java).toMutableMap() var config = gson.fromJson(String(configJson), Map::class.java).toMutableMap()
@ -74,12 +78,16 @@ class YggdrasilTunService : VpnService() {
yggConduitEndpoint = ygg.startJSON(configJson) yggConduitEndpoint = ygg.startJSON(configJson)
val address = ygg.addressString // hack for getting generic ipv6 string from NodeID val address = ygg.addressString // hack for getting generic ipv6 string from NodeID
tunInterface = builder var builder = Builder()
.addAddress(address, 7) .addAddress(address, 7)
.allowFamily(OsConstants.AF_INET) .allowFamily(OsConstants.AF_INET)
.setMtu(MAX_PACKET_SIZE) .setMtu(MAX_PACKET_SIZE)
.establish() if(dns.size>0){
for (d in dns){
builder.addDnsServer(d.address)
}
}
tunInterface = builder.establish()
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor) tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor) tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
readCoroutine = GlobalScope.launch { readCoroutine = GlobalScope.launch {

View File

@ -0,0 +1,34 @@
package io.github.chronosx88.yggdrasil.models
import android.content.Context
import com.hbb20.CCPCountry
import com.hbb20.CountryCodePicker
import java.net.InetAddress
class DNSInfo {
constructor(address: InetAddress, countryCode: String, description: String){
this.address = address
this.countryCode = countryCode
this.description = description
}
var address: InetAddress
var countryCode: String
var description: String
var ping: Int = Int.MAX_VALUE
override fun toString(): String {
return "[" + address.toString().substring(1) + "]"
}
override fun equals(other: Any?): Boolean {
return toString() == other.toString()
}
fun getCountry(context: Context): CCPCountry? {
return CCPCountry.getCountryForNameCodeFromLibraryMasterList(context, CountryCodePicker.Language.ENGLISH, countryCode)
}
}

View File

@ -0,0 +1,44 @@
package io.github.chronosx88.yggdrasil.models.config
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
import io.github.chronosx88.yggdrasil.R
import io.github.chronosx88.yggdrasil.models.DNSInfo
class DNSInfoListAdapter(
context: Context,
allDNS: List<DNSInfo>
) : ArrayAdapter<DNSInfo?> (context, 0, allDNS) {
private val mContext: Context = context
private var allDNS: List<DNSInfo> = allDNS
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var dnsInfoHolder = DNSInfoHolder()
var listItem: View? = convertView
if (listItem == null) {
listItem = LayoutInflater.from(mContext).inflate(R.layout.host_list_item, parent, false)
dnsInfoHolder.countryFlag = listItem.findViewById(R.id.countryFlag) as ImageView
dnsInfoHolder.dnsInfoText = listItem.findViewById(R.id.hostInfoText) as TextView
listItem.tag = dnsInfoHolder
} else {
dnsInfoHolder = listItem.tag as DNSInfoHolder
}
val currentDNS = allDNS[position]
dnsInfoHolder.countryFlag.setImageResource(currentDNS.getCountry(mContext)!!.flagID)
dnsInfoHolder.dnsInfoText.text = currentDNS.toString()
return listItem!!
}
class DNSInfoHolder {
lateinit var countryFlag: ImageView
lateinit var dnsInfoText: TextView
}
}

View File

@ -5,12 +5,10 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.CheckBox
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import io.github.chronosx88.yggdrasil.R import io.github.chronosx88.yggdrasil.R
import io.github.chronosx88.yggdrasil.models.PeerInfo import io.github.chronosx88.yggdrasil.models.PeerInfo
import java.util.ArrayList
class PeerInfoListAdapter( class PeerInfoListAdapter(
@ -25,17 +23,16 @@ class PeerInfoListAdapter(
var peerInfoHolder = PeerInfoHolder() var peerInfoHolder = PeerInfoHolder()
var listItem: View? = convertView var listItem: View? = convertView
if (listItem == null) { if (listItem == null) {
listItem = LayoutInflater.from(mContext).inflate(R.layout.peers_list_item, parent, false) listItem = LayoutInflater.from(mContext).inflate(R.layout.host_list_item, parent, false)
peerInfoHolder.countryFlag = listItem.findViewById(R.id.countryFlag) as ImageView peerInfoHolder.countryFlag = listItem.findViewById(R.id.countryFlag) as ImageView
peerInfoHolder.peerInfoText = listItem.findViewById(R.id.peerInfoText) as TextView peerInfoHolder.peerInfoText = listItem.findViewById(R.id.hostInfoText) as TextView
listItem.tag = peerInfoHolder listItem.tag = peerInfoHolder
} else { } else {
peerInfoHolder = listItem.tag as PeerInfoHolder peerInfoHolder = listItem.tag as PeerInfoHolder
} }
val currentPeer = allPeers[position] val currentPeer = allPeers[position]
peerInfoHolder.countryFlag.setImageResource(currentPeer.getCountry(mContext)!!.flagID) peerInfoHolder.countryFlag.setImageResource(currentPeer.getCountry(mContext)!!.flagID)
val peerId = currentPeer.toString() peerInfoHolder.peerInfoText.text = currentPeer.toString()
peerInfoHolder.peerInfoText.text = peerId
return listItem!! return listItem!!
} }

View File

@ -0,0 +1,99 @@
package io.github.chronosx88.yggdrasil.models.config
import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.CheckBox
import android.widget.ImageView
import android.widget.TextView
import io.github.chronosx88.yggdrasil.R
import io.github.chronosx88.yggdrasil.models.DNSInfo
class SelectDNSInfoListAdapter(
context: Context,
allDNS: List<DNSInfo>,
currentDNS: MutableSet<DNSInfo>
) : ArrayAdapter<DNSInfo?> (context, 0, allDNS) {
private val mContext: Context = context
private var allDNS: MutableList<DNSInfo> = allDNS as MutableList<DNSInfo>
private var currentDNS: MutableSet<DNSInfo> = currentDNS
override fun getItem(position: Int): DNSInfo? {
return allDNS.get(position)
}
override fun getCount(): Int {
return allDNS.size
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var dnsInfoHolder = DNSInfoHolder()
var listItem: View? = convertView
if (listItem == null) {
listItem = LayoutInflater.from(mContext).inflate(R.layout.host_list_item_edit, parent, false)
dnsInfoHolder.checkbox = listItem.findViewById(R.id.checkbox) as CheckBox
dnsInfoHolder.countryFlag = listItem.findViewById(R.id.countryFlag) as ImageView
dnsInfoHolder.dnsInfoText = listItem.findViewById(R.id.hostInfoText) as TextView
dnsInfoHolder.ping = listItem.findViewById(R.id.ping) as TextView
listItem.tag = dnsInfoHolder
} else {
dnsInfoHolder = listItem.tag as DNSInfoHolder
}
val currentDNS = allDNS[position]
dnsInfoHolder.countryFlag.setImageResource(currentDNS.getCountry(mContext)!!.flagID)
val dnsId = currentDNS.toString()
if(currentDNS.ping == Int.MAX_VALUE){
dnsInfoHolder.dnsInfoText.text = dnsId
dnsInfoHolder.ping.text=""
dnsInfoHolder.dnsInfoText.setTextColor(Color.GRAY)
} else {
dnsInfoHolder.dnsInfoText.text = dnsId
dnsInfoHolder.ping.text = currentDNS.ping.toString() + " ms"
dnsInfoHolder.dnsInfoText.setTextColor(Color.WHITE)
}
dnsInfoHolder.checkbox.setOnCheckedChangeListener { _, isChecked ->
if(isChecked){
if(!this.currentDNS.contains(currentDNS)){
this.currentDNS.add(currentDNS)
}
} else {
if(this.currentDNS.contains(currentDNS)){
this.currentDNS.remove(currentDNS)
}
}
}
dnsInfoHolder.checkbox.isChecked = this.currentDNS.contains(currentDNS)
return listItem!!
}
fun getSelectedDNS(): Set<DNSInfo> {
return currentDNS
}
fun addItem(peerInfo: DNSInfo){
allDNS.add(peerInfo)
}
fun addAll(index: Int, peerInfo: ArrayList<DNSInfo>){
currentDNS.addAll(peerInfo)
allDNS.removeAll(peerInfo)
allDNS.addAll(index, peerInfo)
this.notifyDataSetChanged()
}
fun sort(){
allDNS = ArrayList(allDNS.sortedWith(compareBy { it.ping }))
this.notifyDataSetChanged()
}
class DNSInfoHolder {
lateinit var checkbox: CheckBox
lateinit var countryFlag: ImageView
lateinit var dnsInfoText: TextView
lateinit var ping: TextView
}
}

View File

@ -34,10 +34,10 @@ class SelectPeerInfoListAdapter(
var peerInfoHolder = PeerInfoHolder() var peerInfoHolder = PeerInfoHolder()
var listItem: View? = convertView var listItem: View? = convertView
if (listItem == null) { if (listItem == null) {
listItem = LayoutInflater.from(mContext).inflate(R.layout.peers_list_item_edit, parent, false) listItem = LayoutInflater.from(mContext).inflate(R.layout.host_list_item_edit, parent, false)
peerInfoHolder.checkbox = listItem.findViewById(R.id.checkbox) as CheckBox peerInfoHolder.checkbox = listItem.findViewById(R.id.checkbox) as CheckBox
peerInfoHolder.countryFlag = listItem.findViewById(R.id.countryFlag) as ImageView peerInfoHolder.countryFlag = listItem.findViewById(R.id.countryFlag) as ImageView
peerInfoHolder.peerInfoText = listItem.findViewById(R.id.peerInfoText) as TextView peerInfoHolder.peerInfoText = listItem.findViewById(R.id.hostInfoText) as TextView
peerInfoHolder.ping = listItem.findViewById(R.id.ping) as TextView peerInfoHolder.ping = listItem.findViewById(R.id.ping) as TextView
listItem.tag = peerInfoHolder listItem.tag = peerInfoHolder
} else { } else {

View File

@ -0,0 +1,27 @@
package io.github.chronosx88.yggdrasil.models.config
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Socket
class Utils {
companion object {
@JvmStatic
fun ping(address: InetAddress, port:Int): Int {
val start = System.currentTimeMillis()
val socket = Socket()
try {
socket.connect(InetSocketAddress(address, port), 5000)
socket.close()
} catch (e: Exception) {
e.printStackTrace()
print(address)
return Int.MAX_VALUE
}
return (System.currentTimeMillis() - start).toInt()
}
}
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DNSListActivity"
android:background="@color/grey">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_dns_list" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/fab_margin"
app:backgroundTint="@color/green"
app:tint="@color/white"
app:borderWidth="0dp"
app:elevation="6dp"
app:fabSize="normal"
app:srcCompat="@android:drawable/ic_input_add"
android:visibility="gone"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -131,7 +131,7 @@
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<ListView <ListView
android:id="@+id/dnsList" android:id="@+id/dns"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center_vertical" android:gravity="center_vertical"

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<ListView
android:id="@+id/dnsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/dark_20"
android:dividerHeight="2px"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -15,7 +15,7 @@
android:scaleType="fitStart"/> android:scaleType="fitStart"/>
</FrameLayout> </FrameLayout>
<TextView <TextView
android:id="@+id/peerInfoText" android:id="@+id/hostInfoText"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:gravity="center_vertical"

View File

@ -31,7 +31,7 @@
android:layout_toEndOf="@+id/frame" android:layout_toEndOf="@+id/frame"
android:layout_centerInParent="true"/> android:layout_centerInParent="true"/>
<TextView <TextView
android:id="@+id/peerInfoText" android:id="@+id/hostInfoText"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:gravity="center_vertical"

View File

@ -4,4 +4,5 @@
<string name="disconnect_button">Disconnect</string> <string name="disconnect_button">Disconnect</string>
<string name="switch_button_title">SwitchOn</string> <string name="switch_button_title">SwitchOn</string>
<string name="title_activity_peer_list">Edit peers</string> <string name="title_activity_peer_list">Edit peers</string>
<string name="title_activity_dns_list">Edit DNS</string>
</resources> </resources>