mirror of
https://github.com/yggdrasil-network/yggdrasil-android.git
synced 2025-04-27 13:45:09 +03:00
Optimization and localizations. (#27)
* Optimized UI refresh to save battery. Extracted all strings to xml to enable localizations. * And added Russian localization.
This commit is contained in:
parent
8615d43761
commit
41569a9ee2
12 changed files with 274 additions and 157 deletions
|
@ -108,7 +108,7 @@ class DnsActivity : AppCompatActivity() {
|
|||
|
||||
view.findViewById<ImageButton>(R.id.deletePeerButton).setOnClickListener { button ->
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
||||
builder.setTitle("Remove ${server}?")
|
||||
builder.setTitle(getString(R.string.dns_remove_title, server))
|
||||
builder.setPositiveButton(getString(R.string.remove)) { dialog, _ ->
|
||||
servers.removeAt(button.tag as Int)
|
||||
preferences.edit().apply {
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
package eu.neilalexander.yggdrasil
|
||||
|
||||
import android.app.Application
|
||||
import android.content.IntentFilter
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
|
||||
class GlobalApplication: Application() {
|
||||
private var state = PacketTunnelState
|
||||
private lateinit var config: ConfigurationProxy
|
||||
var updaterConnections: Int = 0
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
config = ConfigurationProxy(applicationContext)
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
state, IntentFilter(PacketTunnelProvider.RECEIVER_INTENT)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
super.onTerminate()
|
||||
fun subscribe() {
|
||||
updaterConnections++
|
||||
}
|
||||
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(state)
|
||||
fun unsubscribe() {
|
||||
if (updaterConnections > 0) {
|
||||
updaterConnections--
|
||||
}
|
||||
}
|
||||
|
||||
fun needUiUpdates(): Boolean {
|
||||
return updaterConnections > 0
|
||||
}
|
||||
}
|
|
@ -12,12 +12,12 @@ import android.widget.Toast
|
|||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import eu.neilalexander.yggdrasil.PacketTunnelProvider.Companion.STATE_INTENT
|
||||
import mobile.Mobile
|
||||
import org.json.JSONArray
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private var state = PacketTunnelState
|
||||
|
||||
private lateinit var enabledSwitch: Switch
|
||||
private lateinit var enabledLabel: TextView
|
||||
private lateinit var ipAddressLabel: TextView
|
||||
|
@ -116,20 +116,27 @@ class MainActivity : AppCompatActivity() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
receiver, IntentFilter(PacketTunnelState.RECEIVER_INTENT)
|
||||
receiver, IntentFilter(STATE_INTENT)
|
||||
)
|
||||
val preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this.baseContext)
|
||||
val serverString = preferences.getString(KEY_DNS_SERVERS, "")
|
||||
if (serverString!!.isNotEmpty()) {
|
||||
val servers = serverString.split(",")
|
||||
dnsLabel.text = when (servers.size) {
|
||||
0 -> "No servers"
|
||||
1 -> "1 server"
|
||||
else -> "${servers.size} servers"
|
||||
0 -> getString(R.string.dns_no_servers)
|
||||
1 -> getString(R.string.dns_one_server)
|
||||
else -> getString(R.string.dns_many_servers, servers.size)
|
||||
}
|
||||
} else {
|
||||
dnsLabel.text = "No servers"
|
||||
dnsLabel.text = getString(R.string.dns_no_servers)
|
||||
}
|
||||
(application as GlobalApplication).subscribe()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
(application as GlobalApplication).unsubscribe()
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
|
||||
}
|
||||
|
||||
private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
|
@ -138,33 +145,39 @@ class MainActivity : AppCompatActivity() {
|
|||
"state" -> {
|
||||
enabledLabel.text = if (intent.getBooleanExtra("started", false)) {
|
||||
enabledSwitch.isChecked = true
|
||||
if (state.dhtCount() == 0) {
|
||||
var count = 0
|
||||
if (intent.hasExtra("dht")) {
|
||||
val dht = intent.getStringExtra("dht")
|
||||
if (dht != null && dht != "null") {
|
||||
val dhtState = JSONArray(dht)
|
||||
count = dhtState.length()
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
enabledLabel.setTextColor(Color.RED)
|
||||
"No connectivity"
|
||||
getString(R.string.main_no_connectivity)
|
||||
} else {
|
||||
enabledLabel.setTextColor(Color.GREEN)
|
||||
"Enabled"
|
||||
getString(R.string.main_enabled)
|
||||
}
|
||||
} else {
|
||||
enabledSwitch.isChecked = false
|
||||
enabledLabel.setTextColor(Color.GRAY)
|
||||
"Not enabled"
|
||||
getString(R.string.main_disabled)
|
||||
}
|
||||
ipAddressLabel.text = intent.getStringExtra("ip") ?: "N/A"
|
||||
subnetLabel.text = intent.getStringExtra("subnet") ?: "N/A"
|
||||
coordinatesLabel.text = intent.getStringExtra("coords") ?: "[]"
|
||||
peersLabel.text = when (val count = state.peerCount()) {
|
||||
0 -> "No peers"
|
||||
1 -> "1 peer"
|
||||
else -> "$count peers"
|
||||
if (intent.hasExtra("peers")) {
|
||||
val peerState = JSONArray(intent.getStringExtra("peers") ?: "[]")
|
||||
peersLabel.text = when (val count = peerState.length()) {
|
||||
0 -> getString(R.string.main_no_peers)
|
||||
1 -> getString(R.string.main_one_peer)
|
||||
else -> getString(R.string.main_many_peers, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ private const val TAG = "PacketTunnelProvider"
|
|||
|
||||
class PacketTunnelProvider: VpnService() {
|
||||
companion object {
|
||||
const val RECEIVER_INTENT = "eu.neilalexander.yggdrasil.PacketTunnelProvider.MESSAGE"
|
||||
const val STATE_INTENT = "eu.neilalexander.yggdrasil.PacketTunnelProvider.STATE_MESSAGE"
|
||||
|
||||
const val ACTION_START = "eu.neilalexander.yggdrasil.PacketTunnelProvider.START"
|
||||
const val ACTION_STOP = "eu.neilalexander.yggdrasil.PacketTunnelProvider.STOP"
|
||||
|
@ -130,7 +130,7 @@ class PacketTunnelProvider: VpnService() {
|
|||
updater()
|
||||
}
|
||||
|
||||
val intent = Intent(RECEIVER_INTENT)
|
||||
val intent = Intent(STATE_INTENT)
|
||||
intent.putExtra("type", "state")
|
||||
intent.putExtra("started", true)
|
||||
intent.putExtra("ip", yggdrasil.addressString)
|
||||
|
@ -173,7 +173,7 @@ class PacketTunnelProvider: VpnService() {
|
|||
updateThread = null
|
||||
}
|
||||
|
||||
val intent = Intent(RECEIVER_INTENT)
|
||||
val intent = Intent(STATE_INTENT)
|
||||
intent.putExtra("type", "state")
|
||||
intent.putExtra("started", false)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
|
@ -183,15 +183,23 @@ class PacketTunnelProvider: VpnService() {
|
|||
|
||||
private fun updater() {
|
||||
updates@ while (started.get()) {
|
||||
val intent = Intent(RECEIVER_INTENT)
|
||||
intent.putExtra("type", "state")
|
||||
intent.putExtra("started", true)
|
||||
intent.putExtra("ip", yggdrasil.addressString)
|
||||
intent.putExtra("subnet", yggdrasil.subnetString)
|
||||
intent.putExtra("coords", yggdrasil.coordsString)
|
||||
intent.putExtra("peers", yggdrasil.peersJSON)
|
||||
intent.putExtra("dht", yggdrasil.dhtjson)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
if ((application as GlobalApplication).needUiUpdates()) {
|
||||
val intent = Intent(STATE_INTENT)
|
||||
intent.putExtra("type", "state")
|
||||
intent.putExtra("started", true)
|
||||
intent.putExtra("ip", yggdrasil.addressString)
|
||||
intent.putExtra("subnet", yggdrasil.subnetString)
|
||||
intent.putExtra("coords", yggdrasil.coordsString)
|
||||
intent.putExtra("peers", yggdrasil.peersJSON)
|
||||
intent.putExtra("dht", yggdrasil.dhtjson)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(1000)
|
||||
} catch (e: InterruptedException) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (Thread.currentThread().isInterrupted) {
|
||||
break@updates
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package eu.neilalexander.yggdrasil
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import org.json.JSONArray
|
||||
|
||||
object PacketTunnelState: BroadcastReceiver() {
|
||||
var dhtState: JSONArray? = null
|
||||
private set
|
||||
|
||||
var peersState: JSONArray? = null
|
||||
private set
|
||||
|
||||
const val RECEIVER_INTENT = "eu.neilalexander.yggdrasil.PacketTunnelState.MESSAGE"
|
||||
|
||||
fun peerCount(): Int {
|
||||
if (peersState == null) {
|
||||
return 0
|
||||
}
|
||||
return peersState!!.length()
|
||||
}
|
||||
|
||||
fun dhtCount(): Int {
|
||||
if (dhtState == null) {
|
||||
return 0
|
||||
}
|
||||
return dhtState!!.length()
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
when (intent.getStringExtra("type")) {
|
||||
"state" -> {
|
||||
var dht = intent.getStringExtra("dht")
|
||||
var peers = intent.getStringExtra("peers")
|
||||
|
||||
if (dht == null || dht == "null") {
|
||||
dht = "[]"
|
||||
}
|
||||
if (peers == null || peers == "null") {
|
||||
peers = "[]"
|
||||
}
|
||||
|
||||
peersState = JSONArray(peers)
|
||||
dhtState = JSONArray(dht)
|
||||
|
||||
intent.action = RECEIVER_INTENT
|
||||
LocalBroadcastManager.getInstance(context!!).sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +1,25 @@
|
|||
package eu.neilalexander.yggdrasil
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
class PeersActivity : AppCompatActivity() {
|
||||
private var state = PacketTunnelState
|
||||
private lateinit var config: ConfigurationProxy
|
||||
private lateinit var inflater: LayoutInflater
|
||||
private lateinit var peers: Array<JSONObject>
|
||||
|
||||
private lateinit var connectedTableLayout: TableLayout
|
||||
private lateinit var connectedTableLabel: TextView
|
||||
|
@ -29,6 +35,7 @@ class PeersActivity : AppCompatActivity() {
|
|||
|
||||
config = ConfigurationProxy(applicationContext)
|
||||
inflater = LayoutInflater.from(this)
|
||||
peers = emptyArray()
|
||||
|
||||
connectedTableLayout = findViewById(R.id.connectedPeersTableLayout)
|
||||
connectedTableLabel = findViewById(R.id.connectedPeersLabel)
|
||||
|
@ -52,16 +59,16 @@ class PeersActivity : AppCompatActivity() {
|
|||
val view = inflater.inflate(R.layout.dialog_addpeer, null)
|
||||
val input = view.findViewById<TextInputEditText>(R.id.addPeerInput)
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
|
||||
builder.setTitle("Add Configured Peer")
|
||||
builder.setTitle(getString(R.string.peers_add_peer))
|
||||
builder.setView(view)
|
||||
builder.setPositiveButton("Add") { dialog, _ ->
|
||||
builder.setPositiveButton(getString(R.string.peers_add)) { dialog, _ ->
|
||||
config.updateJSON { json ->
|
||||
json.getJSONArray("Peers").put(input.text.toString().trim())
|
||||
}
|
||||
dialog.dismiss()
|
||||
updateConfiguredPeers()
|
||||
}
|
||||
builder.setNegativeButton("Cancel") { dialog, _ ->
|
||||
builder.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
builder.show()
|
||||
|
@ -70,22 +77,32 @@ class PeersActivity : AppCompatActivity() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
receiver, IntentFilter(PacketTunnelProvider.STATE_INTENT)
|
||||
)
|
||||
(application as GlobalApplication).subscribe()
|
||||
|
||||
updateConfiguredPeers()
|
||||
updateConnectedPeers()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
(application as GlobalApplication).unsubscribe()
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
|
||||
}
|
||||
|
||||
private fun updateConfiguredPeers() {
|
||||
val peers = config.getJSON().getJSONArray("Peers")
|
||||
|
||||
when (peers.length()) {
|
||||
0 -> {
|
||||
configuredTableLayout.visibility = View.GONE
|
||||
configuredTableLabel.text = "No peers currently configured"
|
||||
configuredTableLabel.text = getString(R.string.peers_no_configured_title)
|
||||
}
|
||||
else -> {
|
||||
configuredTableLayout.visibility = View.VISIBLE
|
||||
configuredTableLabel.text = "Configured Peers"
|
||||
configuredTableLabel.text = getString(R.string.peers_configured_title)
|
||||
|
||||
configuredTableLayout.removeAllViewsInLayout()
|
||||
for (i in 0 until peers.length()) {
|
||||
|
@ -96,15 +113,15 @@ class PeersActivity : AppCompatActivity() {
|
|||
|
||||
view.findViewById<ImageButton>(R.id.deletePeerButton).setOnClickListener { button ->
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
||||
builder.setTitle("Remove ${peer}?")
|
||||
builder.setPositiveButton("Remove") { dialog, _ ->
|
||||
builder.setTitle(getString(R.string.peers_remove_title, peer))
|
||||
builder.setPositiveButton(getString(R.string.peers_remove)) { dialog, _ ->
|
||||
config.updateJSON { json ->
|
||||
json.getJSONArray("Peers").remove(button.tag as Int)
|
||||
}
|
||||
dialog.dismiss()
|
||||
updateConfiguredPeers()
|
||||
}
|
||||
builder.setNegativeButton("Cancel") { dialog, _ ->
|
||||
builder.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
builder.show()
|
||||
|
@ -116,20 +133,17 @@ class PeersActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun updateConnectedPeers() {
|
||||
val peers = state.peersState ?: JSONArray("[]")
|
||||
|
||||
when (peers.length()) {
|
||||
when (peers.size) {
|
||||
0 -> {
|
||||
connectedTableLayout.visibility = View.GONE
|
||||
connectedTableLabel.text = "No peers currently connected"
|
||||
connectedTableLabel.text = getString(R.string.peers_no_connected_title)
|
||||
}
|
||||
else -> {
|
||||
connectedTableLayout.visibility = View.VISIBLE
|
||||
connectedTableLabel.text = "Connected Peers"
|
||||
connectedTableLabel.text = getString(R.string.peers_connected_title)
|
||||
|
||||
connectedTableLayout.removeAllViewsInLayout()
|
||||
for (i in 0 until peers.length()) {
|
||||
val peer = peers.getJSONObject(i)
|
||||
for (peer in peers) {
|
||||
val view = inflater.inflate(R.layout.peers_connected, null)
|
||||
val ip = peer.getString("IP")
|
||||
view.findViewById<TextView>(R.id.addressLabel).text = ip
|
||||
|
@ -139,4 +153,23 @@ class PeersActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
when (intent.getStringExtra("type")) {
|
||||
"state" -> {
|
||||
if (intent.hasExtra("peers")) {
|
||||
val peersArray = JSONArray(intent.getStringExtra("peers") ?: "[]")
|
||||
val array = Array(peersArray.length()) { i ->
|
||||
peersArray.getJSONObject(i)
|
||||
}
|
||||
array.sortWith(compareBy { it.getString("IP") })
|
||||
peers = array
|
||||
|
||||
updateConnectedPeers()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ import android.os.Bundle
|
|||
import android.view.ContextThemeWrapper
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.*
|
||||
import androidx.core.view.setPadding
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import org.json.JSONObject
|
||||
|
||||
|
@ -33,7 +32,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
|
||||
deviceNameEntry.doOnTextChanged { text, _, _, _ ->
|
||||
config.updateJSON { cfg ->
|
||||
var nodeinfo = cfg.optJSONObject("NodeInfo")
|
||||
val nodeinfo = cfg.optJSONObject("NodeInfo")
|
||||
if (nodeinfo == null) {
|
||||
cfg.put("NodeInfo", JSONObject("{}"))
|
||||
}
|
||||
|
@ -42,16 +41,16 @@ class SettingsActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
resetConfigurationRow.setOnClickListener {
|
||||
var view = inflater.inflate(R.layout.dialog_resetconfig, null)
|
||||
val view = inflater.inflate(R.layout.dialog_resetconfig, null)
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
|
||||
builder.setTitle("Warning")
|
||||
builder.setTitle(getString(R.string.settings_warning_title))
|
||||
builder.setView(view)
|
||||
builder.setPositiveButton("Reset") { dialog, _ ->
|
||||
builder.setPositiveButton(getString(R.string.settings_reset)) { dialog, _ ->
|
||||
config.resetJSON()
|
||||
updateView()
|
||||
dialog.dismiss()
|
||||
}
|
||||
builder.setNegativeButton("Cancel") { dialog, _ ->
|
||||
builder.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
builder.show()
|
||||
|
@ -68,7 +67,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
updateView()
|
||||
}
|
||||
|
||||
fun updateView() {
|
||||
private fun updateView() {
|
||||
val nodeinfo = config.getJSON().optJSONObject("NodeInfo")
|
||||
if (nodeinfo != null) {
|
||||
deviceNameEntry.setText(nodeinfo.getString("name"), TextView.BufferType.EDITABLE)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8pt"
|
||||
android:text="Yggdrasil"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?attr/textDefault"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
@ -47,7 +47,7 @@
|
|||
android:layout_marginRight="8pt"
|
||||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:text="Status"
|
||||
android:text="@string/main_status"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -84,7 +84,7 @@
|
|||
android:id="@+id/enableYggdrasilLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enable Yggdrasil"
|
||||
android:text="@string/main_enable_yggdrasil"
|
||||
android:textColor="?attr/textDefault"
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
@ -114,7 +114,7 @@
|
|||
android:id="@+id/yggdrasilStatusLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Not enabled"
|
||||
android:text="@string/main_disabled"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
@ -137,7 +137,7 @@
|
|||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Statistics"
|
||||
android:text="@string/main_statistics"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -175,7 +175,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:text="IP"
|
||||
android:text="@string/main_ip"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<TextView
|
||||
|
@ -188,7 +188,7 @@
|
|||
android:scrollHorizontally="true"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:text="N/A"
|
||||
android:text="@string/main_not_available"
|
||||
android:textAlignment="viewEnd"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="14sp" />
|
||||
|
@ -209,7 +209,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:text="Subnet"
|
||||
android:text="@string/main_subnet"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<TextView
|
||||
|
@ -222,7 +222,7 @@
|
|||
android:scrollHorizontally="true"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:text="N/A"
|
||||
android:text="@string/main_not_available"
|
||||
android:textAlignment="viewEnd"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="14sp" />
|
||||
|
@ -244,7 +244,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:text="Coordinates"
|
||||
android:text="@string/main_coordinates"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<TextView
|
||||
|
@ -280,7 +280,7 @@
|
|||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Configuration"
|
||||
android:text="@string/main_configuration"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -318,7 +318,7 @@
|
|||
android:id="@+id/multicastLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Peers"
|
||||
android:text="@string/main_peers"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<Space
|
||||
|
@ -331,7 +331,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.5"
|
||||
android:text="No peers"
|
||||
android:text="@string/main_no_peers"
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
<ImageView
|
||||
|
@ -362,7 +362,7 @@
|
|||
android:id="@+id/dnsLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="DNS servers"
|
||||
android:text="@string/main_dns_servers"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<Space
|
||||
|
@ -375,7 +375,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.5"
|
||||
android:text="No servers"
|
||||
android:text="@string/dns_no_servers"
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
<ImageView
|
||||
|
@ -405,7 +405,7 @@
|
|||
android:id="@+id/settingsLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Settings"
|
||||
android:text="@string/main_settings"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<Space
|
||||
|
@ -445,7 +445,7 @@
|
|||
android:id="@+id/versionLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Version"
|
||||
android:text="@string/main_version"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<Space
|
||||
|
@ -458,7 +458,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.5"
|
||||
android:text="Unknown"
|
||||
android:text="@string/main_unknown"
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
</TableRow>
|
||||
|
@ -475,7 +475,7 @@
|
|||
android:layout_marginRight="8pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="You must re-enable Yggdrasil after modifying Peers, DNS servers or Settings to make any changes effective."
|
||||
android:text="@string/main_bottom_warning"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8pt"
|
||||
android:text="Peers"
|
||||
android:text="@string/main_peers"
|
||||
android:textColor="?attr/textDefault"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
@ -67,7 +67,7 @@
|
|||
android:layout_marginRight="8pt"
|
||||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:text="Connected Peers"
|
||||
android:text="@string/peers_connected_title"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -101,7 +101,7 @@
|
|||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Configured Peers"
|
||||
android:text="@string/peers_configured_title"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -134,7 +134,7 @@
|
|||
android:layout_marginBottom="4pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Yggdrasil will automatically attempt to connect to configured peers when started. If you configure more than one peer, your device may carry traffic on behalf of other network nodes. Avoid this by configuring only a single peer."
|
||||
android:text="@string/configured_peers_hint"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -153,7 +153,7 @@
|
|||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Peer Connectivity"
|
||||
android:text="@string/peer_connectivity_title"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -188,7 +188,7 @@
|
|||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Discoverable over multicast"
|
||||
android:text="@string/discoverable_over_multicast"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<Space
|
||||
|
@ -215,7 +215,7 @@
|
|||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Search for multicast peers"
|
||||
android:text="@string/search_for_multicast_peers"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<Space
|
||||
|
@ -242,7 +242,7 @@
|
|||
android:layout_marginRight="8pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Multicast peers will be discovered on the same Wi-Fi network or via USB. Data charges may apply when using mobile data. You can prevent data usage in the device settings."
|
||||
android:text="@string/peer_connectivity_hint"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8pt"
|
||||
android:text="Settings"
|
||||
android:text="@string/main_settings"
|
||||
android:textColor="?attr/textDefault"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
@ -57,7 +57,7 @@
|
|||
android:layout_marginRight="8pt"
|
||||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:text="Node Info"
|
||||
android:text="@string/node_info"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -93,7 +93,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Device Name"
|
||||
android:text="@string/device_name"
|
||||
android:textColor="?attr/textDefault" />
|
||||
|
||||
<EditText
|
||||
|
@ -103,7 +103,7 @@
|
|||
android:layout_weight="1"
|
||||
android:background="@null"
|
||||
android:ems="10"
|
||||
android:hint="Tap to edit"
|
||||
android:hint="@string/tap_to_edit"
|
||||
android:inputType="textPersonName"
|
||||
android:padding="0pt"
|
||||
android:textAlignment="textEnd"
|
||||
|
@ -124,7 +124,7 @@
|
|||
android:layout_marginBottom="4pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Information entered here is public and may be shown on network maps."
|
||||
android:text="@string/node_info_hint"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -140,7 +140,7 @@
|
|||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Public Key"
|
||||
android:text="@string/public_key"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -180,7 +180,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:text="Public Key"
|
||||
android:text="@string/public_key"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -198,7 +198,7 @@
|
|||
android:layout_marginBottom="4pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Your public key forms your identity on the network. It is safe to be shared."
|
||||
android:text="@string/public_key_hint"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -217,7 +217,7 @@
|
|||
android:layout_marginBottom="2pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Reset"
|
||||
android:text="@string/settings_reset"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
@ -251,7 +251,7 @@
|
|||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Reset configuration"
|
||||
android:text="@string/reset_configuration"
|
||||
android:textColor="@android:color/holo_red_dark" />
|
||||
</TableRow>
|
||||
</TableLayout>
|
||||
|
@ -266,7 +266,7 @@
|
|||
android:layout_marginRight="8pt"
|
||||
android:alpha="0.7"
|
||||
android:paddingRight="8pt"
|
||||
android:text="Resetting will overwrite with newly generated configuration. Your public keys and IP address on the network will change."
|
||||
android:text="@string/reset_configuration_hint"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp" />
|
||||
|
|
68
app/src/main/res/values-ru/strings.xml
Normal file
68
app/src/main/res/values-ru/strings.xml
Normal file
|
@ -0,0 +1,68 @@
|
|||
<resources>
|
||||
<string name="app_name">Yggdrasil</string>
|
||||
<string name="copied_to_clipboard">Скопировано в буфер</string>
|
||||
<string name="dns_configured_servers_hint">Эти серверы DNS будут использоваться при включении Yggdrasil. Заметьте, что все запросы в DNS, даже о доменах не в Yggdrasil, будут отправляться на эти серверы.</string>
|
||||
<string name="dns_configured_servers_hint_empty">Yggdrasil не будет переопределять серверы DNS при старте. Все запросы DNS будут разрешаться серверами по умолчанию.</string>
|
||||
<string name="dns_usable_servers_hint">Эти серверы DNS предоставляются членами коммюнити. Нажмите кнопку + чтобы добавить их в список выше. Долгое нажатие чтобы посмотреть информацию.</string>
|
||||
<string name="dns_no_configured_servers">Серверы не настроены</string>
|
||||
<string name="dns_configured_servers">Настроенные серверы</string>
|
||||
<string name="dns_server_info_revertron">Этот сервер поддерживает работу с обычными доменами ICANN, системой ALFIS, доменами OpenNIC.\n\nКроме того, он блокирует рекламу, системы слежения и зловредные домены.\n\nАдминистратор сервера Revertron.</string>
|
||||
<string name="dns_server_info_dialog_title">О сервере</string>
|
||||
<string name="ok">Ок</string>
|
||||
<string name="cancel">Отмена</string>
|
||||
<string name="remove">Убрать</string>
|
||||
<string name="add">Добавить</string>
|
||||
<string name="dns_add_server_dialog_title">Добавить сервер DNS</string>
|
||||
<string name="dns_activity_title">DNS</string>
|
||||
<string name="dns_usable_servers">Рекомендуемые серверы</string>
|
||||
<string name="dns_fix_chrome_based_browsers">Обхитрить браузеры на основе Chrome</string>
|
||||
<string name="dns_fix_chrome_based_browsers_hint">Если у вас нет обычного подключения по IPv6, эта опция должна заставить браузеры на движке Chrome всё равно запрашивать записи IPv6.</string>
|
||||
<string name="dns_fixes">DNS трюки</string>
|
||||
<string name="dns_no_servers">Нет серверов</string>
|
||||
<string name="dns_one_server">1 сервер</string>
|
||||
<string name="dns_many_servers">%d сервера/серверов</string>
|
||||
<string name="dns_remove_title">Убрать %s?</string>
|
||||
<string name="main_no_connectivity">Нет подключения</string>
|
||||
<string name="main_enabled">Включено</string>
|
||||
<string name="main_disabled">Выключено</string>
|
||||
<string name="main_no_peers">Нет пиров</string>
|
||||
<string name="main_one_peer">1 пир</string>
|
||||
<string name="main_many_peers">%d пира/пиров</string>
|
||||
<string name="peers_add_peer">Добавить пира в конфиг</string>
|
||||
<string name="peers_add">Добавить</string>
|
||||
<string name="peers_remove_title">Убрать %s?</string>
|
||||
<string name="peers_remove">Убрать</string>
|
||||
<string name="peers_no_configured_title">Пиры не добавлены</string>
|
||||
<string name="peers_configured_title">Добавленные пиры</string>
|
||||
<string name="peers_no_connected_title">Нет подключенных пиров</string>
|
||||
<string name="peers_connected_title">Подключенные пиры</string>
|
||||
<string name="settings_warning_title">Внимание</string>
|
||||
<string name="settings_reset">Сброс</string>
|
||||
<string name="main_status">Состояние</string>
|
||||
<string name="main_enable_yggdrasil">Включить Yggdrasil</string>
|
||||
<string name="main_statistics">Статистика</string>
|
||||
<string name="main_not_available">Н/Д</string>
|
||||
<string name="main_ip">Адрес</string>
|
||||
<string name="main_subnet">Подсеть</string>
|
||||
<string name="main_coordinates">Координаты</string>
|
||||
<string name="main_configuration">Конфигурация</string>
|
||||
<string name="main_peers">Пиры</string>
|
||||
<string name="main_dns_servers">Серверы DNS</string>
|
||||
<string name="main_settings">Настройки</string>
|
||||
<string name="main_version">Версия</string>
|
||||
<string name="main_unknown">Не известно</string>
|
||||
<string name="main_bottom_warning">Вы должны перезапустить Yggdrasil после изменения пиров, серверов DNS или настроек, чтобы изменения вступили в силу.</string>
|
||||
<string name="peer_connectivity_title">Подключения пиров</string>
|
||||
<string name="discoverable_over_multicast">Находимый через multicast</string>
|
||||
<string name="search_for_multicast_peers">Искать пиров через multicast</string>
|
||||
<string name="configured_peers_hint">Yggdrasil будет пытаться подключаться к этим пирам автоматически. Если вы добавите несколько пиров, ваше устройство может быть использовано для переноса данных между другими узлами сети. Чтобы этого избежать настройте только один пир.</string>
|
||||
<string name="peer_connectivity_hint">Пиры могут быть найдены с помощью Multicast если они находятся в той же Wi-Fi сети, либо через USB. Трафик в мобильной сети может быть платным. Вы можете отключить мобильные данные в настройках устройства.</string>
|
||||
<string name="node_info">Об узле</string>
|
||||
<string name="device_name">Название устройства</string>
|
||||
<string name="tap_to_edit">Нажмите для изменения</string>
|
||||
<string name="node_info_hint">Эта информация публична и может появиться на картах сети.</string>
|
||||
<string name="public_key">Публичный ключ</string>
|
||||
<string name="public_key_hint">Ваш публичный ключ идентифицирует вас в сети. Его распространение безопасно.</string>
|
||||
<string name="reset_configuration">Сбросить настройки</string>
|
||||
<string name="reset_configuration_hint">Сброс создаст полностью новые настройки. Это изменит ваш публичный ключ и адрес IP.</string>
|
||||
</resources>
|
|
@ -18,4 +18,51 @@
|
|||
<string name="dns_fix_chrome_based_browsers">Fix Chrome-based browsers</string>
|
||||
<string name="dns_fix_chrome_based_browsers_hint">If you do not have IPv6 internet connectivity, this option should help Chrome-based browsers to resolve Yggdrasil domain names correctly.</string>
|
||||
<string name="dns_fixes">DNS fixes</string>
|
||||
<string name="dns_no_servers">No servers</string>
|
||||
<string name="dns_one_server">1 server</string>
|
||||
<string name="dns_many_servers">%d server</string>
|
||||
<string name="dns_remove_title">Remove %s?</string>
|
||||
<string name="main_no_connectivity">No connectivity</string>
|
||||
<string name="main_enabled">Enabled</string>
|
||||
<string name="main_disabled">Not enabled</string>
|
||||
<string name="main_no_peers">No peers</string>
|
||||
<string name="main_one_peer">1 peer</string>
|
||||
<string name="main_many_peers">%d peers</string>
|
||||
<string name="peers_add_peer">Add Configured Peer</string>
|
||||
<string name="peers_add">Add</string>
|
||||
<string name="peers_remove_title">Remove %s?</string>
|
||||
<string name="peers_remove">Remove</string>
|
||||
<string name="peers_no_configured_title">No peers currently configured</string>
|
||||
<string name="peers_configured_title">Configured Peers</string>
|
||||
<string name="peers_no_connected_title">No peers currently connected</string>
|
||||
<string name="peers_connected_title">Connected Peers</string>
|
||||
<string name="settings_warning_title">Warning</string>
|
||||
<string name="settings_reset">Reset</string>
|
||||
<string name="main_status">Status</string>
|
||||
<string name="main_enable_yggdrasil">Enable Yggdrasil</string>
|
||||
<string name="main_statistics">Statistics</string>
|
||||
<string name="main_not_available">N/A</string>
|
||||
<string name="main_ip">IP</string>
|
||||
<string name="main_subnet">Subnet</string>
|
||||
<string name="main_coordinates">Coordinates</string>
|
||||
<string name="main_configuration">Configuration</string>
|
||||
<string name="main_peers">Peers</string>
|
||||
<string name="main_dns_servers">DNS servers</string>
|
||||
<string name="main_settings">Settings</string>
|
||||
<string name="main_version">Version</string>
|
||||
<string name="main_unknown">Unknown</string>
|
||||
<string name="main_bottom_warning">You must re-enable Yggdrasil after modifying Peers, DNS servers or Settings to make any changes effective.</string>
|
||||
<string name="peer_connectivity_title">Peer Connectivity</string>
|
||||
<string name="discoverable_over_multicast">Discoverable over multicast</string>
|
||||
<string name="search_for_multicast_peers">Search for multicast peers</string>
|
||||
<string name="configured_peers_hint">Yggdrasil will automatically attempt to connect to configured peers when started. If you configure more than one peer, your device may carry traffic on behalf of other network nodes. Avoid this by configuring only a single peer.</string>
|
||||
<string name="peer_connectivity_hint">Multicast peers will be discovered on the same Wi-Fi network or via USB. Data charges may apply when using mobile data. You can prevent data usage in the device settings.</string>
|
||||
<string name="node_info">Node Info</string>
|
||||
<string name="device_name">Device Name</string>
|
||||
<string name="tap_to_edit">Tap to edit</string>
|
||||
<string name="node_info_hint">Information entered here is public and may be shown on network maps.</string>
|
||||
<string name="public_key">Public Key</string>
|
||||
<string name="public_key_hint">Your public key forms your identity on the network. It is safe to be shared.</string>
|
||||
<string name="reset_configuration">Reset configuration</string>
|
||||
<string name="reset_configuration_hint">Resetting will overwrite with newly generated configuration. Your public keys and IP address on the network will change.</string>
|
||||
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue