mirror of
https://github.com/yggdrasil-network/crispa-android.git
synced 2024-11-09 12:01:01 +00:00
1. added DNS form. iteration 1.
This commit is contained in:
parent
aec660bff0
commit
3db311c4d2
@ -18,7 +18,10 @@
|
||||
android:name=".PeerListActivity"
|
||||
android:label="@string/title_activity_peer_list"
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
|
||||
<activity
|
||||
android:name=".DNSListActivity"
|
||||
android:label="@string/title_activity_dns_list"
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<service
|
||||
android:name=".YggdrasilTunService"
|
||||
android:enabled="true"
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -13,7 +13,9 @@ import android.widget.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.preference.PreferenceManager
|
||||
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.config.DNSInfoListAdapter
|
||||
import io.github.chronosx88.yggdrasil.models.config.PeerInfoListAdapter
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashSet
|
||||
@ -31,9 +33,13 @@ class MainActivity : AppCompatActivity() {
|
||||
const val STATUS_STOP = 9
|
||||
const val IPv6: String = "IPv6"
|
||||
const val PEERS: String = "PEERS"
|
||||
const val DNS: String = "DNS"
|
||||
const val PEER_LIST_CODE = 1000
|
||||
const val DNS_LIST_CODE = 2000
|
||||
const val PEER_LIST = "PEERS_LIST"
|
||||
const val DNS_LIST = "DNS_LIST"
|
||||
const val CURRENT_PEERS = "CURRENT_PEERS_v1.1"
|
||||
const val CURRENT_DNS = "CURRENT_DNS_v1.1"
|
||||
const val START_VPN = "START_VPN"
|
||||
private const val TAG="Yggdrasil"
|
||||
private const val VPN_REQUEST_CODE = 0x0F
|
||||
@ -48,6 +54,16 @@ class MainActivity : AppCompatActivity() {
|
||||
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
|
||||
fun deserializeStringSet2PeerInfoSet(list: Set<String>): MutableSet<PeerInfo> {
|
||||
var gson = Gson()
|
||||
@ -58,6 +74,16 @@ class MainActivity : AppCompatActivity() {
|
||||
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
|
||||
fun serializePeerInfoSet2StringList(list: Set<PeerInfo>): ArrayList<String> {
|
||||
var gson = Gson()
|
||||
@ -67,10 +93,21 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
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 currentPeers = setOf<PeerInfo>()
|
||||
private var currentDNS = setOf<DNSInfo>()
|
||||
private var isStarted = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -82,7 +119,7 @@ class MainActivity : AppCompatActivity() {
|
||||
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
||||
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
|
||||
val editPeersButton = findViewById<Button>(R.id.edit)
|
||||
editPeersButton.setOnClickListener {
|
||||
@ -90,10 +127,25 @@ class MainActivity : AppCompatActivity() {
|
||||
showToast("Service is running. Please stop service before edit Peers list")
|
||||
return@setOnClickListener
|
||||
}
|
||||
val intent = Intent(this, PeerListActivity::class.java)
|
||||
val intent = Intent(this@MainActivity, PeerListActivity::class.java)
|
||||
intent.putStringArrayListExtra(PEER_LIST, serializePeerInfoSet2StringList(currentPeers))
|
||||
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) {
|
||||
startVpnFlag = intent.extras!!.getBoolean(START_VPN, false)
|
||||
}
|
||||
@ -123,6 +175,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (requestCode == VPN_REQUEST_CODE && resultCode== Activity.RESULT_OK){
|
||||
if(currentPeers.isEmpty()){
|
||||
showToast("No peers selected!")
|
||||
@ -134,8 +187,10 @@ class MainActivity : AppCompatActivity() {
|
||||
intent.putExtra(PARAM_PINTENT, pi)
|
||||
intent.putExtra(COMMAND, START)
|
||||
intent.putStringArrayListExtra(PEERS, serializePeerInfoSet2StringList(currentPeers))
|
||||
intent.putStringArrayListExtra(DNS, serializeDNSInfoSet2StringList(currentDNS))
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
if (requestCode == PEER_LIST_CODE && resultCode== Activity.RESULT_OK){
|
||||
if(data!!.extras!=null){
|
||||
var currentPeers = data.extras!!.getStringArrayList(PEER_LIST)
|
||||
@ -152,7 +207,7 @@ class MainActivity : AppCompatActivity() {
|
||||
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
||||
preferences.edit().putStringSet(CURRENT_PEERS, HashSet(currentPeers)).apply()
|
||||
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()
|
||||
val i = baseContext.packageManager
|
||||
.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) {
|
||||
STATUS_START -> print("service started")
|
||||
STATUS_FINISH -> {
|
||||
|
@ -18,6 +18,7 @@ import com.hbb20.CCPCountry
|
||||
import io.github.chronosx88.yggdrasil.models.PeerInfo
|
||||
import io.github.chronosx88.yggdrasil.models.Status
|
||||
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.GlobalScope
|
||||
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?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_peer_list)
|
||||
@ -67,8 +55,7 @@ class PeerListActivity : AppCompatActivity() {
|
||||
}
|
||||
var extras = intent.extras
|
||||
var peerList = findViewById<ListView>(R.id.peerList)
|
||||
var allPeers = arrayListOf<PeerInfo>()
|
||||
var adapter = SelectPeerInfoListAdapter(this, allPeers, mutableSetOf())
|
||||
var adapter = SelectPeerInfoListAdapter(this, arrayListOf(), mutableSetOf())
|
||||
peerList.adapter = adapter
|
||||
|
||||
GlobalScope.launch {
|
||||
@ -103,7 +90,7 @@ class PeerListActivity : AppCompatActivity() {
|
||||
var ping = ping(address, url.port)
|
||||
peerInfo.ping = ping
|
||||
adapter.addItem(peerInfo)
|
||||
if(peerList.adapter.count % 5 == 0) {
|
||||
if(adapter.count % 5 == 0) {
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.sort()
|
||||
}
|
||||
@ -128,7 +115,7 @@ class PeerListActivity : AppCompatActivity() {
|
||||
|
||||
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_peers, menu)
|
||||
menuInflater.inflate(R.menu.save, menu)
|
||||
val item = menu.findItem(R.id.saveItem) as MenuItem
|
||||
item.setActionView(R.layout.menu_save)
|
||||
val saveButton = item
|
||||
|
@ -7,6 +7,7 @@ import android.os.ParcelFileDescriptor
|
||||
import android.system.OsConstants
|
||||
import com.google.gson.Gson
|
||||
import dummy.ConduitEndpoint
|
||||
import io.github.chronosx88.yggdrasil.models.DNSInfo
|
||||
import io.github.chronosx88.yggdrasil.models.PeerInfo
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.cancel
|
||||
@ -53,18 +54,21 @@ class YggdrasilTunService : VpnService() {
|
||||
}
|
||||
if (intent?.getStringExtra(MainActivity.COMMAND) == MainActivity.START) {
|
||||
val peers = MainActivity.deserializeStringList2PeerInfoSet(intent.getStringArrayListExtra(MainActivity.PEERS))
|
||||
val dns = MainActivity.deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS))
|
||||
val pi: PendingIntent = intent.getParcelableExtra(MainActivity.PARAM_PINTENT)
|
||||
ygg = Yggdrasil()
|
||||
setupTunInterface(pi, peers)
|
||||
setupTunInterface(pi, peers, dns)
|
||||
}
|
||||
|
||||
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)
|
||||
val builder = Builder()
|
||||
|
||||
var configJson = Mobile.generateConfigJSON()
|
||||
val gson = Gson()
|
||||
var config = gson.fromJson(String(configJson), Map::class.java).toMutableMap()
|
||||
@ -74,12 +78,16 @@ class YggdrasilTunService : VpnService() {
|
||||
yggConduitEndpoint = ygg.startJSON(configJson)
|
||||
val address = ygg.addressString // hack for getting generic ipv6 string from NodeID
|
||||
|
||||
tunInterface = builder
|
||||
var builder = Builder()
|
||||
.addAddress(address, 7)
|
||||
.allowFamily(OsConstants.AF_INET)
|
||||
.setMtu(MAX_PACKET_SIZE)
|
||||
.establish()
|
||||
|
||||
if(dns.size>0){
|
||||
for (d in dns){
|
||||
builder.addDnsServer(d.address)
|
||||
}
|
||||
}
|
||||
tunInterface = builder.establish()
|
||||
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
|
||||
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
|
||||
readCoroutine = GlobalScope.launch {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -5,12 +5,10 @@ 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.PeerInfo
|
||||
import java.util.ArrayList
|
||||
|
||||
|
||||
class PeerInfoListAdapter(
|
||||
@ -25,17 +23,16 @@ class PeerInfoListAdapter(
|
||||
var peerInfoHolder = PeerInfoHolder()
|
||||
var listItem: View? = convertView
|
||||
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.peerInfoText = listItem.findViewById(R.id.peerInfoText) as TextView
|
||||
peerInfoHolder.peerInfoText = listItem.findViewById(R.id.hostInfoText) as TextView
|
||||
listItem.tag = peerInfoHolder
|
||||
} else {
|
||||
peerInfoHolder = listItem.tag as PeerInfoHolder
|
||||
}
|
||||
val currentPeer = allPeers[position]
|
||||
peerInfoHolder.countryFlag.setImageResource(currentPeer.getCountry(mContext)!!.flagID)
|
||||
val peerId = currentPeer.toString()
|
||||
peerInfoHolder.peerInfoText.text = peerId
|
||||
peerInfoHolder.peerInfoText.text = currentPeer.toString()
|
||||
return listItem!!
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -34,10 +34,10 @@ class SelectPeerInfoListAdapter(
|
||||
var peerInfoHolder = PeerInfoHolder()
|
||||
var listItem: View? = convertView
|
||||
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.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
|
||||
listItem.tag = peerInfoHolder
|
||||
} else {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
40
app/src/main/res/layout/activity_dns_list.xml
Normal file
40
app/src/main/res/layout/activity_dns_list.xml
Normal 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>
|
@ -131,7 +131,7 @@
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<ListView
|
||||
android:id="@+id/dnsList"
|
||||
android:id="@+id/dns"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
|
13
app/src/main/res/layout/content_dns_list.xml
Normal file
13
app/src/main/res/layout/content_dns_list.xml
Normal 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>
|
@ -15,7 +15,7 @@
|
||||
android:scaleType="fitStart"/>
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:id="@+id/peerInfoText"
|
||||
android:id="@+id/hostInfoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
@ -31,7 +31,7 @@
|
||||
android:layout_toEndOf="@+id/frame"
|
||||
android:layout_centerInParent="true"/>
|
||||
<TextView
|
||||
android:id="@+id/peerInfoText"
|
||||
android:id="@+id/hostInfoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
@ -4,4 +4,5 @@
|
||||
<string name="disconnect_button">Disconnect</string>
|
||||
<string name="switch_button_title">SwitchOn</string>
|
||||
<string name="title_activity_peer_list">Edit peers</string>
|
||||
<string name="title_activity_dns_list">Edit DNS</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user