Add theming system

Standardize theming across the app into ThemeUtils.
This commit is contained in:
OxygenCobalt 2020-09-01 07:37:49 -06:00
parent d5e6b813a9
commit 8f850f2288
13 changed files with 171 additions and 32 deletions

View file

@ -10,7 +10,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/BaseTheme"> android:theme="@style/Theme.Base">
<activity android:name=".MainActivity"> <activity android:name=".MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View file

@ -1,16 +1,27 @@
package org.oxycblt.auxio package org.oxycblt.auxio
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.util.AttributeSet
import android.util.Log import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import org.oxycblt.auxio.theme.accent
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
setTheme(accent.second)
return super.onCreateView(name, context, attrs)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
Log.d(this::class.simpleName, "Activity Created.") Log.d(this::class.simpleName, "Activity Created.")
} }

View file

@ -15,8 +15,9 @@ import com.google.android.material.tabs.TabLayoutMediator
import org.oxycblt.auxio.databinding.FragmentMainBinding import org.oxycblt.auxio.databinding.FragmentMainBinding
import org.oxycblt.auxio.library.LibraryFragment import org.oxycblt.auxio.library.LibraryFragment
import org.oxycblt.auxio.songs.SongsFragment import org.oxycblt.auxio.songs.SongsFragment
import org.oxycblt.auxio.theme.getAccentTransparency import org.oxycblt.auxio.theme.accent
import org.oxycblt.auxio.theme.getDeselectedTransparency import org.oxycblt.auxio.theme.getInactiveAlpha
import org.oxycblt.auxio.theme.getTransparentAccent
import org.oxycblt.auxio.theme.toColor import org.oxycblt.auxio.theme.toColor
class MainFragment : Fragment() { class MainFragment : Fragment() {
@ -27,12 +28,14 @@ class MainFragment : Fragment() {
private val songsFragment: SongsFragment by lazy { SongsFragment() } private val songsFragment: SongsFragment by lazy { SongsFragment() }
private val colorSelected: Int by lazy { private val colorSelected: Int by lazy {
R.color.blue.toColor(requireContext()) accent.first.toColor(requireContext())
} }
private val colorDeselected: Int by lazy { private val colorDeselected: Int by lazy {
getAccentTransparency( getTransparentAccent(
requireContext(), R.color.blue, getDeselectedTransparency(R.color.blue) requireContext(),
accent.first,
getInactiveAlpha(accent.first)
) )
} }
@ -83,10 +86,6 @@ class MainFragment : Fragment() {
} }
) )
binding.tabs.getTabAt(
binding.viewPager.offscreenPageLimit
)
Log.d(this::class.simpleName, "Fragment Created.") Log.d(this::class.simpleName, "Fragment Created.")
return binding.root return binding.root

View file

@ -4,8 +4,8 @@ import android.graphics.drawable.ColorDrawable
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.theme.getAccentTransparency import org.oxycblt.auxio.theme.getDayNightAlpha
import org.oxycblt.auxio.theme.getDayNightTransparency import org.oxycblt.auxio.theme.getTransparentAccent
// Apply a custom vertical divider // Apply a custom vertical divider
fun RecyclerView.applyDivider() { fun RecyclerView.applyDivider() {
@ -16,8 +16,8 @@ fun RecyclerView.applyDivider() {
div.setDrawable( div.setDrawable(
ColorDrawable( ColorDrawable(
getAccentTransparency( getTransparentAccent(
context, R.color.divider_color, getDayNightTransparency() context, R.color.divider_color, getDayNightAlpha()
) )
) )
) )

View file

@ -6,18 +6,43 @@ import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
fun getDayNightTransparency(): Int { // Pairs of the base accent and its theme
private val ACCENTS = listOf(
Pair(R.color.red, R.style.Theme_Red),
Pair(R.color.pink, R.style.Theme_Pink),
Pair(R.color.purple, R.style.Theme_Purple),
Pair(R.color.deep_purple, R.style.Theme_DeepPurple),
Pair(R.color.indigo, R.style.Theme_Indigo),
Pair(R.color.blue, R.style.Theme_Blue),
Pair(R.color.light_blue, R.style.Theme_Blue),
Pair(R.color.cyan, R.style.Theme_Cyan),
Pair(R.color.teal, R.style.Theme_Teal),
Pair(R.color.green, R.style.Theme_Green),
Pair(R.color.light_green, R.style.Theme_LightGreen),
Pair(R.color.lime, R.style.Theme_Lime),
Pair(R.color.yellow, R.style.Theme_Yellow),
Pair(R.color.amber, R.style.Theme_Amber),
Pair(R.color.orange, R.style.Theme_Orange),
Pair(R.color.deep_orange, R.style.Theme_DeepOrange),
Pair(R.color.brown, R.style.Theme_Brown),
Pair(R.color.grey, R.style.Theme_Gray),
Pair(R.color.blue_grey, R.style.Theme_BlueGrey)
)
val accent = ACCENTS[5]
fun getDayNightAlpha(): Int {
val isDark = AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES val isDark = AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES
// Depending on the theme use a different opacity for the divider // Depending on the theme use a different opacity for the divider
return if (isDark) 45 else 85 return if (isDark) 45 else 85
} }
fun getDeselectedTransparency(color: Int): Int { fun getInactiveAlpha(color: Int): Int {
return if (color == R.color.yellow) 100 else 150 return if (color == R.color.yellow) 100 else 150
} }
fun getAccentTransparency(context: Context, color: Int, alpha: Int): Int { fun getTransparentAccent(context: Context, color: Int, alpha: Int): Int {
return ColorUtils.setAlphaComponent( return ColorUtils.setAlphaComponent(
ContextCompat.getColor(context, color), ContextCompat.getColor(context, color),
alpha alpha
@ -28,6 +53,7 @@ fun Int.toColor(context: Context): Int {
return try { return try {
ContextCompat.getColor(context, this) ContextCompat.getColor(context, this)
} catch (e: Exception) { } catch (e: Exception) {
ContextCompat.getColor(context, android.R.color.white) // Default to the emergency color [Black] if the loading fails.
ContextCompat.getColor(context, android.R.color.black)
} }
} }

View file

@ -8,7 +8,7 @@
<shape android:shape="rectangle"> <shape android:shape="rectangle">
<solid android:color="@android:color/white" /> <solid android:color="@android:color/white" />
<corners android:radius="4dp" /> <corners android:radius="4dp" />
<size android:height="2dp" /> <size android:height="3dp" />
</shape> </shape>
</item> </item>
</layer-list> </layer-list>

View file

@ -14,8 +14,7 @@
android:layout_height="?android:attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/windowBackground" android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal" android:elevation="@dimen/elevation_normal"
app:titleTextAppearance="@style/ToolbarStyle" app:titleTextAppearance="@style/TextAppearance.Toolbar.Bold"
app:layout_constraintTop_toTopOf="parent"
app:title="@string/title_library_fragment" /> app:title="@string/title_library_fragment" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView

View file

@ -20,7 +20,7 @@
android:id="@+id/loading_bar" android:id="@+id/loading_bar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:indeterminateTint="@color/blue" android:indeterminateTint="?attr/colorPrimary"
android:indeterminateTintMode="src_in" android:indeterminateTintMode="src_in"
android:paddingBottom="@dimen/padding_tiny" android:paddingBottom="@dimen/padding_tiny"
app:layout_constraintBottom_toTopOf="@+id/error_text" app:layout_constraintBottom_toTopOf="@+id/error_text"
@ -28,7 +28,8 @@
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" /> app:layout_constraintVertical_chainStyle="packed"
tools:indeterminateTint="@color/blue" />
<TextView <TextView
android:id="@+id/error_text" android:id="@+id/error_text"
@ -53,13 +54,14 @@
android:text="@string/label_retry" android:text="@string/label_retry"
android:visibility="gone" android:visibility="gone"
android:fontFamily="@font/inter_semibold" android:fontFamily="@font/inter_semibold"
android:textColor="@color/blue" android:textColor="?attr/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/error_text" app:layout_constraintTop_toBottomOf="@+id/error_text"
tools:visibility="visible" /> tools:visibility="visible"
tools:textColor="@color/blue" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout> </layout>

View file

@ -20,6 +20,7 @@
android:layout_height="@dimen/tab_menu_size" android:layout_height="@dimen/tab_menu_size"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:background="?android:attr/windowBackground" android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal"
app:tabIndicatorColor="?android:attr/colorPrimary" app:tabIndicatorColor="?android:attr/colorPrimary"
app:tabGravity="fill" app:tabGravity="fill"
app:tabMode="fixed" app:tabMode="fixed"

View file

@ -14,7 +14,7 @@
android:layout_height="?android:attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/windowBackground" android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal" android:elevation="@dimen/elevation_normal"
app:titleTextAppearance="@style/ToolbarStyle" app:titleTextAppearance="@style/TextAppearance.Toolbar.Bold"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:title="@string/title_all_songs" /> app:title="@string/title_all_songs" />

View file

@ -10,7 +10,7 @@
<dimen name="cover_size_compact">44dp</dimen> <dimen name="cover_size_compact">44dp</dimen>
<dimen name="cover_size_normal">56dp</dimen> <dimen name="cover_size_normal">56dp</dimen>
<dimen name="tab_menu_size">38dp</dimen> <dimen name="tab_menu_size">40dp</dimen>
<dimen name="elevation_normal">4dp</dimen> <dimen name="elevation_normal">4dp</dimen>
</resources> </resources>

View file

@ -1,15 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!-- Base theme --> <!-- Base theme -->
<style name="BaseTheme" parent="Theme.AppCompat.DayNight.NoActionBar"> <style name="Theme.Base" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:colorPrimary">@color/blue</item>
<item name="android:windowBackground">@color/background</item> <item name="android:windowBackground">@color/background</item>
<item name="android:statusBarColor">@android:color/black</item> <item name="android:statusBarColor">@android:color/black</item>
<item name="android:fontFamily">@font/inter</item> <item name="android:fontFamily">@font/inter</item>
</style> </style>
<style name="ToolbarStyle" parent="TextAppearance.Widget.AppCompat.Toolbar.Title"> <style name="TextAppearance.Toolbar.Bold" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:fontFamily">@font/inter_black</item> <item name="android:fontFamily">@font/inter_black</item>
<item name="android:textColor">@color/blue</item> <item name="android:textColor">?android:attr/colorPrimary</item>
</style> </style>
</resources> </resources>

View file

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Red" parent="Theme.Base">
<item name="colorPrimary">@color/red</item>
<item name="colorSecondary">@color/red</item>
</style>
<style name="Theme.Pink" parent="Theme.Base">
<item name="colorPrimary">@color/pink</item>
<item name="colorSecondary">@color/pink</item>
</style>
<style name="Theme.Purple" parent="Theme.Base">
<item name="colorPrimary">@color/purple</item>
<item name="colorSecondary">@color/purple</item>
</style>
<style name="Theme.DeepPurple" parent="Theme.Base">
<item name="colorPrimary">@color/deep_purple</item>
<item name="colorSecondary">@color/deep_purple</item>
</style>
<style name="Theme.Indigo" parent="Theme.Base">
<item name="colorPrimary">@color/indigo</item>
<item name="colorSecondary">@color/indigo</item>
</style>
<style name="Theme.Blue" parent="Theme.Base">
<item name="colorPrimary">@color/blue</item>
<item name="colorSecondary">@color/blue</item>
</style>
<style name="Theme.LightBlue" parent="Theme.Base">
<item name="colorPrimary">@color/light_blue</item>
<item name="colorSecondary">@color/light_blue</item>
</style>
<style name="Theme.Cyan" parent="Theme.Base">
<item name="colorPrimary">@color/cyan</item>
<item name="colorSecondary">@color/cyan</item>
</style>
<style name="Theme.Teal" parent="Theme.Base">
<item name="colorPrimary">@color/teal</item>
<item name="colorSecondary">@color/teal</item>
</style>
<style name="Theme.Green" parent="Theme.Base">
<item name="colorPrimary">@color/green</item>
<item name="colorSecondary">@color/green</item>
</style>
<style name="Theme.LightGreen" parent="Theme.Base">
<item name="colorPrimary">@color/light_green</item>
<item name="colorSecondary">@color/light_green</item>
</style>
<style name="Theme.Lime" parent="Theme.Base">
<item name="colorPrimary">@color/lime</item>
<item name="colorSecondary">@color/lime</item>
</style>
<style name="Theme.Yellow" parent="Theme.Base">
<item name="colorPrimary">@color/yellow</item>
<item name="colorSecondary">@color/yellow</item>
</style>
<style name="Theme.Amber" parent="Theme.Base">
<item name="colorPrimary">@color/amber</item>
<item name="colorSecondary">@color/amber</item>
</style>
<style name="Theme.Orange" parent="Theme.Base">
<item name="colorPrimary">@color/orange</item>
<item name="colorSecondary">@color/orange</item>
</style>
<style name="Theme.DeepOrange" parent="Theme.Base">
<item name="colorPrimary">@color/deep_orange</item>
<item name="colorSecondary">@color/deep_orange</item>
</style>
<style name="Theme.Brown" parent="Theme.Base">
<item name="colorPrimary">@color/brown</item>
<item name="colorSecondary">@color/brown</item>
</style>
<style name="Theme.Gray" parent="Theme.Base">
<item name="colorPrimary">@color/grey</item>
<item name="colorSecondary">@color/grey</item>
</style>
<style name="Theme.BlueGrey" parent="Theme.Base">
<item name="colorPrimary">@color/blue_grey</item>
<item name="colorSecondary">@color/blue_grey</item>
</style>
</resources>