ui: use real M3 themeing on TV
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
4944762d7c
commit
75899594c3
@ -17,8 +17,6 @@ import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
|||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||||
import com.google.android.material.color.DynamicColors
|
import com.google.android.material.color.DynamicColors
|
||||||
import com.google.android.material.color.DynamicColorsOptions
|
|
||||||
import com.wireguard.android.activity.TvMainActivity
|
|
||||||
import com.wireguard.android.backend.Backend
|
import com.wireguard.android.backend.Backend
|
||||||
import com.wireguard.android.backend.GoBackend
|
import com.wireguard.android.backend.GoBackend
|
||||||
import com.wireguard.android.backend.WgQuickBackend
|
import com.wireguard.android.backend.WgQuickBackend
|
||||||
@ -89,9 +87,7 @@ class Application : android.app.Application() {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
Log.i(TAG, USER_AGENT)
|
Log.i(TAG, USER_AGENT)
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
DynamicColors.applyToActivitiesIfAvailable(this,
|
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||||
// TODO: Remove this second argument once the TV theme has a proper M3 color palette.
|
|
||||||
DynamicColorsOptions.Builder().setPrecondition { activity, _ -> activity !is TvMainActivity }.build())
|
|
||||||
rootShell = RootShell(applicationContext)
|
rootShell = RootShell(applicationContext)
|
||||||
toolsInstaller = ToolsInstaller(applicationContext, rootShell)
|
toolsInstaller = ToolsInstaller(applicationContext, rootShell)
|
||||||
preferencesDataStore = PreferenceDataStoreFactory.create { applicationContext.preferencesDataStoreFile("settings") }
|
preferencesDataStore = PreferenceDataStoreFactory.create { applicationContext.preferencesDataStoreFile("settings") }
|
||||||
|
@ -23,6 +23,7 @@ import com.wireguard.android.R
|
|||||||
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler
|
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler
|
||||||
import com.wireguard.android.widget.ToggleSwitch
|
import com.wireguard.android.widget.ToggleSwitch
|
||||||
import com.wireguard.android.widget.ToggleSwitch.OnBeforeCheckedChangeListener
|
import com.wireguard.android.widget.ToggleSwitch.OnBeforeCheckedChangeListener
|
||||||
|
import com.wireguard.android.widget.TvCardView
|
||||||
import com.wireguard.config.Attribute
|
import com.wireguard.config.Attribute
|
||||||
import com.wireguard.config.InetNetwork
|
import com.wireguard.config.InetNetwork
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
@ -168,4 +169,16 @@ object BindingAdapters {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@BindingAdapter("isUp")
|
||||||
|
fun setIsUp(card: TvCardView, up: Boolean) {
|
||||||
|
card.isUp = up
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@BindingAdapter("isDeleting")
|
||||||
|
fun setIsDeleting(card: TvCardView, deleting: Boolean) {
|
||||||
|
card.isDeleting = deleting
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
44
ui/src/main/java/com/wireguard/android/widget/TvCardView.kt
Normal file
44
ui/src/main/java/com/wireguard/android/widget/TvCardView.kt
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.wireguard.android.widget
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.wireguard.android.R
|
||||||
|
|
||||||
|
class TvCardView(context: Context?, attrs: AttributeSet?) : MaterialCardView(context, attrs) {
|
||||||
|
var isUp: Boolean = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
refreshDrawableState()
|
||||||
|
}
|
||||||
|
var isDeleting: Boolean = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
refreshDrawableState()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDrawableState(extraSpace: Int): IntArray {
|
||||||
|
if (isUp || isDeleting) {
|
||||||
|
val drawableState = super.onCreateDrawableState(extraSpace + (if (isUp) 1 else 0) + (if (isDeleting) 1 else 0))
|
||||||
|
if (isUp) {
|
||||||
|
View.mergeDrawableStates(drawableState, STATE_IS_UP)
|
||||||
|
}
|
||||||
|
if (isDeleting) {
|
||||||
|
View.mergeDrawableStates(drawableState, STATE_IS_DELETING)
|
||||||
|
}
|
||||||
|
return drawableState
|
||||||
|
}
|
||||||
|
return super.onCreateDrawableState(extraSpace)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val STATE_IS_UP = intArrayOf(R.attr.state_isUp)
|
||||||
|
private val STATE_IS_DELETING = intArrayOf(R.attr.state_isDeleting)
|
||||||
|
}
|
||||||
|
}
|
7
ui/src/main/res/color/tv_list_item_tint.xml
Normal file
7
ui/src/main/res/color/tv_list_item_tint.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item app:state_isUp="true" app:state_isDeleting="false" android:color="?attr/colorPrimaryInverse" />
|
||||||
|
<item android:state_focused="true" app:state_isDeleting="true" android:color="?attr/colorErrorContainer" />
|
||||||
|
<item android:color="?attr/colorOnSurfaceInverse" />
|
||||||
|
</selector>
|
@ -135,7 +135,6 @@
|
|||||||
android:visibility="@{isDeleting ? View.GONE : View.VISIBLE}"
|
android:visibility="@{isDeleting ? View.GONE : View.VISIBLE}"
|
||||||
app:icon="@{filesRoot.isEmpty ? @drawable/ic_action_add_white : @drawable/ic_arrow_back}"
|
app:icon="@{filesRoot.isEmpty ? @drawable/ic_action_add_white : @drawable/ic_arrow_back}"
|
||||||
app:iconPadding="0dp"
|
app:iconPadding="0dp"
|
||||||
app:iconTint="?attr/colorOnPrimary"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
@ -149,7 +148,6 @@
|
|||||||
android:visibility="@{((tunnels.isEmpty && !isDeleting) || !filesRoot.isEmpty) ? View.GONE : View.VISIBLE}"
|
android:visibility="@{((tunnels.isEmpty && !isDeleting) || !filesRoot.isEmpty) ? View.GONE : View.VISIBLE}"
|
||||||
app:icon="@{isDeleting ? @drawable/ic_arrow_back : @drawable/ic_action_delete}"
|
app:icon="@{isDeleting ? @drawable/ic_arrow_back : @drawable/ic_action_delete}"
|
||||||
app:iconPadding="0dp"
|
app:iconPadding="0dp"
|
||||||
app:iconTint="?attr/colorOnPrimary"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginBottom="0dp"
|
android:layout_marginBottom="0dp"
|
||||||
android:backgroundTint="@color/tv_card_background"
|
|
||||||
android:checkable="true"
|
android:checkable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:contentPadding="8dp">
|
app:contentPadding="8dp">
|
||||||
@ -35,7 +34,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{key}"
|
android:text="@{key}"
|
||||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||||
android:textColor="?attr/colorOnPrimary"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
@ -28,16 +28,18 @@
|
|||||||
type="com.wireguard.android.model.ObservableTunnel" />
|
type="com.wireguard.android.model.ObservableTunnel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.wireguard.android.widget.TvCardView
|
||||||
android:layout_width="225dp"
|
android:layout_width="225dp"
|
||||||
android:layout_height="110dp"
|
android:layout_height="110dp"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginBottom="0dp"
|
android:layout_marginBottom="0dp"
|
||||||
|
android:backgroundTint="@color/tv_list_item_tint"
|
||||||
android:checkable="true"
|
android:checkable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:contentPadding="8dp"
|
app:contentPadding="8dp"
|
||||||
android:backgroundTint="@{(item.state == State.UP && !isDeleting) ? @color/tv_secondary_dark_color : (isDeleting && isFocused) ? @color/tv_card_delete_background : @color/tv_card_background}">
|
app:isDeleting="@{isDeleting}"
|
||||||
|
app:isUp="@{item.state == State.UP}">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -49,7 +51,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{item.name}"
|
android:text="@{item.name}"
|
||||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||||
android:textColor="?attr/colorOnPrimary"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@sample/interface_names.json/names/names/name" />
|
tools:text="@sample/interface_names.json/names/names/name" />
|
||||||
@ -76,6 +77,6 @@
|
|||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.wireguard.android.widget.TvCardView>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -4,4 +4,8 @@
|
|||||||
<attr name="state_multiselected" format="boolean" />
|
<attr name="state_multiselected" format="boolean" />
|
||||||
<attr name="colorMultiselectActiveBackground" format="reference|color" />
|
<attr name="colorMultiselectActiveBackground" format="reference|color" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
<declare-styleable name="TvCardView">
|
||||||
|
<attr name="state_isUp" format="boolean" />
|
||||||
|
<attr name="state_isDeleting" format="boolean" />
|
||||||
|
</declare-styleable>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Various additional API-specific features in values-v*/styles.xml -->
|
<!-- Various additional API-specific features in values-v*/styles.xml -->
|
||||||
<style name="AppTheme" parent="AppThemeBase"/>
|
<style name="AppTheme" parent="AppThemeBase" />
|
||||||
|
|
||||||
<style name="WireGuardTheme.MaterialCardView" parent="Widget.Material3.CardView.Elevated">
|
<style name="WireGuardTheme.MaterialCardView" parent="Widget.Material3.CardView.Elevated">
|
||||||
<item name="cornerRadius">4dp</item>
|
<item name="cornerRadius">4dp</item>
|
||||||
@ -36,4 +36,9 @@
|
|||||||
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
|
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
|
||||||
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
|
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="TvTheme" parent="AppTheme">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="tv_primary_color">#ff212121</color>
|
|
||||||
<color name="tv_secondary_dark_color">#ff0059c1</color>
|
|
||||||
<color name="tv_card_background">@color/tv_primary_color</color>
|
|
||||||
<color name="tv_card_delete_background">#b00020</color>
|
|
||||||
<color name="tv_list_multiselect_background">#ffeeeeee</color>
|
|
||||||
</resources>
|
|
@ -1,31 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<style name="TvTheme" parent="Theme.Material3.DayNight.NoActionBar">
|
|
||||||
<item name="colorPrimary">@color/tv_primary_color</item>
|
|
||||||
<item name="colorOnPrimary">#fffafafa</item>
|
|
||||||
<item name="colorPrimaryDark">@color/tv_primary_color</item>
|
|
||||||
<item name="colorPrimaryVariant">#ff484848</item>
|
|
||||||
<item name="colorSecondary">#ff4285f4</item>
|
|
||||||
<item name="colorOnSecondary">#ff0059c1</item>
|
|
||||||
<item name="colorSurface">@color/tv_primary_color</item>
|
|
||||||
<item name="colorOnSurface">#fffafafa</item>
|
|
||||||
<item name="colorMultiselectActiveBackground">@color/tv_list_multiselect_background</item>
|
|
||||||
<item name="colorControlNormal">#fffafafa</item>
|
|
||||||
<item name="elevationOverlayEnabled">false</item>
|
|
||||||
<item name="android:statusBarColor">@color/tv_primary_color</item>
|
|
||||||
<item name="android:windowBackground">@color/tv_primary_color</item>
|
|
||||||
<item name="alertDialogTheme">@style/TvTheme.Dialog</item>
|
|
||||||
<item name="materialAlertDialogTheme">@style/TvTheme.Dialog</item>
|
|
||||||
<item name="materialCardViewStyle">@style/TvTheme.MaterialCardView</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="TvTheme.Dialog" parent="Theme.Material3.DayNight.Dialog.Alert">
|
|
||||||
<item name="android:windowBackground">?attr/colorSurface</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="TvTheme.MaterialCardView" parent="Widget.Material3.CardView.Elevated">
|
|
||||||
<item name="cornerRadius">4dp</item>
|
|
||||||
<item name="contentPadding">8dp</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
Loading…
Reference in New Issue
Block a user