mirror of
https://github.com/openlibrecommunity/olcng.git
synced 2026-07-03 14:05:17 +02:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b30fc13b0d | |||
| a9f5844b84 | |||
| 518edd096b | |||
| 450542d3b8 | |||
| b775851960 | |||
| 4c52c1e45c | |||
| e55ad93c52 | |||
| db931be24e | |||
| 1f1d110a82 | |||
| 2912d17aca | |||
| 261bd389f6 | |||
| 2c9eb2d8af | |||
| 35a396ea0a | |||
| 0fa72f5ee1 |
@@ -74,6 +74,7 @@ object AppConfig {
|
|||||||
const val PREF_HEV_TUNNEL_RW_TIMEOUT = "pref_hev_tunnel_rw_timeout_v2"
|
const val PREF_HEV_TUNNEL_RW_TIMEOUT = "pref_hev_tunnel_rw_timeout_v2"
|
||||||
const val PREF_AUTO_SORT_AFTER_TEST = "pref_auto_sort_after_test"
|
const val PREF_AUTO_SORT_AFTER_TEST = "pref_auto_sort_after_test"
|
||||||
const val PREF_SHOW_COPY_BUTTON = "pref_show_copy_button"
|
const val PREF_SHOW_COPY_BUTTON = "pref_show_copy_button"
|
||||||
|
const val PREF_SHOW_SERVER_IP = "pref_show_server_ip"
|
||||||
const val PREF_DYNAMIC_COLORS = "pref_dynamic_colors"
|
const val PREF_DYNAMIC_COLORS = "pref_dynamic_colors"
|
||||||
const val PREF_SUBSCRIPTIONS_BOTTOM = "pref_subscriptions_bottom"
|
const val PREF_SUBSCRIPTIONS_BOTTOM = "pref_subscriptions_bottom"
|
||||||
|
|
||||||
|
|||||||
@@ -612,18 +612,19 @@ object AngConfigManager {
|
|||||||
Log.i(AppConfig.TAG, url)
|
Log.i(AppConfig.TAG, url)
|
||||||
val userAgent = it.subscription.userAgent
|
val userAgent = it.subscription.userAgent
|
||||||
|
|
||||||
val timeout = if (url.startsWith("https://key.zarazaex.xyz/sub")) 3000 else 6000
|
val proxyTimeout = if (url.startsWith("https://key.zarazaex.xyz/sub")) 3000 else 5000
|
||||||
|
val directTimeout = if (url.startsWith("https://key.zarazaex.xyz/sub")) 3000 else 11000
|
||||||
|
|
||||||
var configText = try {
|
var configText = try {
|
||||||
val httpPort = SettingsManager.getHttpPort()
|
val httpPort = SettingsManager.getHttpPort()
|
||||||
HttpUtil.getUrlContentWithUserAgent(url, userAgent, timeout, httpPort)
|
HttpUtil.getUrlContentWithUserAgent(url, userAgent, proxyTimeout, httpPort)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(AppConfig.ANG_PACKAGE, "Update subscription: proxy not ready or other error", e)
|
Log.e(AppConfig.ANG_PACKAGE, "Update subscription: proxy not ready or other error", e)
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
if (configText.isEmpty()) {
|
if (configText.isEmpty()) {
|
||||||
configText = try {
|
configText = try {
|
||||||
HttpUtil.getUrlContentWithUserAgent(url, userAgent, timeout)
|
HttpUtil.getUrlContentWithUserAgent(url, userAgent, directTimeout)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(AppConfig.TAG, "Update subscription: Failed to get URL content with user agent", e)
|
Log.e(AppConfig.TAG, "Update subscription: Failed to get URL content with user agent", e)
|
||||||
""
|
""
|
||||||
|
|||||||
@@ -123,6 +123,9 @@ abstract class BaseActivity : AppCompatActivity() {
|
|||||||
setSupportActionBar(it)
|
setSupportActionBar(it)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(showHomeAsUp)
|
supportActionBar?.setDisplayHomeAsUpEnabled(showHomeAsUp)
|
||||||
title?.let { t -> this.title = t }
|
title?.let { t -> this.title = t }
|
||||||
|
val typedValue = TypedValue()
|
||||||
|
theme.resolveAttribute(com.google.android.material.R.attr.colorOnSurface, typedValue, true)
|
||||||
|
it.setTitleTextColor(typedValue.data)
|
||||||
syncStatusBarWithToolbar(it)
|
syncStatusBarWithToolbar(it)
|
||||||
}
|
}
|
||||||
progressBar = findViewById(R.id.progress_bar)
|
progressBar = findViewById(R.id.progress_bar)
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class GroupServerFragment : BaseFragment<FragmentGroupServerBinding>(),
|
|||||||
} else {
|
} else {
|
||||||
binding.recyclerView.layoutManager = GridLayoutManager(requireContext(), 1)
|
binding.recyclerView.layoutManager = GridLayoutManager(requireContext(), 1)
|
||||||
}
|
}
|
||||||
addCustomDividerToRecyclerView(binding.recyclerView, R.drawable.custom_divider)
|
addCustomDividerToRecyclerView(binding.recyclerView, R.drawable.server_list_divider)
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
|
|
||||||
itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback(adapter, allowSwipe = false))
|
itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback(adapter, allowSwipe = false))
|
||||||
@@ -229,12 +229,18 @@ class GroupServerFragment : BaseFragment<FragmentGroupServerBinding>(),
|
|||||||
*/
|
*/
|
||||||
private fun setSelectServer(guid: String) {
|
private fun setSelectServer(guid: String) {
|
||||||
val selected = MmkvManager.getSelectServer()
|
val selected = MmkvManager.getSelectServer()
|
||||||
if (guid != selected) {
|
if (guid == selected) {
|
||||||
|
MmkvManager.setSelectServer("")
|
||||||
|
val position = mainViewModel.getPosition(guid)
|
||||||
|
adapter.setSelectServer(position, position)
|
||||||
|
if (mainViewModel.isRunning.value == true) {
|
||||||
|
ownerActivity.restartV2Ray()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
MmkvManager.setSelectServer(guid)
|
MmkvManager.setSelectServer(guid)
|
||||||
val fromPosition = mainViewModel.getPosition(selected.orEmpty())
|
val fromPosition = mainViewModel.getPosition(selected.orEmpty())
|
||||||
val toPosition = mainViewModel.getPosition(guid)
|
val toPosition = mainViewModel.getPosition(guid)
|
||||||
adapter.setSelectServer(fromPosition, toPosition)
|
adapter.setSelectServer(fromPosition, toPosition)
|
||||||
|
|
||||||
if (mainViewModel.isRunning.value == true) {
|
if (mainViewModel.isRunning.value == true) {
|
||||||
ownerActivity.restartV2Ray()
|
ownerActivity.restartV2Ray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package xyz.zarazaex.olc.ui
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.net.VpnService
|
import android.net.VpnService
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@@ -11,6 +12,8 @@ import android.view.Menu
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
|
import com.google.android.material.color.MaterialColors
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
@@ -53,6 +56,7 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
private var isLiteTesting = false
|
private var isLiteTesting = false
|
||||||
private var easterEggClickCount = 0
|
private var easterEggClickCount = 0
|
||||||
private var isEasterEggActive = false
|
private var isEasterEggActive = false
|
||||||
|
private var liteActionJob: kotlinx.coroutines.Job? = null
|
||||||
/** Был ли VPN уже запущен в предыдущем колбэке — чтобы детектировать момент подключения */
|
/** Был ли VPN уже запущен в предыдущем колбэке — чтобы детектировать момент подключения */
|
||||||
private var wasRunning = false
|
private var wasRunning = false
|
||||||
|
|
||||||
@@ -107,21 +111,33 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
toggle.syncState()
|
toggle.syncState()
|
||||||
binding.navView.setNavigationItemSelectedListener(this)
|
binding.navView.setNavigationItemSelectedListener(this)
|
||||||
|
|
||||||
|
val typedValue = android.util.TypedValue()
|
||||||
|
theme.resolveAttribute(com.google.android.material.R.attr.colorOnSurface, typedValue, true)
|
||||||
|
val onSurface = typedValue.data
|
||||||
|
binding.toolbar.setTitleTextColor(onSurface)
|
||||||
|
// MaterialToolbar с titleCentered рисует отдельный TextView — красим его явно
|
||||||
|
for (i in 0 until binding.toolbar.childCount) {
|
||||||
|
val child = binding.toolbar.getChildAt(i)
|
||||||
|
if (child is android.widget.TextView) {
|
||||||
|
child.setTextColor(onSurface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.drawerContentLayout) { v, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(binding.drawerContentLayout) { v, insets ->
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
v.setPadding(0, systemBars.top, 0, systemBars.bottom)
|
v.setPadding(0, systemBars.top, 0, systemBars.bottom)
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
|
|
||||||
findViewById<android.widget.TextView>(R.id.drawer_settings)?.setOnClickListener {
|
findViewById<android.view.View>(R.id.drawer_settings)?.setOnClickListener {
|
||||||
requestActivityLauncher.launch(Intent(this, SettingsActivity::class.java))
|
requestActivityLauncher.launch(Intent(this, SettingsActivity::class.java))
|
||||||
binding.drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START)
|
binding.drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START)
|
||||||
}
|
}
|
||||||
findViewById<android.widget.TextView>(R.id.drawer_per_app)?.setOnClickListener {
|
findViewById<android.view.View>(R.id.drawer_per_app)?.setOnClickListener {
|
||||||
requestActivityLauncher.launch(Intent(this, PerAppProxyActivity::class.java))
|
requestActivityLauncher.launch(Intent(this, PerAppProxyActivity::class.java))
|
||||||
binding.drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START)
|
binding.drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START)
|
||||||
}
|
}
|
||||||
findViewById<android.widget.TextView>(R.id.drawer_check_update)?.setOnClickListener {
|
findViewById<android.view.View>(R.id.drawer_check_update)?.setOnClickListener {
|
||||||
startActivity(Intent(this, CheckUpdateActivity::class.java))
|
startActivity(Intent(this, CheckUpdateActivity::class.java))
|
||||||
binding.drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START)
|
binding.drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START)
|
||||||
}
|
}
|
||||||
@@ -200,12 +216,16 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
// Молния — стоп-кнопка, всегда активна во время теста
|
// Молния — стоп-кнопка, всегда активна во время теста
|
||||||
binding.btnSummaryLite.isEnabled = true
|
binding.btnSummaryLite.isEnabled = true
|
||||||
binding.btnSummaryLite.alpha = 1.0f
|
binding.btnSummaryLite.alpha = 1.0f
|
||||||
binding.btnSummaryLite.setImageResource(R.drawable.ic_stop_24dp)
|
binding.btnSummaryLite.setIconResource(R.drawable.ic_stop_24dp)
|
||||||
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_active))
|
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(
|
||||||
|
com.google.android.material.color.MaterialColors.getColor(this, com.google.android.material.R.attr.colorPrimaryContainer, 0)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
setButtonsEnabled(true)
|
setButtonsEnabled(true)
|
||||||
binding.btnSummaryLite.setImageResource(R.drawable.bolt_24)
|
binding.btnSummaryLite.setIconResource(R.drawable.bolt_24)
|
||||||
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
|
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(
|
||||||
|
com.google.android.material.color.MaterialColors.getColor(this, com.google.android.material.R.attr.colorSecondaryContainer, 0)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,15 +319,19 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleFabAction() {
|
private fun handleFabAction() {
|
||||||
|
// Если идёт подключение (isLoading) — позволяем прервать и остановить сервис
|
||||||
if (isFabOperationInProgress) {
|
if (isFabOperationInProgress) {
|
||||||
|
Log.d(AppConfig.TAG, "FAB: cancel in-progress, stopping service")
|
||||||
|
isFabOperationInProgress = false
|
||||||
|
lifecycleScope.launch {
|
||||||
|
V2RayServiceManager.stopVService(this@MainActivity)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
isFabOperationInProgress = true
|
isFabOperationInProgress = true
|
||||||
|
|
||||||
val isRunning = mainViewModel.isRunning.value == true
|
val isRunning = mainViewModel.isRunning.value == true
|
||||||
|
|
||||||
// Блокируем все кнопки сразу
|
|
||||||
setButtonsEnabled(false)
|
|
||||||
applyRunningState(isLoading = true, isRunning = false)
|
applyRunningState(isLoading = true, isRunning = false)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
@@ -338,11 +362,20 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLiteAction() {
|
private fun handleLiteAction() {
|
||||||
// If testing is in progress - stop it
|
// Отмена на любом этапе: обновление подписок или тест
|
||||||
if (mainViewModel.isTesting.value == true) {
|
if (mainViewModel.isTesting.value == true || liteActionJob?.isActive == true) {
|
||||||
|
liteActionJob?.cancel()
|
||||||
|
liteActionJob = null
|
||||||
mainViewModel.cancelAllTests()
|
mainViewModel.cancelAllTests()
|
||||||
showStatus("Тест остановлен")
|
|
||||||
isLiteTesting = false
|
isLiteTesting = false
|
||||||
|
isFabOperationInProgress = false
|
||||||
|
showStatus("Остановлено")
|
||||||
|
setButtonsEnabled(true)
|
||||||
|
binding.btnSummaryLite.setIconResource(R.drawable.bolt_24)
|
||||||
|
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(
|
||||||
|
com.google.android.material.color.MaterialColors.getColor(this, com.google.android.material.R.attr.colorSecondaryContainer, 0)
|
||||||
|
)
|
||||||
|
hideLoading()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,10 +384,7 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
}
|
}
|
||||||
isFabOperationInProgress = true
|
isFabOperationInProgress = true
|
||||||
|
|
||||||
// Блокируем все кнопки сразу при нажатии
|
liteActionJob = lifecycleScope.launch {
|
||||||
setButtonsEnabled(false)
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
try {
|
try {
|
||||||
if (mainViewModel.isRunning.value == true) {
|
if (mainViewModel.isRunning.value == true) {
|
||||||
V2RayServiceManager.stopVService(this@MainActivity)
|
V2RayServiceManager.stopVService(this@MainActivity)
|
||||||
@@ -363,33 +393,36 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
|
|
||||||
showStatus("Обновление профилей...")
|
showStatus("Обновление профилей...")
|
||||||
showLoading()
|
showLoading()
|
||||||
|
// Иконка молнии → стоп пока идёт обновление
|
||||||
|
binding.btnSummaryLite.setIconResource(R.drawable.ic_stop_24dp)
|
||||||
isLiteTesting = true
|
isLiteTesting = true
|
||||||
|
|
||||||
launch(Dispatchers.IO) {
|
val result = withContext(Dispatchers.IO) { mainViewModel.updateConfigViaSubAll() }
|
||||||
val result = mainViewModel.updateConfigViaSubAll()
|
val removed = withContext(Dispatchers.IO) { mainViewModel.removeDuplicateByIpAll() }
|
||||||
val removed = mainViewModel.removeDuplicateByIpAll()
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
mainViewModel.reloadServerList()
|
|
||||||
if (result.configCount > 0) {
|
|
||||||
val status = if (removed > 0)
|
|
||||||
"Обновлено ${result.configCount} профилей, удалено $removed дубл. IP. Запуск теста..."
|
|
||||||
else
|
|
||||||
"Обновлено ${result.configCount} профилей. Запуск теста..."
|
|
||||||
showStatus(status)
|
|
||||||
} else {
|
|
||||||
showStatus("Запуск теста...")
|
|
||||||
}
|
|
||||||
hideLoading()
|
|
||||||
|
|
||||||
showStatus("Выполняется замер задержки. Ожидаем завершения...")
|
mainViewModel.reloadServerList()
|
||||||
mainViewModel.testAllRealPing()
|
if (result.configCount > 0) {
|
||||||
}
|
val status = if (removed > 0)
|
||||||
|
"Обновлено ${result.configCount} профилей, удалено $removed дубл. IP. Запуск теста..."
|
||||||
|
else
|
||||||
|
"Обновлено ${result.configCount} профилей. Запуск теста..."
|
||||||
|
showStatus(status)
|
||||||
|
} else {
|
||||||
|
showStatus("Запуск теста...")
|
||||||
}
|
}
|
||||||
delay(1500)
|
hideLoading()
|
||||||
|
|
||||||
|
showStatus("Выполняется замер задержки. Ожидаем завершения...")
|
||||||
|
mainViewModel.testAllRealPing()
|
||||||
|
} catch (e: kotlinx.coroutines.CancellationException) {
|
||||||
|
// Пользователь нажал стоп — уже обработано выше
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(AppConfig.TAG, "Error in handleLiteAction", e)
|
Log.e(AppConfig.TAG, "Error in handleLiteAction", e)
|
||||||
|
isLiteTesting = false
|
||||||
|
hideLoading()
|
||||||
} finally {
|
} finally {
|
||||||
isFabOperationInProgress = false
|
isFabOperationInProgress = false
|
||||||
|
liteActionJob = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -470,33 +503,58 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun applyRunningState(isLoading: Boolean, isRunning: Boolean) {
|
private fun applyRunningState(isLoading: Boolean, isRunning: Boolean) {
|
||||||
|
val secContainer = ColorStateList.valueOf(
|
||||||
|
com.google.android.material.color.MaterialColors.getColor(this, com.google.android.material.R.attr.colorSecondaryContainer, 0)
|
||||||
|
)
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
// Идёт процесс подключения/отключения — блокируем всё
|
// Во время загрузки FAB и молния остаются доступны для отмены
|
||||||
setButtonsEnabled(false)
|
binding.fab.isEnabled = true
|
||||||
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
|
binding.fab.alpha = 1.0f
|
||||||
|
val menu = binding.toolbar.menu
|
||||||
|
menu.findItem(R.id.real_ping_all)?.let { it.isEnabled = false; it.icon?.alpha = 128 }
|
||||||
|
menu.findItem(R.id.filter_by_country)?.let { it.isEnabled = false; it.icon?.alpha = 128 }
|
||||||
|
menu.findItem(R.id.sub_update)?.let { it.isEnabled = false; it.icon?.alpha = 128 }
|
||||||
|
binding.btnSummaryLite.isEnabled = true
|
||||||
|
binding.btnSummaryLite.alpha = 1.0f
|
||||||
|
binding.fab.backgroundTintList = secContainer
|
||||||
|
setStatusDot(DotState.LOADING)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
// Подключены: только FAB (отключить) активен, остальное блокируем
|
|
||||||
setSecondaryButtonsEnabled(false)
|
setSecondaryButtonsEnabled(false)
|
||||||
binding.fab.isEnabled = true
|
binding.fab.isEnabled = true
|
||||||
binding.fab.alpha = 1.0f
|
binding.fab.alpha = 1.0f
|
||||||
binding.fab.backgroundTintList = accentColor()
|
binding.fab.backgroundTintList = accentColor()
|
||||||
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
|
binding.btnSummaryLite.backgroundTintList = secContainer
|
||||||
binding.fab.contentDescription = getString(R.string.action_stop_service)
|
binding.fab.contentDescription = getString(R.string.action_stop_service)
|
||||||
setTestState(getString(R.string.connection_connected))
|
setTestState(getString(R.string.connection_connected))
|
||||||
binding.layoutTest.isFocusable = true
|
binding.layoutTest.isFocusable = true
|
||||||
|
setStatusDot(DotState.CONNECTED)
|
||||||
} else {
|
} else {
|
||||||
setButtonsEnabled(true)
|
setButtonsEnabled(true)
|
||||||
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
|
binding.fab.backgroundTintList = accentColor()
|
||||||
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
|
binding.btnSummaryLite.backgroundTintList = secContainer
|
||||||
binding.fab.contentDescription = getString(R.string.tasker_start_service)
|
binding.fab.contentDescription = getString(R.string.tasker_start_service)
|
||||||
setTestState(getString(R.string.connection_not_connected))
|
setTestState(getString(R.string.connection_not_connected))
|
||||||
binding.layoutTest.isFocusable = false
|
binding.layoutTest.isFocusable = false
|
||||||
|
setStatusDot(DotState.IDLE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum class DotState { IDLE, CONNECTED, LOADING }
|
||||||
|
|
||||||
|
private fun setStatusDot(state: DotState) {
|
||||||
|
val dot = binding.statusDot
|
||||||
|
dot.animate().cancel()
|
||||||
|
dot.alpha = 1f; dot.scaleX = 1f; dot.scaleY = 1f
|
||||||
|
dot.backgroundTintList = ColorStateList.valueOf(when (state) {
|
||||||
|
DotState.CONNECTED -> ContextCompat.getColor(this, R.color.status_connected)
|
||||||
|
DotState.LOADING -> com.google.android.material.color.MaterialColors.getColor(this, com.google.android.material.R.attr.colorPrimaryContainer, 0)
|
||||||
|
DotState.IDLE -> com.google.android.material.color.MaterialColors.getColor(this, com.google.android.material.R.attr.colorOutline, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "")
|
MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "")
|
||||||
@@ -509,6 +567,13 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
menuInflater.inflate(R.menu.menu_main, menu)
|
menuInflater.inflate(R.menu.menu_main, menu)
|
||||||
|
|
||||||
|
val iconColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface, Color.BLACK)
|
||||||
|
for (i in 0 until menu.size()) {
|
||||||
|
menu.getItem(i).icon?.let {
|
||||||
|
DrawableCompat.setTint(DrawableCompat.wrap(it).mutate(), iconColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val searchItem = menu.findItem(R.id.search_view)
|
val searchItem = menu.findItem(R.id.search_view)
|
||||||
val searchView = searchItem.actionView as SearchView
|
val searchView = searchItem.actionView as SearchView
|
||||||
|
|
||||||
@@ -672,6 +737,7 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
|
|
||||||
private fun importAllSubsOnStartup() {
|
private fun importAllSubsOnStartup() {
|
||||||
showLoading()
|
showLoading()
|
||||||
|
setTestState(getString(R.string.connection_updating_profiles))
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val result = AngConfigManager.updateConfigViaSubAll()
|
val result = AngConfigManager.updateConfigViaSubAll()
|
||||||
val removed = mainViewModel.removeDuplicateByIpAll()
|
val removed = mainViewModel.removeDuplicateByIpAll()
|
||||||
@@ -694,6 +760,7 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
|
|||||||
*/
|
*/
|
||||||
fun importConfigViaSub(): Boolean {
|
fun importConfigViaSub(): Boolean {
|
||||||
showLoading()
|
showLoading()
|
||||||
|
setTestState(getString(R.string.connection_updating_profiles))
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val result = mainViewModel.updateConfigViaSubAll()
|
val result = mainViewModel.updateConfigViaSubAll()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.color.MaterialColors
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import xyz.zarazaex.olc.AppConfig
|
import xyz.zarazaex.olc.AppConfig
|
||||||
import xyz.zarazaex.olc.R
|
import xyz.zarazaex.olc.R
|
||||||
@@ -35,7 +36,11 @@ class MainRecyclerAdapter(
|
|||||||
MmkvManager.decodeSettingsBool(AppConfig.PREF_DOUBLE_COLUMN_DISPLAY, false)
|
MmkvManager.decodeSettingsBool(AppConfig.PREF_DOUBLE_COLUMN_DISPLAY, false)
|
||||||
private val showCopyButton =
|
private val showCopyButton =
|
||||||
MmkvManager.decodeSettingsBool(AppConfig.PREF_SHOW_COPY_BUTTON, false)
|
MmkvManager.decodeSettingsBool(AppConfig.PREF_SHOW_COPY_BUTTON, false)
|
||||||
|
private val showServerIp =
|
||||||
|
MmkvManager.decodeSettingsBool(AppConfig.PREF_SHOW_SERVER_IP, false)
|
||||||
private var data: MutableList<ServersCache> = mutableListOf()
|
private var data: MutableList<ServersCache> = mutableListOf()
|
||||||
|
private var minReachablePing: Long? = null
|
||||||
|
private var maxReachablePing: Long? = null
|
||||||
private var recyclerView: RecyclerView? = null
|
private var recyclerView: RecyclerView? = null
|
||||||
|
|
||||||
override fun onAttachedToRecyclerView(rv: RecyclerView) {
|
override fun onAttachedToRecyclerView(rv: RecyclerView) {
|
||||||
@@ -59,6 +64,7 @@ class MainRecyclerAdapter(
|
|||||||
|
|
||||||
if (data.isEmpty() || parsedNewData.isEmpty() || position >= 0) {
|
if (data.isEmpty() || parsedNewData.isEmpty() || position >= 0) {
|
||||||
data = parsedNewData.toMutableList()
|
data = parsedNewData.toMutableList()
|
||||||
|
recomputePingRange()
|
||||||
if (position >= 0 && position in data.indices) {
|
if (position >= 0 && position in data.indices) {
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
} else {
|
} else {
|
||||||
@@ -106,6 +112,7 @@ class MainRecyclerAdapter(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data = parsedNewData.toMutableList()
|
data = parsedNewData.toMutableList()
|
||||||
|
recomputePingRange()
|
||||||
diffResult.dispatchUpdatesTo(this)
|
diffResult.dispatchUpdatesTo(this)
|
||||||
|
|
||||||
if (isAtTop) {
|
if (isAtTop) {
|
||||||
@@ -162,26 +169,32 @@ class MainRecyclerAdapter(
|
|||||||
|
|
||||||
// Name address
|
// Name address
|
||||||
holder.itemMainBinding.tvName.text = profile.remarks
|
holder.itemMainBinding.tvName.text = profile.remarks
|
||||||
holder.itemMainBinding.tvStatistics.text = getAddress(profile)
|
val addressText = getAddress(profile)
|
||||||
|
holder.itemMainBinding.tvStatistics.text = addressText
|
||||||
|
holder.itemMainBinding.tvStatistics.visibility =
|
||||||
|
if (addressText.isEmpty()) View.GONE else View.VISIBLE
|
||||||
|
|
||||||
// TestResult
|
// TestResult
|
||||||
val aff = MmkvManager.decodeServerAffiliationInfo(guid)
|
val aff = MmkvManager.decodeServerAffiliationInfo(guid)
|
||||||
holder.itemMainBinding.tvTestResult.text = aff?.getTestDelayString().orEmpty()
|
holder.itemMainBinding.tvTestResult.text = aff?.getTestDelayString().orEmpty()
|
||||||
if ((aff?.testDelayMillis ?: 0L) < 0L) {
|
holder.itemMainBinding.tvTestResult.setTextColor(
|
||||||
holder.itemMainBinding.tvTestResult.setTextColor(
|
getPingColor(context, aff?.testDelayMillis)
|
||||||
ContextCompat.getColor(context, R.color.colorPingRed)
|
)
|
||||||
)
|
(holder.itemMainBinding.tvTestResult.layoutParams as? ViewGroup.MarginLayoutParams)?.marginStart =
|
||||||
} else {
|
if (addressText.isEmpty()) 0 else 6.dpToPx(context)
|
||||||
holder.itemMainBinding.tvTestResult.setTextColor(
|
|
||||||
ContextCompat.getColor(context, R.color.colorPing)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// layoutIndicator
|
// Keep regular list items on the page surface; selected state is a quiet surface pill.
|
||||||
if (guid == MmkvManager.getSelectServer()) {
|
val isSelected = guid == MmkvManager.getSelectServer()
|
||||||
holder.itemMainBinding.layoutIndicator.setBackgroundResource(R.color.colorIndicator)
|
holder.itemMainBinding.cardContainer.apply {
|
||||||
} else {
|
val selectedColor = MaterialColors.getColor(
|
||||||
holder.itemMainBinding.layoutIndicator.setBackgroundResource(0)
|
context,
|
||||||
|
com.google.android.material.R.attr.colorSurfaceContainerHigh,
|
||||||
|
Color.TRANSPARENT
|
||||||
|
)
|
||||||
|
|
||||||
|
setCardBackgroundColor(if (isSelected) selectedColor else Color.TRANSPARENT)
|
||||||
|
strokeWidth = 0
|
||||||
|
strokeColor = Color.TRANSPARENT
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscription remarks
|
// subscription remarks
|
||||||
@@ -223,9 +236,52 @@ class MainRecyclerAdapter(
|
|||||||
* @return Formatted address string
|
* @return Formatted address string
|
||||||
*/
|
*/
|
||||||
private fun getAddress(profile: ProfileItem): String {
|
private fun getAddress(profile: ProfileItem): String {
|
||||||
|
if (!showServerIp) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
return AngConfigManager.generateDescription(profile)
|
return AngConfigManager.generateDescription(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getPingColor(context: android.content.Context, delayMillis: Long?): Int {
|
||||||
|
val delay = delayMillis ?: return MaterialColors.getColor(
|
||||||
|
context,
|
||||||
|
com.google.android.material.R.attr.colorOnSurfaceVariant,
|
||||||
|
ContextCompat.getColor(context, R.color.colorPing)
|
||||||
|
)
|
||||||
|
if (delay == 0L) {
|
||||||
|
return MaterialColors.getColor(
|
||||||
|
context,
|
||||||
|
com.google.android.material.R.attr.colorOnSurfaceVariant,
|
||||||
|
ContextCompat.getColor(context, R.color.colorPing)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return when {
|
||||||
|
delay < 0L -> ContextCompat.getColor(context, R.color.colorPingRed)
|
||||||
|
minReachablePing == null || maxReachablePing == null -> ContextCompat.getColor(context, R.color.colorPingGood)
|
||||||
|
minReachablePing == maxReachablePing -> ContextCompat.getColor(context, R.color.colorPingGood)
|
||||||
|
else -> {
|
||||||
|
val min = minReachablePing ?: delay
|
||||||
|
val max = maxReachablePing ?: delay
|
||||||
|
val relative = ((delay - min).toFloat() / (max - min).toFloat()).coerceIn(0f, 1f)
|
||||||
|
when {
|
||||||
|
relative <= 0.33f -> ContextCompat.getColor(context, R.color.colorPingGood)
|
||||||
|
relative <= 0.66f -> ContextCompat.getColor(context, R.color.colorPingMedium)
|
||||||
|
else -> ContextCompat.getColor(context, R.color.colorPingRed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recomputePingRange() {
|
||||||
|
val delays = data.mapNotNull { item ->
|
||||||
|
MmkvManager.decodeServerAffiliationInfo(item.guid)
|
||||||
|
?.testDelayMillis
|
||||||
|
?.takeIf { it > 0L }
|
||||||
|
}
|
||||||
|
minReachablePing = delays.minOrNull()
|
||||||
|
maxReachablePing = delays.maxOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the subscription remarks information
|
* Gets the subscription remarks information
|
||||||
* @param profile The server configuration
|
* @param profile The server configuration
|
||||||
@@ -245,6 +301,7 @@ class MainRecyclerAdapter(
|
|||||||
val idx = data.indexOfFirst { it.guid == guid }
|
val idx = data.indexOfFirst { it.guid == guid }
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
data.removeAt(idx)
|
data.removeAt(idx)
|
||||||
|
recomputePingRange()
|
||||||
notifyItemRemoved(idx)
|
notifyItemRemoved(idx)
|
||||||
notifyItemRangeChanged(idx, data.size - idx)
|
notifyItemRangeChanged(idx, data.size - idx)
|
||||||
}
|
}
|
||||||
@@ -255,6 +312,10 @@ class MainRecyclerAdapter(
|
|||||||
notifyItemChanged(toPosition)
|
notifyItemChanged(toPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Int.dpToPx(context: android.content.Context): Int {
|
||||||
|
return (this * context.resources.displayMetrics.density).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
VIEW_TYPE_ITEM ->
|
VIEW_TYPE_ITEM ->
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pinSelectedGuidToTop(serverList)
|
||||||
updateCache()
|
updateCache()
|
||||||
updateListAction.value = -1
|
updateListAction.value = -1
|
||||||
}
|
}
|
||||||
@@ -638,6 +639,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
pinSelectedCacheItemToTop(serversCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sortByTestResults() {
|
fun sortByTestResults() {
|
||||||
@@ -689,6 +691,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
val serversBySubId = allServerDelays.groupBy { it.subId }
|
val serversBySubId = allServerDelays.groupBy { it.subId }
|
||||||
serversBySubId.forEach { (subId, servers) ->
|
serversBySubId.forEach { (subId, servers) ->
|
||||||
val sortedList = servers.map { it.guid }.toMutableList()
|
val sortedList = servers.map { it.guid }.toMutableList()
|
||||||
|
pinSelectedGuidToTop(sortedList)
|
||||||
MmkvManager.encodeServerList(sortedList, subId)
|
MmkvManager.encodeServerList(sortedList, subId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -716,11 +719,32 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
serverDelays.sortWith(compareBy({ !it.isFav }, { it.testDelayMillis }))
|
serverDelays.sortWith(compareBy({ !it.isFav }, { it.testDelayMillis }))
|
||||||
|
|
||||||
val sortedServerList = serverDelays.map { it.guid }.toMutableList()
|
val sortedServerList = serverDelays.map { it.guid }.toMutableList()
|
||||||
|
pinSelectedGuidToTop(sortedServerList)
|
||||||
|
|
||||||
// Save the sorted list for this subscription
|
// Save the sorted list for this subscription
|
||||||
MmkvManager.encodeServerList(sortedServerList, subId)
|
MmkvManager.encodeServerList(sortedServerList, subId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun pinSelectedGuidToTop(list: MutableList<String>) {
|
||||||
|
val selectedGuid = MmkvManager.getSelectServer().orEmpty()
|
||||||
|
if (selectedGuid.isEmpty()) return
|
||||||
|
val index = list.indexOf(selectedGuid)
|
||||||
|
if (index > 0) {
|
||||||
|
list.removeAt(index)
|
||||||
|
list.add(0, selectedGuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pinSelectedCacheItemToTop(list: MutableList<ServersCache>) {
|
||||||
|
val selectedGuid = MmkvManager.getSelectServer().orEmpty()
|
||||||
|
if (selectedGuid.isEmpty()) return
|
||||||
|
val index = list.indexOfFirst { it.guid == selectedGuid }
|
||||||
|
if (index > 0) {
|
||||||
|
val selectedItem = list.removeAt(index)
|
||||||
|
list.add(0, selectedItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes assets.
|
* Initializes assets.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="oval">
|
android:shape="oval">
|
||||||
<solid android:color="@color/divider_color_light" />
|
<solid android:color="?attr/colorSecondaryContainer" />
|
||||||
<size
|
<size
|
||||||
android:width="48dp"
|
android:width="24dp"
|
||||||
android:height="48dp" />
|
android:height="24dp" />
|
||||||
</shape>
|
</shape>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:bottom="0dp"
|
||||||
|
android:left="28dp"
|
||||||
|
android:right="28dp"
|
||||||
|
android:top="0dp">
|
||||||
|
<shape>
|
||||||
|
<size android:height="1dp" />
|
||||||
|
<solid android:color="@color/server_list_divider" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="#FF888888" />
|
||||||
|
<size android:width="10dp" android:height="10dp" />
|
||||||
|
</shape>
|
||||||
@@ -1,171 +1,228 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView 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_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="top"
|
android:layout_marginBottom="8dp"
|
||||||
android:orientation="vertical">
|
app:cardBackgroundColor="?attr/colorSurfaceContainerLow"
|
||||||
|
app:cardCornerRadius="16dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:strokeWidth="0dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layout_soure_ccode"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:gravity="top"
|
||||||
android:clickable="true"
|
android:orientation="vertical">
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center|start"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/padding_spacing_dp16">
|
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
android:id="@+id/layout_soure_ccode"
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
android:layout_width="match_parent"
|
||||||
android:importantForAccessibility="no"
|
|
||||||
app:srcCompat="@drawable/ic_source_code_24dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="@dimen/padding_spacing_dp16"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:text="@string/title_source_code"
|
android:clickable="true"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
android:focusable="true"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_source_code_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:text="@string/title_source_code"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="?attr/colorOutlineVariant" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_oss_licenses"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/license_24px"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:text="@string/title_oss_license"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="?attr/colorOutlineVariant" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_feedback"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_feedback_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:text="@string/title_pref_feedback"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="?attr/colorOutlineVariant" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_tg_channel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_telegram_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:text="@string/title_tg_channel"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="?attr/colorOutlineVariant" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_privacy_policy"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_privacy_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:text="@string/title_privacy_policy"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
</com.google.android.material.card.MaterialCardView>
|
||||||
android:id="@+id/layout_oss_licenses"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center|start"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/padding_spacing_dp16">
|
|
||||||
|
|
||||||
<ImageView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
android:layout_height="wrap_content"
|
||||||
android:importantForAccessibility="no"
|
app:cardBackgroundColor="?attr/colorSurfaceContainerLowest"
|
||||||
app:srcCompat="@drawable/license_24px" />
|
app:cardCornerRadius="16dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
<TextView
|
app:strokeWidth="0dp">
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp16"
|
|
||||||
android:text="@string/title_oss_license"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_feedback"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center|start"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/padding_spacing_dp16">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
app:srcCompat="@drawable/ic_feedback_24dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp16"
|
|
||||||
android:text="@string/title_pref_feedback"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_tg_channel"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center|start"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/padding_spacing_dp16">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
app:srcCompat="@drawable/ic_telegram_24dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp16"
|
|
||||||
android:text="@string/title_tg_channel"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_privacy_policy"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center|start"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/padding_spacing_dp16">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
app:srcCompat="@drawable/ic_privacy_24dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp16"
|
|
||||||
android:text="@string/title_privacy_policy"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/padding_spacing_dp16">
|
android:padding="20dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_version"
|
android:id="@+id/tv_version"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/title_about"
|
android:text="@string/title_about"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
android:textAppearance="@style/TextAppearance.Material3.LabelMedium"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_app_id"
|
android:id="@+id/tv_app_id"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
android:text="@string/title_about"
|
android:text="@string/title_about"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||||
|
android:textColor="?attr/colorOutline" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
|||||||
@@ -5,33 +5,41 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/app_bar"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
android:background="?attr/colorSurface"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:elevation="0dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:titleTextAppearance="@style/TextAppearance.AppCompat.Title" />
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:titleTextAppearance="@style/TextAppearance.Material3.TitleLarge" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
android:id="@+id/progress_bar"
|
android:id="@+id/progress_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
app:layout_constraintTop_toBottomOf="@id/app_bar"
|
||||||
android:indeterminate="true"
|
android:indeterminate="true"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:indicatorColor="@color/color_fab_active" />
|
app:indicatorColor="?attr/colorPrimary"
|
||||||
|
app:trackColor="?attr/colorSurfaceVariant" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/content_container"
|
android:id="@+id/content_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
app:layout_constraintTop_toBottomOf="@id/app_bar"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
android:id="@+id/drawer_layout"
|
android:id="@+id/drawer_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/md_theme_surface">
|
android:background="?attr/colorSurface">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -15,15 +15,18 @@
|
|||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/md_theme_surface"
|
android:background="?attr/colorSurface"
|
||||||
app:elevation="0dp">
|
app:elevation="0dp"
|
||||||
|
app:liftOnScroll="false">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:title="@string/app_name"
|
app:title="@string/app_name"
|
||||||
app:titleCentered="true" />
|
app:titleCentered="true"
|
||||||
|
app:titleTextColor="?attr/colorOnSurface"
|
||||||
|
app:titleTextAppearance="@style/TextAppearance.Material3.TitleLarge" />
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
@@ -47,7 +50,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:indeterminate="true"
|
android:indeterminate="true"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:indicatorColor="@color/md_theme_primary" />
|
app:indicatorColor="?attr/colorPrimary"
|
||||||
|
app:trackCornerRadius="0dp"
|
||||||
|
app:trackColor="@android:color/transparent" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/tab_slot_top"
|
android:id="@+id/tab_slot_top"
|
||||||
@@ -58,7 +63,7 @@
|
|||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="@color/divider_color_light" />
|
android:background="?attr/colorOutlineVariant" />
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
android:id="@+id/view_pager"
|
android:id="@+id/view_pager"
|
||||||
@@ -68,16 +73,18 @@
|
|||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
android:layout_weight="1" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<!-- Bottom container: tab + action card -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/bottom_container"
|
android:id="@+id/bottom_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:background="?attr/colorSurfaceContainer">
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="@color/divider_color_light" />
|
android:background="?attr/colorOutlineVariant" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/tab_slot_bottom"
|
android:id="@+id/tab_slot_bottom"
|
||||||
@@ -85,104 +92,130 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
<com.google.android.material.tabs.TabLayout
|
||||||
android:id="@+id/tab_group"
|
android:id="@+id/tab_group"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="56dp"
|
||||||
app:tabIndicatorFullWidth="true"
|
android:minHeight="56dp"
|
||||||
app:tabMode="auto"
|
android:background="?attr/colorSurface"
|
||||||
app:tabGravity="fill"
|
app:tabIndicatorFullWidth="true"
|
||||||
app:tabMaxWidth="0dp"
|
app:tabIndicatorHeight="3dp"
|
||||||
app:tabRippleColor="@android:color/transparent"
|
app:tabMode="fixed"
|
||||||
app:tabTextAppearance="@style/TabLayoutTextStyle" />
|
app:tabGravity="fill"
|
||||||
|
app:tabMaxWidth="0dp"
|
||||||
|
app:tabRippleColor="@android:color/transparent"
|
||||||
|
app:tabIndicatorColor="?attr/colorPrimary"
|
||||||
|
app:tabSelectedTextColor="?attr/colorPrimary"
|
||||||
|
app:tabTextColor="?attr/colorOnSurfaceVariant"
|
||||||
|
app:tabTextAppearance="@style/TabLayoutTextStyle" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<!-- Bottom action row -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:paddingBottom="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:id="@+id/btn_summary_lite"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:src="@drawable/bolt_24"
|
|
||||||
app:tint="@color/colorWhite"
|
|
||||||
app:backgroundTint="@color/color_fab_inactive"
|
|
||||||
app:rippleColor="#33FFFFFF"
|
|
||||||
app:fabSize="normal"
|
|
||||||
app:maxImageSize="28dp"
|
|
||||||
app:elevation="4dp"
|
|
||||||
app:pressedTranslationZ="8dp"
|
|
||||||
app:hoveredFocusedTranslationZ="6dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:id="@+id/fab"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/tasker_start_service"
|
|
||||||
android:focusable="true"
|
|
||||||
android:nextFocusLeft="@+id/layout_test"
|
|
||||||
android:src="@drawable/shield_24"
|
|
||||||
app:tint="@color/colorWhite"
|
|
||||||
app:rippleColor="#33FFFFFF"
|
|
||||||
app:fabSize="normal"
|
|
||||||
app:maxImageSize="28dp"
|
|
||||||
app:elevation="4dp"
|
|
||||||
app:pressedTranslationZ="8dp"
|
|
||||||
app:hoveredFocusedTranslationZ="6dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_test"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/connection_test_pending"
|
|
||||||
android:focusable="true"
|
|
||||||
android:nextFocusLeft="@+id/view_pager"
|
|
||||||
android:nextFocusRight="@+id/fab"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingTop="4dp"
|
|
||||||
android:paddingBottom="12dp"
|
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp">
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp">
|
||||||
|
|
||||||
<TextView
|
<!-- Bolt icon button -->
|
||||||
android:id="@+id/tv_test_state"
|
<com.google.android.material.button.MaterialButton
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/btn_summary_lite"
|
||||||
android:layout_height="wrap_content"
|
style="@style/Widget.ActionSquareButton"
|
||||||
android:gravity="center"
|
android:layout_width="52dp"
|
||||||
android:maxLines="2"
|
android:layout_height="52dp"
|
||||||
android:minLines="1"
|
app:icon="@drawable/bolt_24"
|
||||||
android:text="@string/connection_test_pending"
|
app:iconSize="22dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
app:backgroundTint="?attr/colorSecondaryContainer"
|
||||||
|
app:iconTint="?attr/colorOnSecondaryContainer"
|
||||||
|
app:rippleColor="?attr/colorOnSecondaryContainer"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/fab"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<!-- Connect / Disconnect icon button -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/fab"
|
||||||
|
style="@style/Widget.ActionSquareButton"
|
||||||
|
android:layout_width="52dp"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:contentDescription="@string/tasker_start_service"
|
||||||
|
app:icon="@drawable/shield_24"
|
||||||
|
app:iconSize="26dp"
|
||||||
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
|
app:rippleColor="?attr/colorOnPrimary"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
<!-- Status pill: dot + text, tappable for ping -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/layout_test"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:contentDescription="@string/connection_test_pending"
|
||||||
|
app:cardBackgroundColor="?attr/colorSurfaceContainerHigh"
|
||||||
|
app:cardCornerRadius="26dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:strokeWidth="0dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn_summary_lite"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="12dp">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/status_dot"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:background="@drawable/status_dot"
|
||||||
|
android:layout_marginEnd="10dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_test_state"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:text="@string/connection_test_pending"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Navigation Drawer -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/drawer_content_layout"
|
android:id="@+id/drawer_content_layout"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="280dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?attr/colorSurfaceContainerLow"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.navigation.NavigationView
|
<com.google.android.material.navigation.NavigationView
|
||||||
@@ -190,6 +223,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
app:headerLayout="@layout/nav_header" />
|
app:headerLayout="@layout/nav_header" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -198,61 +232,65 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/drawer_settings"
|
android:id="@+id/drawer_settings"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
android:drawablePadding="12dp"
|
android:drawablePadding="12dp"
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:paddingTop="12dp"
|
android:paddingTop="12dp"
|
||||||
android:paddingBottom="12dp"
|
android:paddingBottom="12dp"
|
||||||
android:text="@string/title_settings"
|
android:text="@string/title_settings"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:clickable="true"
|
app:iconGravity="start"
|
||||||
android:focusable="true" />
|
app:iconTint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/drawer_per_app"
|
android:id="@+id/drawer_per_app"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
android:drawablePadding="12dp"
|
android:drawablePadding="12dp"
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:paddingTop="12dp"
|
android:paddingTop="12dp"
|
||||||
android:paddingBottom="12dp"
|
android:paddingBottom="12dp"
|
||||||
android:text="@string/per_app_proxy_settings"
|
android:text="@string/per_app_proxy_settings"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:clickable="true"
|
app:iconGravity="start"
|
||||||
android:focusable="true" />
|
app:iconTint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/drawer_check_update"
|
android:id="@+id/drawer_check_update"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
android:drawablePadding="12dp"
|
android:drawablePadding="12dp"
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:paddingTop="12dp"
|
android:paddingTop="12dp"
|
||||||
android:paddingBottom="16dp"
|
android:paddingBottom="16dp"
|
||||||
android:text="@string/update_check_for_update"
|
android:text="@string/update_check_for_update"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:clickable="true"
|
app:iconGravity="start"
|
||||||
android:focusable="true" />
|
app:iconTint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:background="@color/divider_color_light" />
|
android:background="?attr/colorOutlineVariant" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_forked"
|
android:id="@+id/tv_forked"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/drawer_forked_text"
|
android:text="@string/drawer_forked_text"
|
||||||
android:textColor="#9E9E9E"
|
android:textColor="?attr/colorOnSurfaceVariant"
|
||||||
android:textColorLink="#9E9E9E"
|
android:textColorLink="?attr/colorPrimary"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||||
android:linksClickable="true"
|
android:linksClickable="true"
|
||||||
android:textIsSelectable="true" />
|
android:textIsSelectable="true" />
|
||||||
|
|
||||||
@@ -262,8 +300,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:text="@string/drawer_developed_text"
|
android:text="@string/drawer_developed_text"
|
||||||
android:textColor="#9E9E9E"
|
android:textColor="?attr/colorOnSurfaceVariant"
|
||||||
android:textColorLink="#9E9E9E"
|
android:textColorLink="?attr/colorPrimary"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||||
android:linksClickable="true"
|
android:linksClickable="true"
|
||||||
android:textIsSelectable="true" />
|
android:textIsSelectable="true" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -1,163 +1,158 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout 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"
|
|
||||||
android:id="@+id/item_bg"
|
android:id="@+id/item_bg"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/info_container"
|
android:id="@+id/card_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
app:cardBackgroundColor="@android:color/transparent"
|
||||||
android:background="?attr/selectableItemBackground"
|
app:cardCornerRadius="14dp"
|
||||||
android:clickable="true"
|
app:cardElevation="0dp"
|
||||||
android:focusable="true"
|
app:strokeWidth="0dp">
|
||||||
android:gravity="center"
|
|
||||||
android:nextFocusRight="@+id/layout_share"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp4"
|
|
||||||
android:paddingTop="@dimen/padding_spacing_dp8"
|
|
||||||
android:paddingEnd="@dimen/padding_spacing_dp4"
|
|
||||||
android:paddingBottom="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_indicator"
|
|
||||||
android:layout_width="@dimen/padding_spacing_dp4"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:orientation="vertical" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/info_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:layout_gravity="center"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:nextFocusRight="@+id/layout_share"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingTop="13dp"
|
||||||
|
android:paddingEnd="4dp"
|
||||||
|
android:paddingBottom="13dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal">
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:orientation="horizontal">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_weight="1"
|
||||||
android:paddingStart="@dimen/padding_spacing_dp8">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_name"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:minLines="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="vertical"
|
||||||
android:paddingTop="@dimen/padding_spacing_dp8">
|
android:paddingStart="12dp">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/layout_subscription"
|
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_marginEnd="@dimen/padding_spacing_dp4"
|
|
||||||
android:background="@drawable/ic_circle">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_subscription"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
android:textSize="11sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_statistics"
|
android:id="@+id/tv_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:lines="1"
|
android:maxLines="2"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
android:minLines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
|
||||||
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="5dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_subscription"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:background="@drawable/ic_circle">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_subscription"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||||
|
android:textSize="10sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_statistics"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_test_result"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||||
|
android:textColor="@color/colorPing"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
<LinearLayout
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:gravity="end">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/iv_favorite"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:gravity="center"
|
||||||
android:clickable="true"
|
android:orientation="vertical">
|
||||||
android:focusable="true"
|
|
||||||
android:padding="@dimen/padding_spacing_dp8"
|
|
||||||
android:src="@drawable/kid_star_outline_24" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/iv_copy"
|
android:id="@+id/iv_favorite"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="@dimen/padding_spacing_dp8"
|
android:padding="6dp"
|
||||||
android:visibility="gone"
|
android:src="@drawable/kid_star_outline_24" />
|
||||||
app:srcCompat="@drawable/ic_copy"
|
|
||||||
app:tint="?attr/colorAccent" />
|
<ImageView
|
||||||
|
android:id="@+id/iv_copy"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:srcCompat="@drawable/ic_copy"
|
||||||
|
app:tint="?attr/colorPrimary" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp8"
|
|
||||||
android:paddingTop="@dimen/padding_spacing_dp8"
|
|
||||||
android:paddingEnd="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_test_result"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:lines="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
android:textColor="@color/colorPing"
|
|
||||||
android:textSize="11sp"
|
|
||||||
tools:text="214ms" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -4,110 +4,127 @@
|
|||||||
android:id="@+id/item_bg"
|
android:id="@+id/item_bg"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/info_container"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
app:cardBackgroundColor="?attr/colorSurfaceContainerLow"
|
||||||
android:background="?attr/selectableItemBackground"
|
app:cardCornerRadius="16dp"
|
||||||
android:clickable="true"
|
app:cardElevation="0dp"
|
||||||
android:focusable="true"
|
app:strokeWidth="0dp">
|
||||||
android:gravity="center"
|
|
||||||
android:nextFocusRight="@+id/layout_edit"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:id="@+id/info_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_gravity="center"
|
||||||
android:orientation="vertical"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:nextFocusRight="@+id/layout_edit"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal">
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/remarks"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/img_locked"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_lock_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/remarks"
|
android:id="@+id/domainIp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
android:layout_marginTop="6dp"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:id="@+id/img_locked"
|
android:id="@+id/outboundTag"
|
||||||
android:layout_width="@dimen/padding_spacing_dp16"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/padding_spacing_dp16"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginStart="@dimen/padding_spacing_dp16"
|
android:lines="1"
|
||||||
android:importantForAccessibility="no"
|
android:textAppearance="@style/TextAppearance.Material3.LabelMedium"
|
||||||
app:srcCompat="@drawable/ic_lock_24dp" />
|
android:textColor="?attr/colorPrimary" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/domainIp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
|
||||||
android:lines="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/outboundTag"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
|
||||||
android:lines="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layout_edit"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/menu_item_edit_config"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:nextFocusLeft="@+id/info_container"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
android:padding="8dp">
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
android:id="@+id/layout_edit"
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
app:srcCompat="@drawable/ic_edit_24dp" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.SwitchCompat
|
|
||||||
android:id="@+id/chk_enable"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:theme="@style/BrandedSwitch" />
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/menu_item_edit_config"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:nextFocusLeft="@+id/info_container"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_edit_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/chk_enable"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:theme="@style/BrandedSwitch" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -4,195 +4,214 @@
|
|||||||
android:id="@+id/item_bg"
|
android:id="@+id/item_bg"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/info_container"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
app:cardBackgroundColor="?attr/colorSurfaceContainerLow"
|
||||||
android:background="?attr/selectableItemBackground"
|
app:cardCornerRadius="16dp"
|
||||||
android:clickable="true"
|
app:cardElevation="0dp"
|
||||||
android:focusable="true"
|
app:strokeWidth="0dp">
|
||||||
android:gravity="center"
|
|
||||||
android:nextFocusRight="@+id/layout_share"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/info_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:layout_gravity="center"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:nextFocusRight="@+id/layout_share"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_name"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:minLines="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layout_share"
|
android:layout_width="0dp"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:layout_weight="1"
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/title_configuration_share"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center"
|
|
||||||
android:nextFocusLeft="@+id/info_container"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
android:paddingStart="8dp">
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
|
android:id="@+id/tv_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
android:layout_height="wrap_content"
|
||||||
android:importantForAccessibility="no"
|
android:maxLines="2"
|
||||||
app:srcCompat="@drawable/ic_share_24dp" />
|
android:minLines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layout_edit"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/menu_item_edit_config"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="horizontal">
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
android:id="@+id/layout_share"
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
android:layout_width="wrap_content"
|
||||||
android:importantForAccessibility="no"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/ic_edit_24dp" />
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/title_configuration_share"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:nextFocusLeft="@+id/info_container"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_share_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_edit"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/menu_item_edit_config"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_edit_24dp"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_remove"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/menu_item_del_config"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:srcCompat="@drawable/ic_delete_24dp"
|
||||||
|
app:tint="?attr/colorError" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_remove"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/menu_item_del_config"
|
|
||||||
android:focusable="true"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="@dimen/image_size_dp24"
|
|
||||||
android:layout_height="@dimen/image_size_dp24"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
app:srcCompat="@drawable/ic_delete_24dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_url"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layout_url"
|
android:layout_width="0dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_weight="1"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="@dimen/padding_spacing_dp8"
|
android:paddingTop="6dp">
|
||||||
android:paddingEnd="@dimen/padding_spacing_dp8">
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_url"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:lines="2"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/chk_enable"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:theme="@style/BrandedSwitch" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:id="@+id/layout_last_updated"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingTop="@dimen/padding_spacing_dp8">
|
android:layout_marginTop="6dp"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="4dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_url"
|
android:id="@+id/tv_last_updated"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
style="?android:attr/progressBarStyleSmall"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_update_status"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:lines="2"
|
android:layout_marginStart="8dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.SwitchCompat
|
|
||||||
android:id="@+id/chk_enable"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:theme="@style/BrandedSwitch" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_last_updated"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
|
||||||
android:paddingStart="@dimen/padding_spacing_dp8"
|
|
||||||
android:paddingEnd="@dimen/padding_spacing_dp8">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_last_updated"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"/>
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress_bar"
|
|
||||||
style="?android:attr/progressBarStyleSmall"
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="16dp"
|
|
||||||
android:layout_marginStart="@dimen/padding_spacing_dp8"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_update_status"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/padding_spacing_dp8"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Button xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.button.MaterialButton 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:onClick="onModeHelpClicked"
|
android:onClick="onModeHelpClicked"
|
||||||
android:text="@string/title_mode_help"
|
android:text="@string/title_mode_help"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
android:textStyle="italic"
|
android:textStyle="italic"
|
||||||
android:textColor="?attr/colorPrimary"
|
android:textColor="?attr/colorPrimary"
|
||||||
|
app:iconTint="?attr/colorPrimary"
|
||||||
tools:ignore="UsingOnClickInXml" />
|
tools:ignore="UsingOnClickInXml" />
|
||||||
|
|||||||
@@ -1,29 +1,36 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="color_fab_active">#C0C0C0</color>
|
<color name="colorPing">#90CAF9</color>
|
||||||
<color name="color_fab_inactive">#646464</color>
|
<color name="colorPingGood">#86D993</color>
|
||||||
<color name="divider_color_light">#424242</color>
|
<color name="colorPingMedium">#F1C76A</color>
|
||||||
|
<color name="status_connected">#66BB6A</color>
|
||||||
|
<color name="colorPingRed">#FFB4AB</color>
|
||||||
|
<color name="color_fab_active">@color/md_theme_primary</color>
|
||||||
|
<color name="color_fab_inactive">@color/md_theme_secondaryContainer</color>
|
||||||
|
<color name="divider_color_light">@color/md_theme_outlineVariant</color>
|
||||||
|
<color name="server_list_divider">#2649454F</color>
|
||||||
|
|
||||||
<color name="md_theme_primary">#C0C0C0</color>
|
<!-- M3 Dark scheme — Purple/Violet tonal palette -->
|
||||||
<color name="md_theme_onPrimary">#303030</color>
|
<color name="md_theme_primary">#D0BCFF</color>
|
||||||
<color name="md_theme_primaryContainer">#474747</color>
|
<color name="md_theme_onPrimary">#381E72</color>
|
||||||
<color name="md_theme_onPrimaryContainer">#E0E0E0</color>
|
<color name="md_theme_primaryContainer">#4F378B</color>
|
||||||
|
<color name="md_theme_onPrimaryContainer">#EADDFF</color>
|
||||||
|
|
||||||
<color name="md_theme_secondary">#90CAF9</color>
|
<color name="md_theme_secondary">#CCC2DC</color>
|
||||||
<color name="md_theme_onSecondary">#FFFFFF</color>
|
<color name="md_theme_onSecondary">#332D41</color>
|
||||||
<color name="md_theme_secondaryContainer">#6F3800</color>
|
<color name="md_theme_secondaryContainer">#4A4458</color>
|
||||||
<color name="md_theme_onSecondaryContainer">#FFE8D6</color>
|
<color name="md_theme_onSecondaryContainer">#E8DEF8</color>
|
||||||
|
|
||||||
<color name="md_theme_tertiary">#64B5F6</color>
|
<color name="md_theme_tertiary">#EFB8C8</color>
|
||||||
<color name="md_theme_onTertiary">#00382E</color>
|
<color name="md_theme_onTertiary">#492532</color>
|
||||||
<color name="md_theme_tertiaryContainer">#005143</color>
|
<color name="md_theme_tertiaryContainer">#633B48</color>
|
||||||
<color name="md_theme_onTertiaryContainer">#BBDEFB</color>
|
<color name="md_theme_onTertiaryContainer">#FFD8E4</color>
|
||||||
|
|
||||||
<!-- Error colors -->
|
<!-- Error colors -->
|
||||||
<color name="md_theme_error">#FFB4AB</color>
|
<color name="md_theme_error">#F2B8B5</color>
|
||||||
<color name="md_theme_errorContainer">#93000A</color>
|
<color name="md_theme_errorContainer">#8C1D18</color>
|
||||||
<color name="md_theme_onError">#690005</color>
|
<color name="md_theme_onError">#601410</color>
|
||||||
<color name="md_theme_onErrorContainer">#FFDAD6</color>
|
<color name="md_theme_onErrorContainer">#F9DEDC</color>
|
||||||
|
|
||||||
<!-- Background colors -->
|
<!-- Background colors -->
|
||||||
<color name="md_theme_background">#1C1B1F</color>
|
<color name="md_theme_background">#1C1B1F</color>
|
||||||
@@ -35,15 +42,22 @@
|
|||||||
<color name="md_theme_surfaceVariant">#49454F</color>
|
<color name="md_theme_surfaceVariant">#49454F</color>
|
||||||
<color name="md_theme_onSurfaceVariant">#CAC4D0</color>
|
<color name="md_theme_onSurfaceVariant">#CAC4D0</color>
|
||||||
<color name="md_theme_inverseSurface">#E6E1E5</color>
|
<color name="md_theme_inverseSurface">#E6E1E5</color>
|
||||||
<color name="md_theme_inverseOnSurface">#1C1B1F</color>
|
<color name="md_theme_inverseOnSurface">#313033</color>
|
||||||
|
|
||||||
|
<!-- Surface containers — M3 dark elevation tones -->
|
||||||
|
<color name="md_theme_surfaceContainerLowest">#0F0D13</color>
|
||||||
|
<color name="md_theme_surfaceContainerLow">#1D1B20</color>
|
||||||
|
<color name="md_theme_surfaceContainer">#211F26</color>
|
||||||
|
<color name="md_theme_surfaceContainerHigh">#2B2930</color>
|
||||||
|
<color name="md_theme_surfaceContainerHighest">#36343B</color>
|
||||||
|
|
||||||
<!-- Outline colors -->
|
<!-- Outline colors -->
|
||||||
<color name="md_theme_outline">#938F99</color>
|
<color name="md_theme_outline">#938F99</color>
|
||||||
<color name="md_theme_outlineVariant">#49454F</color>
|
<color name="md_theme_outlineVariant">#49454F</color>
|
||||||
|
|
||||||
<!-- Other colors -->
|
<!-- Other colors -->
|
||||||
<color name="md_theme_inversePrimary">#000000</color>
|
<color name="md_theme_inversePrimary">#6750A4</color>
|
||||||
<color name="md_theme_shadow">#000000</color>
|
<color name="md_theme_shadow">#000000</color>
|
||||||
<color name="md_theme_surfaceTint">#C0C0C0</color>
|
<color name="md_theme_surfaceTint">#D0BCFF</color>
|
||||||
<color name="md_theme_scrim">#000000</color>
|
<color name="md_theme_scrim">#000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<!-- Night theme: inherit the shared AppThemeBase and only override night-specific items -->
|
<!-- Night theme: inherit shared base, only override night-specific items -->
|
||||||
<style name="AppThemeDayNight" parent="AppThemeBase">
|
<style name="AppThemeDayNight" parent="AppThemeBase">
|
||||||
<!-- Night mode specific overrides -->
|
|
||||||
<item name="android:windowLightStatusBar">false</item>
|
<item name="android:windowLightStatusBar">false</item>
|
||||||
<item name="android:windowLightNavigationBar" tools:targetApi="27">false</item>
|
<item name="android:windowLightNavigationBar" tools:targetApi="27">false</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -143,15 +143,15 @@
|
|||||||
<string name="msg_downloading_content">Загрузка данных</string>
|
<string name="msg_downloading_content">Загрузка данных</string>
|
||||||
<string name="menu_item_export_proxy_app">Экспорт в буфер обмена</string>
|
<string name="menu_item_export_proxy_app">Экспорт в буфер обмена</string>
|
||||||
<string name="menu_item_import_proxy_app">Импорт из буфера обмена</string>
|
<string name="menu_item_import_proxy_app">Импорт из буфера обмена</string>
|
||||||
<string name="per_app_proxy_settings">Выбор приложений</string>
|
<string name="per_app_proxy_settings">Раздельное туннелирование</string>
|
||||||
<string name="per_app_proxy_settings_enable">Выбор приложений</string>
|
<string name="per_app_proxy_settings_enable">Раздельное туннелирование</string>
|
||||||
|
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">Настройки</string>
|
<string name="title_settings">Настройки</string>
|
||||||
<string name="title_advanced">Расширенные настройки</string>
|
<string name="title_advanced">Расширенные настройки</string>
|
||||||
<string name="title_core_settings">Настройки ядра</string>
|
<string name="title_core_settings">Настройки ядра</string>
|
||||||
<string name="title_vpn_settings">Настройки VPN</string>
|
<string name="title_vpn_settings">Настройки VPN</string>
|
||||||
<string name="title_pref_per_app_proxy">Прокси для выбранных приложений</string>
|
<string name="title_pref_per_app_proxy">Раздельное туннелирование</string>
|
||||||
<string name="summary_pref_per_app_proxy">Основной: выбранное приложение соединяется через прокси, не выбранное — напрямую;\nРежим обхода: выбранное приложение соединяется напрямую, не выбранное — через прокси.\nЕсть возможность автоматического выбора проксируемых приложений в меню.</string>
|
<string name="summary_pref_per_app_proxy">Основной: выбранное приложение соединяется через прокси, не выбранное — напрямую;\nРежим обхода: выбранное приложение соединяется напрямую, не выбранное — через прокси.\nЕсть возможность автоматического выбора проксируемых приложений в меню.</string>
|
||||||
<string name="title_pref_is_booted">Автоподключение при запуске</string>
|
<string name="title_pref_is_booted">Автоподключение при запуске</string>
|
||||||
<string name="summary_pref_is_booted">Автоматически подключаться к выбранному серверу при запуске приложения (может оказаться неудачным)</string>
|
<string name="summary_pref_is_booted">Автоматически подключаться к выбранному серверу при запуске приложения (может оказаться неудачным)</string>
|
||||||
@@ -159,6 +159,11 @@
|
|||||||
<string name="title_pref_auto_sort_after_test">Автосортировка профилей</string>
|
<string name="title_pref_auto_sort_after_test">Автосортировка профилей</string>
|
||||||
<string name="summary_pref_auto_sort_after_test">Автоматическая сортировка профилей после проверки (результаты проверки могут быть неточными)</string>
|
<string name="summary_pref_auto_sort_after_test">Автоматическая сортировка профилей после проверки (результаты проверки могут быть неточными)</string>
|
||||||
|
|
||||||
|
<string name="title_pref_show_copy_button">Показывать кнопку копирования</string>
|
||||||
|
<string name="summary_pref_show_copy_button">Показывать кнопку для копирования конфигурации сервера в буфер обмена</string>
|
||||||
|
<string name="title_pref_show_server_ip">Показывать IP / хост сервера</string>
|
||||||
|
<string name="summary_pref_show_server_ip">Отображать IP-адрес или хост сервера под названием</string>
|
||||||
|
|
||||||
<string name="title_mux_settings">Настройки мультиплексирования</string>
|
<string name="title_mux_settings">Настройки мультиплексирования</string>
|
||||||
<string name="title_pref_mux_enabled">Использовать мультиплексирование</string>
|
<string name="title_pref_mux_enabled">Использовать мультиплексирование</string>
|
||||||
<string name="summary_pref_mux_enabled">Быстрее, но это может привести к нестабильному соединению.\nНиже можно настроить обработку TCP, UDP и QUIC.</string>
|
<string name="summary_pref_mux_enabled">Быстрее, но это может привести к нестабильному соединению.\nНиже можно настроить обработку TCP, UDP и QUIC.</string>
|
||||||
@@ -237,8 +242,6 @@
|
|||||||
<string name="title_pref_group_all_display">Общая вкладка групп</string>
|
<string name="title_pref_group_all_display">Общая вкладка групп</string>
|
||||||
<string name="summary_pref_group_all_display">Показывать дополнительную вкладку со всеми профилями групп</string>
|
<string name="summary_pref_group_all_display">Показывать дополнительную вкладку со всеми профилями групп</string>
|
||||||
|
|
||||||
<string name="title_pref_show_copy_button">Кнопка копирования</string>
|
|
||||||
<string name="summary_pref_show_copy_button">Показывать кнопку копирования конфигурации сервера в буфер обмена</string>
|
|
||||||
<!-- AboutActivity -->
|
<!-- AboutActivity -->
|
||||||
<string name="title_pref_feedback">Обратная связь</string>
|
<string name="title_pref_feedback">Обратная связь</string>
|
||||||
<string name="summary_pref_feedback">Предложить улучшение или сообщить об ошибке на GitHub</string>
|
<string name="summary_pref_feedback">Предложить улучшение или сообщить об ошибке на GitHub</string>
|
||||||
@@ -345,7 +348,8 @@
|
|||||||
<string name="connection_test_fail">Интернет недоступен</string>
|
<string name="connection_test_fail">Интернет недоступен</string>
|
||||||
<string name="connection_test_error_status_code">Код ошибки: #%d</string>
|
<string name="connection_test_error_status_code">Код ошибки: #%d</string>
|
||||||
<string name="connection_connected">Соединено, нажмите для проверки</string>
|
<string name="connection_connected">Соединено, нажмите для проверки</string>
|
||||||
<string name="connection_not_connected">Нет соединения</string>
|
<string name="connection_not_connected">Ожидаем действий</string>
|
||||||
|
<string name="connection_updating_profiles">Обновление профилей…</string>
|
||||||
<string name="connection_runing_task_left">Запущено проверок: %s</string>
|
<string name="connection_runing_task_left">Запущено проверок: %s</string>
|
||||||
|
|
||||||
<string name="import_subscription_success">Подписка импортирована</string>
|
<string name="import_subscription_success">Подписка импортирована</string>
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab">
|
|
||||||
<item name="textAllCaps">false</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,54 +1,66 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="colorPing">#1565C0</color>
|
<color name="colorPing">#006494</color>
|
||||||
<color name="colorPingRed">#FF0099</color>
|
<color name="colorPingGood">#2E7D32</color>
|
||||||
<color name="colorConfigType">#1976D2</color>
|
<color name="colorPingMedium">#9A6700</color>
|
||||||
|
<color name="status_connected">#4CAF50</color>
|
||||||
|
<color name="colorPingRed">#BA1A1A</color>
|
||||||
|
<color name="colorConfigType">#1565C0</color>
|
||||||
<color name="colorWhite">#FFFFFF</color>
|
<color name="colorWhite">#FFFFFF</color>
|
||||||
<color name="color_fab_active">#000000</color>
|
<color name="color_fab_active">@color/md_theme_primary</color>
|
||||||
<color name="color_fab_inactive">#9C9C9C</color>
|
<color name="color_fab_inactive">@color/md_theme_secondaryContainer</color>
|
||||||
<color name="divider_color_light">#E0E0E0</color>
|
<color name="divider_color_light">@color/md_theme_outlineVariant</color>
|
||||||
|
<color name="server_list_divider">#22CAC4D0</color>
|
||||||
<color name="colorIndicator">@color/md_theme_primary</color>
|
<color name="colorIndicator">@color/md_theme_primary</color>
|
||||||
|
|
||||||
<color name="md_theme_primary">#000000</color>
|
<!-- M3 Light scheme — Purple/Violet tonal palette -->
|
||||||
|
<color name="md_theme_primary">#6750A4</color>
|
||||||
<color name="md_theme_onPrimary">#FFFFFF</color>
|
<color name="md_theme_onPrimary">#FFFFFF</color>
|
||||||
<color name="md_theme_primaryContainer">#E0E0E0</color>
|
<color name="md_theme_primaryContainer">#EADDFF</color>
|
||||||
<color name="md_theme_onPrimaryContainer">#000000</color>
|
<color name="md_theme_onPrimaryContainer">#21005D</color>
|
||||||
|
|
||||||
<color name="md_theme_secondary">#1976D2</color>
|
<color name="md_theme_secondary">#625B71</color>
|
||||||
<color name="md_theme_onSecondary">#FFFFFF</color>
|
<color name="md_theme_onSecondary">#FFFFFF</color>
|
||||||
<color name="md_theme_secondaryContainer">#FFE8D6</color>
|
<color name="md_theme_secondaryContainer">#E8DEF8</color>
|
||||||
<color name="md_theme_onSecondaryContainer">#2B1700</color>
|
<color name="md_theme_onSecondaryContainer">#1D192B</color>
|
||||||
|
|
||||||
<color name="md_theme_tertiary">#1565C0</color>
|
<color name="md_theme_tertiary">#7D5260</color>
|
||||||
<color name="md_theme_onTertiary">#FFFFFF</color>
|
<color name="md_theme_onTertiary">#FFFFFF</color>
|
||||||
<color name="md_theme_tertiaryContainer">#BBDEFB</color>
|
<color name="md_theme_tertiaryContainer">#FFD8E4</color>
|
||||||
<color name="md_theme_onTertiaryContainer">#00201A</color>
|
<color name="md_theme_onTertiaryContainer">#31111D</color>
|
||||||
|
|
||||||
<!-- Error colors -->
|
<!-- Error colors -->
|
||||||
<color name="md_theme_error">#BA1A1A</color>
|
<color name="md_theme_error">#B3261E</color>
|
||||||
<color name="md_theme_errorContainer">#FFDAD6</color>
|
<color name="md_theme_errorContainer">#F9DEDC</color>
|
||||||
<color name="md_theme_onError">#FFFFFF</color>
|
<color name="md_theme_onError">#FFFFFF</color>
|
||||||
<color name="md_theme_onErrorContainer">#410002</color>
|
<color name="md_theme_onErrorContainer">#410E0B</color>
|
||||||
|
|
||||||
<!-- Background colors -->
|
<!-- Background colors -->
|
||||||
<color name="md_theme_background">#FFFFFF</color>
|
<color name="md_theme_background">#FFFBFE</color>
|
||||||
<color name="md_theme_onBackground">#1C1B1F</color>
|
<color name="md_theme_onBackground">#1C1B1F</color>
|
||||||
|
|
||||||
<!-- Surface colors -->
|
<!-- Surface colors — M3 tonal surface hierarchy -->
|
||||||
<color name="md_theme_surface">#FFFFFF</color>
|
<color name="md_theme_surface">#FFFBFE</color>
|
||||||
<color name="md_theme_onSurface">#1C1B1F</color>
|
<color name="md_theme_onSurface">#1C1B1F</color>
|
||||||
<color name="md_theme_surfaceVariant">#E7E0EC</color>
|
<color name="md_theme_surfaceVariant">#E7E0EC</color>
|
||||||
<color name="md_theme_onSurfaceVariant">#49454F</color>
|
<color name="md_theme_onSurfaceVariant">#49454F</color>
|
||||||
<color name="md_theme_inverseSurface">#313033</color>
|
<color name="md_theme_inverseSurface">#313033</color>
|
||||||
<color name="md_theme_inverseOnSurface">#F4EFF4</color>
|
<color name="md_theme_inverseOnSurface">#F4EFF4</color>
|
||||||
|
|
||||||
|
<!-- Surface containers — M3 elevation tones -->
|
||||||
|
<color name="md_theme_surfaceContainerLowest">#FFFFFF</color>
|
||||||
|
<color name="md_theme_surfaceContainerLow">#F7F2FA</color>
|
||||||
|
<color name="md_theme_surfaceContainer">#F3EDF7</color>
|
||||||
|
<color name="md_theme_surfaceContainerHigh">#ECE6F0</color>
|
||||||
|
<color name="md_theme_surfaceContainerHighest">#E6E0E9</color>
|
||||||
|
|
||||||
<!-- Outline colors -->
|
<!-- Outline colors -->
|
||||||
<color name="md_theme_outline">#79747E</color>
|
<color name="md_theme_outline">#79747E</color>
|
||||||
<color name="md_theme_outlineVariant">#CAC4D0</color>
|
<color name="md_theme_outlineVariant">#CAC4D0</color>
|
||||||
|
|
||||||
<!-- Other colors -->
|
<!-- Other colors -->
|
||||||
<color name="md_theme_inversePrimary">#C0C0C0</color>
|
<color name="md_theme_inversePrimary">#D0BCFF</color>
|
||||||
<color name="md_theme_shadow">#000000</color>
|
<color name="md_theme_shadow">#000000</color>
|
||||||
<color name="md_theme_surfaceTint">#000000</color>
|
<color name="md_theme_surfaceTint">#6750A4</color>
|
||||||
<color name="md_theme_scrim">#000000</color>
|
<color name="md_theme_scrim">#000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -146,7 +146,7 @@
|
|||||||
<string name="menu_item_import_proxy_app">Import from Clipboard</string>
|
<string name="menu_item_import_proxy_app">Import from Clipboard</string>
|
||||||
<string name="per_app_proxy_settings">Раздельное туннелирование</string>
|
<string name="per_app_proxy_settings">Раздельное туннелирование</string>
|
||||||
<string name="per_app_proxy_settings_enable">Включить</string>
|
<string name="per_app_proxy_settings_enable">Включить</string>
|
||||||
<string name="split_tunneling_description">Выберите приложения, которые будут использовать VPN. В режиме обхода — выбранные приложения НЕ используют VPN.</string>
|
<string name="split_tunneling_description">Выберите приложения, которые будут использовать VPN — остальные приложения, например банки, будут идти напрямую через ваш домашний интернет.\n\nВ режиме обхода всё зеркально — выбранные приложения не используют VPN.</string>
|
||||||
|
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">Settings</string>
|
<string name="title_settings">Settings</string>
|
||||||
@@ -163,6 +163,8 @@
|
|||||||
|
|
||||||
<string name="title_pref_show_copy_button">Show copy button</string>
|
<string name="title_pref_show_copy_button">Show copy button</string>
|
||||||
<string name="summary_pref_show_copy_button">Show button to copy server configuration to clipboard</string>
|
<string name="summary_pref_show_copy_button">Show button to copy server configuration to clipboard</string>
|
||||||
|
<string name="title_pref_show_server_ip">Show server IP / host</string>
|
||||||
|
<string name="summary_pref_show_server_ip">Display the server IP address or host under the server name</string>
|
||||||
|
|
||||||
<string name="title_mux_settings">Mux Settings</string>
|
<string name="title_mux_settings">Mux Settings</string>
|
||||||
<string name="title_pref_mux_enabled">Enable Mux</string>
|
<string name="title_pref_mux_enabled">Enable Mux</string>
|
||||||
@@ -353,6 +355,7 @@
|
|||||||
<string name="connection_test_error_status_code">Error code: #%d</string>
|
<string name="connection_test_error_status_code">Error code: #%d</string>
|
||||||
<string name="connection_connected">Connected, tap to check connection</string>
|
<string name="connection_connected">Connected, tap to check connection</string>
|
||||||
<string name="connection_not_connected">Готово к подключению</string>
|
<string name="connection_not_connected">Готово к подключению</string>
|
||||||
|
<string name="connection_updating_profiles">Updating profiles…</string>
|
||||||
<string name="connection_runing_task_left">Проверено успешно: %s</string>
|
<string name="connection_runing_task_left">Проверено успешно: %s</string>
|
||||||
|
|
||||||
<string name="import_subscription_success">Subscription imported Successfully</string>
|
<string name="import_subscription_success">Subscription imported Successfully</string>
|
||||||
|
|||||||
@@ -1,58 +1,65 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<!-- Common base theme: put all shared items here so day/night can reuse -->
|
<!-- Common base theme -->
|
||||||
<style name="AppThemeBase" parent="Theme.Material3.DayNight">
|
<style name="AppThemeBase" parent="Theme.Material3.DayNight">
|
||||||
<!-- Primary colors - main tone: black -->
|
<!-- Primary -->
|
||||||
<item name="colorPrimary">@color/md_theme_primary</item>
|
<item name="colorPrimary">@color/md_theme_primary</item>
|
||||||
<item name="colorOnPrimary">@color/md_theme_onPrimary</item>
|
<item name="colorOnPrimary">@color/md_theme_onPrimary</item>
|
||||||
<item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item>
|
<item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item>
|
||||||
<item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item>
|
<item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item>
|
||||||
|
|
||||||
|
<!-- Secondary -->
|
||||||
<item name="colorSecondary">@color/md_theme_secondary</item>
|
<item name="colorSecondary">@color/md_theme_secondary</item>
|
||||||
<item name="colorOnSecondary">@color/md_theme_onSecondary</item>
|
<item name="colorOnSecondary">@color/md_theme_onSecondary</item>
|
||||||
<item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item>
|
<item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item>
|
||||||
<item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item>
|
<item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item>
|
||||||
|
|
||||||
|
<!-- Tertiary -->
|
||||||
<item name="colorTertiary">@color/md_theme_tertiary</item>
|
<item name="colorTertiary">@color/md_theme_tertiary</item>
|
||||||
<item name="colorOnTertiary">@color/md_theme_onTertiary</item>
|
<item name="colorOnTertiary">@color/md_theme_onTertiary</item>
|
||||||
<item name="colorTertiaryContainer">@color/md_theme_tertiaryContainer</item>
|
<item name="colorTertiaryContainer">@color/md_theme_tertiaryContainer</item>
|
||||||
<item name="colorOnTertiaryContainer">@color/md_theme_onTertiaryContainer</item>
|
<item name="colorOnTertiaryContainer">@color/md_theme_onTertiaryContainer</item>
|
||||||
|
|
||||||
<!-- Error colors -->
|
<!-- Error -->
|
||||||
<item name="colorError">@color/md_theme_error</item>
|
<item name="colorError">@color/md_theme_error</item>
|
||||||
<item name="colorOnError">@color/md_theme_onError</item>
|
<item name="colorOnError">@color/md_theme_onError</item>
|
||||||
<item name="colorErrorContainer">@color/md_theme_errorContainer</item>
|
<item name="colorErrorContainer">@color/md_theme_errorContainer</item>
|
||||||
<item name="colorOnErrorContainer">@color/md_theme_onErrorContainer</item>
|
<item name="colorOnErrorContainer">@color/md_theme_onErrorContainer</item>
|
||||||
|
|
||||||
<!-- Surface colors -->
|
<!-- Surface -->
|
||||||
<item name="colorSurface">@color/md_theme_surface</item>
|
<item name="colorSurface">@color/md_theme_surface</item>
|
||||||
<item name="colorOnSurface">@color/md_theme_onSurface</item>
|
<item name="colorOnSurface">@color/md_theme_onSurface</item>
|
||||||
<item name="colorSurfaceVariant">@color/md_theme_surfaceVariant</item>
|
<item name="colorSurfaceVariant">@color/md_theme_surfaceVariant</item>
|
||||||
<item name="colorOnSurfaceVariant">@color/md_theme_onSurfaceVariant</item>
|
<item name="colorOnSurfaceVariant">@color/md_theme_onSurfaceVariant</item>
|
||||||
<item name="colorSurfaceInverse">@color/md_theme_inverseSurface</item>
|
<item name="colorSurfaceInverse">@color/md_theme_inverseSurface</item>
|
||||||
<item name="colorOnSurfaceInverse">@color/md_theme_inverseOnSurface</item>
|
<item name="colorOnSurfaceInverse">@color/md_theme_inverseOnSurface</item>
|
||||||
<item name="colorSurfaceContainer">@color/md_theme_surface</item>
|
<item name="colorSurfaceContainer">@color/md_theme_surfaceContainer</item>
|
||||||
<item name="colorSurfaceContainerHigh">@color/md_theme_surface</item>
|
<item name="colorSurfaceContainerHigh">@color/md_theme_surfaceContainerHigh</item>
|
||||||
<item name="colorSurfaceContainerHighest">@color/md_theme_surface</item>
|
<item name="colorSurfaceContainerHighest">@color/md_theme_surfaceContainerHighest</item>
|
||||||
<item name="colorSurfaceContainerLow">@color/md_theme_surface</item>
|
<item name="colorSurfaceContainerLow">@color/md_theme_surfaceContainerLow</item>
|
||||||
<item name="colorSurfaceContainerLowest">@color/md_theme_surface</item>
|
<item name="colorSurfaceContainerLowest">@color/md_theme_surfaceContainerLowest</item>
|
||||||
|
|
||||||
<!-- Background colors -->
|
<!-- Background -->
|
||||||
<item name="android:colorBackground">@color/md_theme_background</item>
|
<item name="android:colorBackground">@color/md_theme_background</item>
|
||||||
<item name="colorOnBackground">@color/md_theme_onBackground</item>
|
<item name="colorOnBackground">@color/md_theme_onBackground</item>
|
||||||
|
|
||||||
<!-- Outline colors -->
|
<!-- Outline -->
|
||||||
<item name="colorOutline">@color/md_theme_outline</item>
|
<item name="colorOutline">@color/md_theme_outline</item>
|
||||||
<item name="colorOutlineVariant">@color/md_theme_outlineVariant</item>
|
<item name="colorOutlineVariant">@color/md_theme_outlineVariant</item>
|
||||||
|
|
||||||
<!-- Other colors -->
|
<!-- Misc -->
|
||||||
<item name="colorPrimaryInverse">@color/md_theme_inversePrimary</item>
|
<item name="colorPrimaryInverse">@color/md_theme_inversePrimary</item>
|
||||||
|
|
||||||
<!-- Status bar and navigation bar - system bars -->
|
<!-- System bars — transparent so edge-to-edge works -->
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
<item name="android:navigationBarColor">@color/md_theme_surface</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
|
|
||||||
<!-- Typography: use Roboto (Google's Material font) everywhere -->
|
<!-- Shape — M3 uses larger corner radii -->
|
||||||
|
<item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.App.SmallComponent</item>
|
||||||
|
<item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>
|
||||||
|
<item name="shapeAppearanceLargeComponent">@style/ShapeAppearance.App.LargeComponent</item>
|
||||||
|
|
||||||
|
<!-- Typography: Roboto -->
|
||||||
<item name="android:fontFamily">sans-serif</item>
|
<item name="android:fontFamily">sans-serif</item>
|
||||||
<item name="fontFamily">sans-serif</item>
|
<item name="fontFamily">sans-serif</item>
|
||||||
<item name="android:editTextStyle">@style/RobotoEditTextStyle</item>
|
<item name="android:editTextStyle">@style/RobotoEditTextStyle</item>
|
||||||
@@ -60,7 +67,23 @@
|
|||||||
<item name="android:dialogTheme">@style/RobotoAlertDialogTheme</item>
|
<item name="android:dialogTheme">@style/RobotoAlertDialogTheme</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="RobotoEditTextStyle" parent="Widget.AppCompat.EditText">
|
<!-- M3 Shape tokens -->
|
||||||
|
<style name="ShapeAppearance.App.SmallComponent" parent="ShapeAppearance.Material3.SmallComponent">
|
||||||
|
<item name="cornerFamily">rounded</item>
|
||||||
|
<item name="cornerSize">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.Material3.MediumComponent">
|
||||||
|
<item name="cornerFamily">rounded</item>
|
||||||
|
<item name="cornerSize">12dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ShapeAppearance.App.LargeComponent" parent="ShapeAppearance.Material3.LargeComponent">
|
||||||
|
<item name="cornerFamily">rounded</item>
|
||||||
|
<item name="cornerSize">16dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="RobotoEditTextStyle" parent="Widget.Material3.TextInputEditText.OutlinedBox">
|
||||||
<item name="android:fontFamily">sans-serif</item>
|
<item name="android:fontFamily">sans-serif</item>
|
||||||
<item name="android:textSize">16sp</item>
|
<item name="android:textSize">16sp</item>
|
||||||
</style>
|
</style>
|
||||||
@@ -68,16 +91,15 @@
|
|||||||
<style name="RobotoAlertDialogTheme" parent="ThemeOverlay.Material3.MaterialAlertDialog">
|
<style name="RobotoAlertDialogTheme" parent="ThemeOverlay.Material3.MaterialAlertDialog">
|
||||||
<item name="android:fontFamily">sans-serif</item>
|
<item name="android:fontFamily">sans-serif</item>
|
||||||
<item name="fontFamily">sans-serif</item>
|
<item name="fontFamily">sans-serif</item>
|
||||||
|
<item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Day/Night theme: inherit common values and set light-mode-specific items -->
|
<!-- Light -->
|
||||||
<style name="AppThemeDayNight" parent="AppThemeBase">
|
<style name="AppThemeDayNight" parent="AppThemeBase">
|
||||||
<!-- day/night-specific overrides (light/default) -->
|
|
||||||
<item name="android:windowLightStatusBar">true</item>
|
<item name="android:windowLightStatusBar">true</item>
|
||||||
<item name="android:windowLightNavigationBar" tools:targetApi="27">true</item>
|
<item name="android:windowLightNavigationBar" tools:targetApi="27">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Theme without ActionBar -->
|
|
||||||
<style name="AppThemeDayNight.NoActionBar" parent="AppThemeDayNight">
|
<style name="AppThemeDayNight.NoActionBar" parent="AppThemeDayNight">
|
||||||
<item name="windowActionBar">false</item>
|
<item name="windowActionBar">false</item>
|
||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
@@ -89,8 +111,40 @@
|
|||||||
<item name="android:windowIsTranslucent">true</item>
|
<item name="android:windowIsTranslucent">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- Switch uses primary color -->
|
||||||
<style name="BrandedSwitch" parent="AppThemeDayNight">
|
<style name="BrandedSwitch" parent="AppThemeDayNight">
|
||||||
<item name="colorPrimary">@color/color_fab_active</item>
|
<item name="colorPrimary">@color/md_theme_primary</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Rounded-square FAB shape overlay (16dp corners) -->
|
||||||
|
<style name="ShapeAppearance.App.RoundedSquare" parent="ShapeAppearance.Material3.SmallComponent">
|
||||||
|
<item name="cornerFamily">rounded</item>
|
||||||
|
<item name="cornerSize">16dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Square icon button: no insets, no minHeight, no text -->
|
||||||
|
<style name="Widget.ActionSquareButton" parent="Widget.Material3.Button">
|
||||||
|
<item name="android:minWidth">0dp</item>
|
||||||
|
<item name="android:minHeight">0dp</item>
|
||||||
|
<item name="android:insetTop">0dp</item>
|
||||||
|
<item name="android:insetBottom">0dp</item>
|
||||||
|
<item name="android:insetLeft">0dp</item>
|
||||||
|
<item name="android:insetRight">0dp</item>
|
||||||
|
<item name="android:paddingStart">0dp</item>
|
||||||
|
<item name="android:paddingEnd">0dp</item>
|
||||||
|
<item name="android:paddingTop">0dp</item>
|
||||||
|
<item name="android:paddingBottom">0dp</item>
|
||||||
|
<item name="iconGravity">textStart</item>
|
||||||
|
<item name="iconPadding">0dp</item>
|
||||||
|
<item name="android:text"></item>
|
||||||
|
<item name="shapeAppearance">@style/ShapeAppearance.App.RoundedSquare</item>
|
||||||
|
<item name="elevation">0dp</item>
|
||||||
|
<item name="android:stateListAnimator">@null</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Tab label -->
|
||||||
|
<style name="TabLayoutTextStyle" parent="TextAppearance.Material3.LabelLarge">
|
||||||
|
<item name="android:textSize">14sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -34,6 +34,12 @@
|
|||||||
android:summary="@string/summary_pref_show_copy_button"
|
android:summary="@string/summary_pref_show_copy_button"
|
||||||
android:title="@string/title_pref_show_copy_button" />
|
android:title="@string/title_pref_show_copy_button" />
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="pref_show_server_ip"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:summary="@string/summary_pref_show_server_ip"
|
||||||
|
android:title="@string/title_pref_show_server_ip" />
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="auto"
|
android:defaultValue="auto"
|
||||||
android:entries="@array/language_select"
|
android:entries="@array/language_select"
|
||||||
|
|||||||
Reference in New Issue
Block a user