mirror of
https://github.com/yggdrasil-network/crispa-android.git
synced 2025-01-22 16:06:30 +00:00
1. VPN DNS refactoring, GUI refactoring
This commit is contained in:
parent
50a107cea4
commit
63f777d2c4
@ -12,7 +12,6 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
|
||||||
tools:ignore="GoogleAppIndexingWarning">
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
<activity
|
<activity
|
||||||
android:name=".PeerListActivity"
|
android:name=".PeerListActivity"
|
||||||
@ -35,6 +34,8 @@
|
|||||||
</service>
|
</service>
|
||||||
|
|
||||||
<activity android:name=".MainActivity"
|
<activity android:name=".MainActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar"
|
||||||
android:screenOrientation="portrait">
|
android:screenOrientation="portrait">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
@ -10,8 +10,6 @@ import android.net.VpnService
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
@ -34,6 +32,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
const val COMMAND = "COMMAND"
|
const val COMMAND = "COMMAND"
|
||||||
const val STOP = "STOP"
|
const val STOP = "STOP"
|
||||||
const val START = "START"
|
const val START = "START"
|
||||||
|
const val UPDATE_DNS = "UPDATE_DNS"
|
||||||
const val PARAM_PINTENT = "pendingIntent"
|
const val PARAM_PINTENT = "pendingIntent"
|
||||||
const val STATUS_START = 7
|
const val STATUS_START = 7
|
||||||
const val STATUS_FINISH = 8
|
const val STATUS_FINISH = 8
|
||||||
@ -52,6 +51,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private const val VPN_REQUEST_CODE = 0x0F
|
private const val VPN_REQUEST_CODE = 0x0F
|
||||||
|
|
||||||
@JvmStatic var isStarted = false
|
@JvmStatic var isStarted = false
|
||||||
|
@JvmStatic var isCancelled = false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,19 +62,41 @@ class MainActivity : AppCompatActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
setSupportActionBar(findViewById(R.id.toolbar))
|
||||||
if(intent.extras!==null) {
|
if(intent.extras!==null) {
|
||||||
startVpnFlag = intent.extras!!.getBoolean(START_VPN, false)
|
startVpnFlag = intent.extras!!.getBoolean(START_VPN, false)
|
||||||
isStarted = true
|
isStarted = true
|
||||||
|
//startVpn()
|
||||||
} else {
|
} else {
|
||||||
isStarted = isYggServiceRunning(this)
|
isStarted = isYggServiceRunning(this)
|
||||||
}
|
}
|
||||||
val listView = findViewById<ListView>(R.id.peers)
|
|
||||||
|
val switchOn = findViewById<Switch>(R.id.switchOn)
|
||||||
|
switchOn.isChecked = isStarted
|
||||||
|
switchOn.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
if(currentPeers.isEmpty()){
|
||||||
|
switchOn.isChecked = false
|
||||||
|
return@setOnCheckedChangeListener
|
||||||
|
}
|
||||||
|
if(isCancelled){
|
||||||
|
switchOn.isChecked = false
|
||||||
|
isCancelled = false
|
||||||
|
return@setOnCheckedChangeListener
|
||||||
|
}
|
||||||
|
if (isChecked) {
|
||||||
|
startVpn()
|
||||||
|
} else {
|
||||||
|
stopVpn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val peersListView = findViewById<ListView>(R.id.peers)
|
||||||
//save to shared preferences
|
//save to shared preferences
|
||||||
val preferences =
|
val preferences =
|
||||||
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, currentPeers.sortedWith(compareBy { it.ping }))
|
val adapter = PeerInfoListAdapter(this, currentPeers.sortedWith(compareBy { it.ping }))
|
||||||
listView.adapter = adapter
|
peersListView.adapter = adapter
|
||||||
|
|
||||||
val copyAddressButton = findViewById<Button>(R.id.copyIp)
|
val copyAddressButton = findViewById<Button>(R.id.copyIp)
|
||||||
copyAddressButton.setOnClickListener {
|
copyAddressButton.setOnClickListener {
|
||||||
@ -133,6 +155,17 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateDNS(){
|
||||||
|
Log.d(TAG,"Update DNS")
|
||||||
|
val intent = Intent(this, YggdrasilTunService::class.java)
|
||||||
|
val TASK_CODE = 100
|
||||||
|
val pi = createPendingResult(TASK_CODE, intent, 0)
|
||||||
|
intent.putExtra(PARAM_PINTENT, pi)
|
||||||
|
intent.putExtra(COMMAND, UPDATE_DNS)
|
||||||
|
intent.putStringArrayListExtra(DNS, serializeDNSInfoSet2StringList(currentDNS))
|
||||||
|
startService(intent)
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@ -151,7 +184,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
startService(intent)
|
startService(intent)
|
||||||
}
|
}
|
||||||
if (requestCode == VPN_REQUEST_CODE && resultCode== Activity.RESULT_CANCELED){
|
if (requestCode == VPN_REQUEST_CODE && resultCode== Activity.RESULT_CANCELED){
|
||||||
//TODO implement
|
isCancelled = true
|
||||||
}
|
}
|
||||||
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){
|
||||||
@ -197,15 +230,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
||||||
preferences.edit().putStringSet(CURRENT_DNS, HashSet(currentDNS)).apply()
|
preferences.edit().putStringSet(CURRENT_DNS, HashSet(currentDNS)).apply()
|
||||||
if(isStarted){
|
if(isStarted){
|
||||||
//TODO implement UpdateConfig method in native interface and apply peer changes
|
updateDNS()
|
||||||
stopVpn()
|
|
||||||
finish()
|
|
||||||
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)
|
|
||||||
startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,34 +256,6 @@ class MainActivity : 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.main_menu, menu)
|
|
||||||
val item = menu.findItem(R.id.switchId) as MenuItem
|
|
||||||
item.setActionView(R.layout.menu_switch)
|
|
||||||
val switchOn = item
|
|
||||||
.actionView.findViewById<Switch>(R.id.switchOn)
|
|
||||||
if(isStarted){
|
|
||||||
switchOn.isChecked = true
|
|
||||||
if(startVpnFlag) {
|
|
||||||
startVpn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switchOn.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if(currentPeers.isEmpty()){
|
|
||||||
switchOn.isChecked = false
|
|
||||||
return@setOnCheckedChangeListener
|
|
||||||
}
|
|
||||||
if (isChecked) {
|
|
||||||
startVpn()
|
|
||||||
} else {
|
|
||||||
stopVpn()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showToast(text: String){
|
private fun showToast(text: String){
|
||||||
val duration = Toast.LENGTH_SHORT
|
val duration = Toast.LENGTH_SHORT
|
||||||
val toast = Toast.makeText(applicationContext, text, duration)
|
val toast = Toast.makeText(applicationContext, text, duration)
|
||||||
|
@ -10,6 +10,7 @@ import com.google.gson.Gson
|
|||||||
import dummy.ConduitEndpoint
|
import dummy.ConduitEndpoint
|
||||||
import io.github.chronosx88.yggdrasil.models.DNSInfo
|
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.Utils.Companion.convertPeerInfoSet2PeerIdSet
|
||||||
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2DNSInfoSet
|
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2DNSInfoSet
|
||||||
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2PeerInfoSet
|
import io.github.chronosx88.yggdrasil.models.config.Utils.Companion.deserializeStringList2PeerInfoSet
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@ -29,20 +30,12 @@ class YggdrasilTunService : VpnService() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "Yggdrasil-service"
|
private const val TAG = "Yggdrasil-service"
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun convertPeerInfoSet2PeerIdSet(list: Set<PeerInfo>): Set<String> {
|
|
||||||
var out = mutableSetOf<String>()
|
|
||||||
for(p in list) {
|
|
||||||
out.add(p.toString())
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private var tunInterface: ParcelFileDescriptor? = null
|
private var tunInterface: ParcelFileDescriptor? = null
|
||||||
private var tunInputStream: InputStream? = null
|
private var tunInputStream: InputStream? = null
|
||||||
private var tunOutputStream: OutputStream? = null
|
private var tunOutputStream: OutputStream? = null
|
||||||
private var scope: CoroutineScope? = null
|
private var scope: CoroutineScope? = null
|
||||||
|
private var address: String? = null
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
|
||||||
@ -57,10 +50,37 @@ class YggdrasilTunService : VpnService() {
|
|||||||
ygg = Yggdrasil()
|
ygg = Yggdrasil()
|
||||||
setupTunInterface(pi, peers, dns)
|
setupTunInterface(pi, peers, dns)
|
||||||
}
|
}
|
||||||
|
if (intent?.getStringExtra(MainActivity.COMMAND) == MainActivity.UPDATE_DNS) {
|
||||||
|
val pi: PendingIntent = intent.getParcelableExtra(MainActivity.PARAM_PINTENT)
|
||||||
|
val dns = deserializeStringList2DNSInfoSet(intent.getStringArrayListExtra(MainActivity.DNS))
|
||||||
|
setupIOStreams(dns)
|
||||||
|
}
|
||||||
|
|
||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupIOStreams(dns: MutableSet<DNSInfo>){
|
||||||
|
address = ygg.addressString
|
||||||
|
var builder = Builder()
|
||||||
|
.addAddress(address, 7)
|
||||||
|
.allowFamily(OsConstants.AF_INET)
|
||||||
|
.setMtu(MAX_PACKET_SIZE)
|
||||||
|
if (dns.size > 0) {
|
||||||
|
for (d in dns) {
|
||||||
|
builder.addDnsServer(d.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tunInterface!=null){
|
||||||
|
tunInterface!!.close()
|
||||||
|
tunInputStream!!.close()
|
||||||
|
tunOutputStream!!.close()
|
||||||
|
}
|
||||||
|
tunInterface = builder.establish()
|
||||||
|
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
|
||||||
|
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupTunInterface(
|
private fun setupTunInterface(
|
||||||
pi: PendingIntent,
|
pi: PendingIntent,
|
||||||
peers: Set<PeerInfo>,
|
peers: Set<PeerInfo>,
|
||||||
@ -74,32 +94,16 @@ class YggdrasilTunService : VpnService() {
|
|||||||
configJson = gson.toJson(config).toByteArray()
|
configJson = gson.toJson(config).toByteArray()
|
||||||
|
|
||||||
var yggConduitEndpoint = ygg.startJSON(configJson)
|
var yggConduitEndpoint = ygg.startJSON(configJson)
|
||||||
val address = ygg.addressString // hack for getting generic ipv6 string from NodeID
|
|
||||||
|
|
||||||
var builder = Builder()
|
setupIOStreams(dns)
|
||||||
.addAddress(address, 7)
|
|
||||||
.allowFamily(OsConstants.AF_INET)
|
|
||||||
.setMtu(MAX_PACKET_SIZE)
|
|
||||||
if (dns.size > 0) {
|
|
||||||
for (d in dns) {
|
|
||||||
builder.addDnsServer(d.address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tunInterface = builder.establish()
|
|
||||||
tunInputStream = FileInputStream(tunInterface!!.fileDescriptor)
|
|
||||||
tunOutputStream = FileOutputStream(tunInterface!!.fileDescriptor)
|
|
||||||
val job = SupervisorJob()
|
val job = SupervisorJob()
|
||||||
scope = CoroutineScope(Dispatchers.Default + job)
|
scope = CoroutineScope(Dispatchers.Default + job)
|
||||||
scope!!.launch {
|
scope!!.launch {
|
||||||
val buffer = ByteArray(2048)
|
val buffer = ByteArray(2048)
|
||||||
try {
|
|
||||||
while (!isClosed) {
|
while (!isClosed) {
|
||||||
readPacketsFromTun(yggConduitEndpoint, buffer)
|
readPacketsFromTun(yggConduitEndpoint, buffer)
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
tunInputStream!!.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
scope!!.launch {
|
scope!!.launch {
|
||||||
while (!isClosed) {
|
while (!isClosed) {
|
||||||
@ -144,6 +148,7 @@ class YggdrasilTunService : VpnService() {
|
|||||||
|
|
||||||
private fun readPacketsFromTun(yggConduitEndpoint: ConduitEndpoint, buffer: ByteArray) {
|
private fun readPacketsFromTun(yggConduitEndpoint: ConduitEndpoint, buffer: ByteArray) {
|
||||||
// Read the outgoing packet from the input stream.
|
// Read the outgoing packet from the input stream.
|
||||||
|
try{
|
||||||
val length = tunInputStream!!.read(buffer)
|
val length = tunInputStream!!.read(buffer)
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
val byteBuffer = ByteBuffer.allocate(length)
|
val byteBuffer = ByteBuffer.allocate(length)
|
||||||
@ -152,10 +157,12 @@ class YggdrasilTunService : VpnService() {
|
|||||||
} else {
|
} else {
|
||||||
Thread.sleep(10)
|
Thread.sleep(10)
|
||||||
}
|
}
|
||||||
|
}catch(e: IOException){
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writePacketsToTun(yggConduitEndpoint: ConduitEndpoint) {
|
private fun writePacketsToTun(yggConduitEndpoint: ConduitEndpoint) {
|
||||||
if(tunOutputStream != null) {
|
|
||||||
val buffer = yggConduitEndpoint.recv()
|
val buffer = yggConduitEndpoint.recv()
|
||||||
if(buffer!=null) {
|
if(buffer!=null) {
|
||||||
try {
|
try {
|
||||||
@ -165,7 +172,6 @@ class YggdrasilTunService : VpnService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun stopVpn(pi: PendingIntent) {
|
private fun stopVpn(pi: PendingIntent) {
|
||||||
isClosed = true;
|
isClosed = true;
|
||||||
|
@ -86,5 +86,14 @@ class Utils {
|
|||||||
return (System.currentTimeMillis() - start).toInt()
|
return (System.currentTimeMillis() - start).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun convertPeerInfoSet2PeerIdSet(list: Set<PeerInfo>): Set<String> {
|
||||||
|
var out = mutableSetOf<String>()
|
||||||
|
for(p in list) {
|
||||||
|
out.add(p.toString())
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,158 +1,48 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/grey"
|
tools:context=".MainActivity"
|
||||||
tools:context=".MainActivity">
|
android:background="@color/grey">
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/ipLayout"
|
android:id="@+id/appBarLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="20dp"
|
android:theme="@style/AppTheme.AppBarOverlay">
|
||||||
android:background="@drawable/info_panel_rounded_corner"
|
|
||||||
android:gravity="left"
|
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
android:visibility="gone">
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/ipLabel"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:elevation="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="IP address:"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:textColor="@color/dark_30"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
android:id="@+id/copyIp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:text="COPY"
|
android:orientation="horizontal">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:background="@android:color/transparent"/>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<TextView
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/ip"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="30dp"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="@android:color/transparent"
|
android:layout_marginEnd="70dp"
|
||||||
android:elevation="8dp"
|
android:background="?attr/colorPrimary"
|
||||||
android:gravity="center_vertical"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/copyIp"
|
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<Switch
|
||||||
android:id="@+id/peerLayout"
|
android:id="@+id/switchOn"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:background="@drawable/info_panel_rounded_corner"
|
|
||||||
android:gravity="left"
|
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/ipLayout">
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/ipPeers"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:background="@android:color/transparent"
|
android:layout_margin="10dp"
|
||||||
android:elevation="8dp"
|
android:theme="@style/SwitchTheme"
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="Peers:"
|
|
||||||
android:textColor="@color/dark_30"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
<Button
|
|
||||||
android:id="@+id/edit"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="EDIT"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:background="@android:color/transparent"/>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<ListView
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
android:id="@+id/peers"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:dividerHeight="0dp"
|
|
||||||
android:divider="@null"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
<include layout="@layout/content_main" />
|
||||||
|
|
||||||
<LinearLayout
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:background="@drawable/info_panel_rounded_corner"
|
|
||||||
android:gravity="left"
|
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/peerLayout">
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/dnsLabel"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:elevation="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="DNS:"
|
|
||||||
android:textColor="@color/dark_30"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
<Button
|
|
||||||
android:id="@+id/editDNS"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="EDIT"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:background="@android:color/transparent"/>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
<ListView
|
|
||||||
android:id="@+id/dns"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:dividerHeight="0dp"
|
|
||||||
android:divider="@null"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
156
app/src/main/res/layout/content_main.xml
Normal file
156
app/src/main/res/layout/content_main.xml
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:background="@color/grey">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ipLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="20dp"
|
||||||
|
android:background="@drawable/info_panel_rounded_corner"
|
||||||
|
android:gravity="left"
|
||||||
|
android:paddingLeft="20dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:visibility="gone">
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ipLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="IP address:"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:textColor="@color/dark_30"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/copyIp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="COPY"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:background="@android:color/transparent"/>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ip"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/copyIp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="@color/white"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/peerLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="20dp"
|
||||||
|
android:background="@drawable/info_panel_rounded_corner"
|
||||||
|
android:gravity="left"
|
||||||
|
android:paddingLeft="20dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/ipLayout">
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ipPeers"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="Peers:"
|
||||||
|
android:textColor="@color/dark_30"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
<Button
|
||||||
|
android:id="@+id/edit"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="EDIT"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:background="@android:color/transparent"/>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/peers"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:dividerHeight="0dp"
|
||||||
|
android:divider="@null"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="20dp"
|
||||||
|
android:background="@drawable/info_panel_rounded_corner"
|
||||||
|
android:gravity="left"
|
||||||
|
android:paddingLeft="20dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/peerLayout">
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dnsLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="DNS:"
|
||||||
|
android:textColor="@color/dark_30"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
<Button
|
||||||
|
android:id="@+id/editDNS"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="EDIT"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:background="@android:color/transparent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/dns"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:dividerHeight="0dp"
|
||||||
|
android:divider="@null"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -3,12 +3,5 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
<Switch
|
|
||||||
android:id="@+id/switchOn"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_margin="10dp"
|
|
||||||
android:theme="@style/SwitchTheme"/>
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
Loading…
x
Reference in New Issue
Block a user