feat(ui): enable edge-to-edge layout and fix status bar color

This commit is contained in:
zarazaex69
2026-05-04 19:03:12 +03:00
parent 9249ff9bce
commit cb1ea3c3a3
7 changed files with 62 additions and 35 deletions
@@ -32,8 +32,9 @@ class AngApplication : Application() {
*/
override fun onCreate() {
super.onCreate()
// Apply Material You dynamic colors (Android 12+)
DynamicColors.applyToActivitiesIfAvailable(this)
// DynamicColors отключён — на Android 12-15 он красит статус-бар в акцент ОС
// и это нельзя переопределить через statusBarColor
// DynamicColors.applyToActivitiesIfAvailable(this)
val mmkvDir = java.io.File(filesDir, "mmkv")
if (!java.io.File(mmkvDir, "MAIN").exists()) {
@@ -1,7 +1,6 @@
package xyz.zarazaex.olc.ui
import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
@@ -16,7 +15,6 @@ import androidx.core.view.WindowCompat
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.color.MaterialColors
import com.google.android.material.progressindicator.LinearProgressIndicator
import xyz.zarazaex.olc.R
import xyz.zarazaex.olc.handler.SettingsManager
@@ -187,13 +185,10 @@ abstract class BaseActivity : AppCompatActivity() {
}
private fun syncStatusBarWithToolbar(toolbar: Toolbar) {
val toolbarColor = (toolbar.background as? ColorDrawable)?.color
?: toolbar.backgroundTintList?.defaultColor
?: MaterialColors.getColor(toolbar, com.google.android.material.R.attr.colorSurface)
window.statusBarColor = toolbarColor
// Статус-бар прозрачный (задан в теме). Управляем только цветом иконок.
val bgColor = ContextCompat.getColor(this, R.color.md_theme_surface)
WindowCompat.getInsetsController(window, window.decorView)?.isAppearanceLightStatusBars =
ColorUtils.calculateLuminance(toolbarColor) > 0.5
ColorUtils.calculateLuminance(bgColor) > 0.5
}
/**
@@ -18,6 +18,7 @@ import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat
import androidx.core.view.GravityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
@@ -76,6 +77,19 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
setContentView(binding.root)
setupToolbar(binding.toolbar, false, getString(R.string.app_name))
// edge-to-edge: контент идёт под статус-бар, AppBarLayout тянется под него же
WindowCompat.setDecorFitsSystemWindows(window, false)
ViewCompat.setOnApplyWindowInsetsListener(binding.appBarLayout) { v, insets ->
v.setPadding(0, insets.getInsets(WindowInsetsCompat.Type.statusBars()).top, 0, 0)
insets
}
// Нижние кнопки поднимаются над навигационной панелью
ViewCompat.setOnApplyWindowInsetsListener(binding.bottomContainer) { v, insets ->
val navBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
v.setPadding(0, 0, 0, navBarHeight)
insets
}
groupPagerAdapter = GroupPagerAdapter(this, emptyList())
binding.viewPager.adapter = groupPagerAdapter
binding.viewPager.isUserInputEnabled = true
@@ -171,15 +185,15 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
mainViewModel.isTesting.observe(this) { testing ->
setButtonsEnabled(!testing)
if (testing) {
// Allow stopping the test
binding.btnSummaryLite.isEnabled = true
binding.btnSummaryLite.alpha = 1.0f
binding.btnSummaryLite.setImageResource(R.drawable.ic_stop_24dp)
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_active))
} else {
binding.btnSummaryLite.setImageResource(R.drawable.bolt_24)
// Re-apply running state to set correct enabled state
val isRunning = mainViewModel.isRunning.value == true
binding.btnSummaryLite.isEnabled = !isRunning
binding.btnSummaryLite.alpha = if (isRunning) 0.5f else 1.0f
binding.btnSummaryLite.isEnabled = true
binding.btnSummaryLite.alpha = 1.0f
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
}
}
@@ -414,6 +428,16 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
private fun showStatus(resId: Int) = showStatus(getString(resId))
private fun accentColor(): ColorStateList {
val typedValue = android.util.TypedValue()
theme.resolveAttribute(androidx.appcompat.R.attr.colorPrimary, typedValue, true)
val color = if (typedValue.resourceId != 0)
ContextCompat.getColor(this, typedValue.resourceId)
else
typedValue.data
return ColorStateList.valueOf(color)
}
private fun applyRunningState(isLoading: Boolean, isRunning: Boolean) {
if (isLoading) {
binding.fab.isEnabled = false
@@ -424,27 +448,22 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect
if (isRunning) {
binding.fab.isEnabled = true
binding.fab.alpha = 1.0f
binding.fab.setImageResource(R.drawable.security_24)
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_active))
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_active))
binding.fab.backgroundTintList = accentColor()
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
binding.fab.contentDescription = getString(R.string.action_stop_service)
setTestState(getString(R.string.connection_connected))
binding.layoutTest.isFocusable = true
// Block lightning while VPN is connected (unless test is running)
if (mainViewModel.isTesting.value != true) {
binding.btnSummaryLite.isEnabled = false
binding.btnSummaryLite.alpha = 0.5f
}
// Молния всегда активна — пользователь может запустить тест даже при работающем VPN
binding.btnSummaryLite.isEnabled = true
binding.btnSummaryLite.alpha = 1.0f
} else {
binding.fab.isEnabled = true
binding.fab.alpha = 1.0f
binding.fab.setImageResource(R.drawable.shield_24)
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
binding.btnSummaryLite.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
binding.fab.contentDescription = getString(R.string.tasker_start_service)
setTestState(getString(R.string.connection_not_connected))
binding.layoutTest.isFocusable = false
// Enable lightning when VPN is disconnected
binding.btnSummaryLite.isEnabled = true
binding.btnSummaryLite.alpha = 1.0f
}
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorOnSurface"
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
</vector>
@@ -4,17 +4,19 @@
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:background="@color/md_theme_surface">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="@color/md_theme_surface"
app:elevation="0dp">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
@@ -67,6 +69,7 @@
android:layout_weight="1" />
<LinearLayout
android:id="@+id/bottom_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
+6 -6
View File
@@ -13,15 +13,15 @@
android:title="Проверить задержку профилей"
app:showAsAction="always" />
<item
android:id="@+id/sub_update"
android:icon="@drawable/update_24"
android:title="@string/title_sub_update"
app:showAsAction="always" />
<item
android:id="@+id/filter_by_country"
android:icon="@drawable/public_24"
android:title="Фильтр по странам"
app:showAsAction="always" />
<item
android:id="@+id/sub_update"
android:icon="@drawable/ic_check_update_24dp"
android:title="@string/title_sub_update"
app:showAsAction="always" />
</menu>
+1 -1
View File
@@ -49,7 +49,7 @@
<item name="colorPrimaryInverse">@color/md_theme_inversePrimary</item>
<!-- Status bar and navigation bar - system bars -->
<item name="android:statusBarColor">@color/md_theme_surface</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@color/md_theme_surface</item>
<!-- Typography: use Roboto (Google's Material font) everywhere -->