refactor: tidy up files

This commit is contained in:
FunkyMuse 2023-07-24 15:27:39 +02:00
parent bdd7ea4ed7
commit be721c987c
13 changed files with 287 additions and 227 deletions

View file

@ -18,6 +18,7 @@ android {
compileSdk = project.libs.versions.app.build.compileSDKVersion.get().toInt()
defaultConfig {
applicationId = libs.versions.app.version.appId.get()
minSdk = project.libs.versions.app.build.minimumSDK.get().toInt()
targetSdk = project.libs.versions.app.build.targetSDK.get().toInt()
versionName = project.libs.versions.app.version.versionName.get()

View file

@ -8,7 +8,6 @@ import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.Lifecycle
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.simplemobiletools.calculator.compose.theme.OnLifecycleEvent
fun Context.getActivity(): Activity {
if (this is Activity) return this
@ -21,7 +20,7 @@ fun TransparentSystemBars() {
val systemUiController = rememberSystemUiController()
val isSystemInDarkTheme = isSystemInDarkTheme()
SideEffect {
systemUiController.setSystemBarsColor(Color.Transparent, darkIcons = isSystemInDarkTheme)
systemUiController.setSystemBarsColor(Color.Transparent, darkIcons = !isSystemInDarkTheme)
}
}

View file

@ -0,0 +1,27 @@
package com.simplemobiletools.calculator.compose.extensions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
@Composable
fun OnLifecycleEvent(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
onEvent: (event: Lifecycle.Event) -> Unit
) {
val currentOnEvent by rememberUpdatedState(onEvent)
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
currentOnEvent(event)
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}

View file

@ -23,7 +23,10 @@ import com.simplemobiletools.calculator.compose.settings.SettingsCheckBoxCompone
import com.simplemobiletools.calculator.compose.settings.SettingsGroup
import com.simplemobiletools.calculator.compose.settings.SettingsPreferenceComponent
import com.simplemobiletools.calculator.compose.settings.SettingsTitleTextComponent
import com.simplemobiletools.calculator.compose.theme.*
import com.simplemobiletools.calculator.compose.theme.AppThemeSurface
import com.simplemobiletools.calculator.compose.theme.divider_grey
import com.simplemobiletools.calculator.compose.theme.isNotLitWell
import com.simplemobiletools.calculator.compose.theme.isSurfaceLitWell
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.helpers.isTiramisuPlus
import java.util.Locale

View file

@ -0,0 +1,47 @@
package com.simplemobiletools.calculator.compose.theme
import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.graphics.BitmapFactory
import com.simplemobiletools.calculator.compose.extensions.getActivity
import com.simplemobiletools.calculator.helpers.Config
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.helpers.APP_ICON_IDS
import com.simplemobiletools.commons.helpers.APP_LAUNCHER_NAME
fun Activity.getAppIconIds(): ArrayList<Int> = ArrayList(intent.getIntegerArrayListExtra(APP_ICON_IDS).orEmpty())
fun Activity.getAppLauncherName(): String = intent.getStringExtra(APP_LAUNCHER_NAME).orEmpty()
internal fun updateRecentsAppIcon(baseConfig: Config, context: Context) {
if (baseConfig.isUsingModifiedAppIcon) {
val appIconIDs = context.getAppIconIds()
val currentAppIconColorIndex = baseConfig.getCurrentAppIconColorIndex(context)
if (appIconIDs.size - 1 < currentAppIconColorIndex) {
return
}
val recentsIcon = BitmapFactory.decodeResource(context.resources, appIconIDs[currentAppIconColorIndex])
val title = context.getAppLauncherName()
val color = baseConfig.primaryColor
val description = ActivityManager.TaskDescription(title, recentsIcon, color)
context.getActivity().setTaskDescription(description)
}
}
private fun Config.getCurrentAppIconColorIndex(context: Context): Int {
val appIconColor = appIconColor
context.getAppIconColors().forEachIndexed { index, color ->
if (color == appIconColor) {
return index
}
}
return 0
}
private fun Context.getAppIconColors() = resources.getIntArray(R.array.md_app_icon_colors).toCollection(ArrayList())
private fun Context.getAppIconIds(): List<Int> = getActivity().getAppIconIds()
private fun Context.getAppLauncherName(): String = getActivity().getAppLauncherName()

View file

@ -0,0 +1,41 @@
package com.simplemobiletools.calculator.compose.theme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.lifecycle.Lifecycle
import com.simplemobiletools.calculator.compose.extensions.OnLifecycleEvent
import com.simplemobiletools.calculator.compose.theme.model.Theme.Companion.systemDefaultMaterialYou
@Composable
fun AppThemeSurface(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
val view = LocalView.current
val context = LocalContext.current
val materialYouTheme = systemDefaultMaterialYou()
var currentTheme by remember {
mutableStateOf(
if (view.isInEditMode) materialYouTheme else getTheme(
context = context,
materialYouTheme = materialYouTheme
)
)
}
OnLifecycleEvent { event ->
if (event == Lifecycle.Event.ON_START && !view.isInEditMode) {
currentTheme = getTheme(context = context, materialYouTheme = materialYouTheme)
}
}
Theme(theme = currentTheme) {
Surface(modifier = modifier.fillMaxSize()) {
content()
}
}
}

View file

@ -0,0 +1,9 @@
package com.simplemobiletools.calculator.compose.theme
import androidx.compose.material3.darkColorScheme
internal val darkColorScheme = darkColorScheme(
primary = color_primary,
secondary = color_primary_dark,
tertiary = color_accent,
)

View file

@ -0,0 +1,34 @@
package com.simplemobiletools.calculator.compose.theme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
@get:ReadOnlyComposable
val disabledTextColor @Composable get() = if (isInDarkThemeAndSurfaceIsNotLitWell()) Color.DarkGray else Color.LightGray
@get:ReadOnlyComposable
val textSubTitleColor
@Composable get() = if (isInDarkThemeAndSurfaceIsNotLitWell()) {
Color.White.copy(0.5f)
} else {
Color.Black.copy(
0.5f,
)
}
@Composable
@ReadOnlyComposable
fun preferenceSummaryColor(isEnabled: Boolean) =
if (isEnabled) textSubTitleColor else disabledTextColor
@Composable
@ReadOnlyComposable
fun preferenceTitleColor(isEnabled: Boolean) = if (isEnabled) MaterialTheme.colorScheme.onSurface else disabledTextColor
fun Color.isLitWell(threshold : Float = LUMINANCE_THRESHOLD) = luminance() > threshold
fun Color.isNotLitWell(threshold: Float = LUMINANCE_THRESHOLD) = luminance() < threshold

View file

@ -1,17 +1,13 @@
package com.simplemobiletools.calculator.compose.theme
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import com.simplemobiletools.calculator.compose.theme.model.Theme
import com.simplemobiletools.calculator.extensions.config
import com.simplemobiletools.commons.extensions.isBlackAndWhiteTheme
import com.simplemobiletools.commons.extensions.isWhiteTheme
@Composable
fun getCurrentTheme() = getTheme(LocalContext.current, Theme.systemDefaultMaterialYou())
fun getTheme(context: Context, materialYouTheme: Theme.SystemDefaultMaterialYou): Theme {
val baseConfig = context.config
val primaryColorInt = baseConfig.primaryColor

View file

@ -1,148 +1,24 @@
package com.simplemobiletools.calculator.compose.theme
import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.content.res.Configuration
import android.graphics.BitmapFactory
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.LocalView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.simplemobiletools.calculator.compose.extensions.getActivity
import com.simplemobiletools.calculator.compose.theme.Theme.Companion.systemDefaultMaterialYou
import com.simplemobiletools.calculator.compose.theme.model.Theme
import com.simplemobiletools.calculator.compose.theme.model.Theme.Companion.systemDefaultMaterialYou
import com.simplemobiletools.calculator.extensions.config
import com.simplemobiletools.calculator.helpers.Config
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.helpers.APP_ICON_IDS
import com.simplemobiletools.commons.helpers.APP_LAUNCHER_NAME
private val darkColorScheme = darkColorScheme(
primary = color_primary,
secondary = color_primary_dark,
tertiary = color_accent,
)
@get:ReadOnlyComposable
val disabledTextColor @Composable get() = if (isInDarkThemeAndSurfaceIsNotLitWell()) Color.DarkGray else Color.LightGray
@get:ReadOnlyComposable
val textSubTitleColor
@Composable get() = if (isInDarkThemeAndSurfaceIsNotLitWell()) {
Color.White.copy(0.5f)
} else {
Color.Black.copy(
0.5f,
)
}
@Composable
@ReadOnlyComposable
fun preferenceSummaryColor(isEnabled: Boolean) =
if (isEnabled) textSubTitleColor else disabledTextColor
@Composable
@ReadOnlyComposable
fun preferenceTitleColor(isEnabled: Boolean) = if (isEnabled) MaterialTheme.colorScheme.onSurface else disabledTextColor
interface CommonTheme {
val primaryColorInt: Int
val backgroundColorInt: Int
val appIconColorInt: Int
val textColorInt: Int
val primaryColor get() = Color(primaryColorInt)
val backgroundColor get() = Color(backgroundColorInt)
val appIconColor get() = Color(appIconColorInt)
val textColor get() = Color(textColorInt)
}
@Stable
sealed class Theme : CommonTheme {
data class SystemDefaultMaterialYou(
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class White(
val accentColor: Int,
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class Dark(
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class BlackAndWhite(
val accentColor: Int,
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class Custom(
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
companion object {
@Composable
fun systemDefaultMaterialYou() = SystemDefaultMaterialYou(
appIconColorInt = LocalContext.current.config.appIconColor,
primaryColorInt = LocalContext.current.config.primaryColor,
backgroundColorInt = LocalContext.current.config.backgroundColor,
textColorInt = (if (isInDarkThemeAndSurfaceIsNotLitWell()) Color.White else Color.Black).toArgb()
)
}
}
@Composable
@ReadOnlyComposable
fun isInDarkThemeAndSurfaceIsNotLitWell() = isSystemInDarkTheme() || isSurfaceNotLitWell()
private const val LUMINANCE_THRESHOLD = 0.5f
@Composable
@ReadOnlyComposable
fun isSurfaceNotLitWell() = MaterialTheme.colorScheme.surface.luminance() < LUMINANCE_THRESHOLD
@Composable
@ReadOnlyComposable
fun isSurfaceLitWell() = MaterialTheme.colorScheme.surface.luminance() > LUMINANCE_THRESHOLD
fun Color.isLitWell() = luminance() > LUMINANCE_THRESHOLD
fun Color.isNotLitWell() = luminance() < LUMINANCE_THRESHOLD
@Composable
private fun Theme(
internal fun Theme(
theme: Theme = systemDefaultMaterialYou(),
content: @Composable () -> Unit,
) {
@ -199,88 +75,3 @@ private fun Theme(
)
}
private fun Context.getAppIconIds(): List<Int> = getActivity().getAppIconIds()
fun Activity.getAppIconIds(): ArrayList<Int> = ArrayList(intent.getIntegerArrayListExtra(APP_ICON_IDS).orEmpty())
private fun Context.getAppLauncherName(): String = getActivity().getAppLauncherName()
fun Activity.getAppLauncherName(): String = intent.getStringExtra(APP_LAUNCHER_NAME).orEmpty()
private fun updateRecentsAppIcon(baseConfig: Config, context: Context) {
if (baseConfig.isUsingModifiedAppIcon) {
val appIconIDs = context.getAppIconIds()
val currentAppIconColorIndex = baseConfig.getCurrentAppIconColorIndex(context)
if (appIconIDs.size - 1 < currentAppIconColorIndex) {
return
}
val recentsIcon = BitmapFactory.decodeResource(context.resources, appIconIDs[currentAppIconColorIndex])
val title = context.getAppLauncherName()
val color = baseConfig.primaryColor
val description = ActivityManager.TaskDescription(title, recentsIcon, color)
context.getActivity().setTaskDescription(description)
}
}
private fun Config.getCurrentAppIconColorIndex(context: Context): Int {
val appIconColor = appIconColor
context.getAppIconColors().forEachIndexed { index, color ->
if (color == appIconColor) {
return index
}
}
return 0
}
private fun Context.getAppIconColors() = resources.getIntArray(R.array.md_app_icon_colors).toCollection(ArrayList())
@Composable
fun AppThemeSurface(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
val view = LocalView.current
val context = LocalContext.current
val materialYouTheme = systemDefaultMaterialYou()
var currentTheme by remember {
mutableStateOf(
if (view.isInEditMode) materialYouTheme else getTheme(
context = context,
materialYouTheme = materialYouTheme
)
)
}
OnLifecycleEvent { event ->
if (event == Lifecycle.Event.ON_START && !view.isInEditMode) {
currentTheme = getTheme(context = context, materialYouTheme = materialYouTheme)
}
}
Theme(theme = currentTheme) {
Surface(modifier = modifier.fillMaxSize()) {
content()
}
}
}
internal fun Context.isDarkMode(): Boolean {
val darkModeFlag = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
return darkModeFlag == Configuration.UI_MODE_NIGHT_YES
}
@Composable
fun OnLifecycleEvent(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
onEvent: (event: Lifecycle.Event) -> Unit
) {
val currentOnEvent by rememberUpdatedState(onEvent)
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
currentOnEvent(event)
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}

View file

@ -0,0 +1,34 @@
package com.simplemobiletools.calculator.compose.theme
import android.content.Context
import android.content.res.Configuration
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.platform.LocalContext
import com.simplemobiletools.calculator.compose.theme.model.Theme.Companion.systemDefaultMaterialYou
@Composable
fun getCurrentTheme() = getTheme(LocalContext.current, systemDefaultMaterialYou())
@Composable
@ReadOnlyComposable
fun isInDarkThemeAndSurfaceIsNotLitWell() = isSystemInDarkTheme() || isSurfaceNotLitWell()
internal const val LUMINANCE_THRESHOLD = 0.5f
@Composable
@ReadOnlyComposable
fun isSurfaceNotLitWell(threshold: Float = LUMINANCE_THRESHOLD) = MaterialTheme.colorScheme.surface.luminance() < threshold
@Composable
@ReadOnlyComposable
fun isSurfaceLitWell(threshold: Float = LUMINANCE_THRESHOLD) = MaterialTheme.colorScheme.surface.luminance() > threshold
fun Context.isDarkMode(): Boolean {
val darkModeFlag = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
return darkModeFlag == Configuration.UI_MODE_NIGHT_YES
}

View file

@ -0,0 +1,18 @@
package com.simplemobiletools.calculator.compose.theme.model
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
@Immutable
interface CommonTheme {
val primaryColorInt: Int
val backgroundColorInt: Int
val appIconColorInt: Int
val textColorInt: Int
val primaryColor get() = Color(primaryColorInt)
val backgroundColor get() = Color(backgroundColorInt)
val appIconColor get() = Color(appIconColorInt)
val textColor get() = Color(textColorInt)
}

View file

@ -0,0 +1,60 @@
package com.simplemobiletools.calculator.compose.theme.model
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import com.simplemobiletools.calculator.compose.theme.isInDarkThemeAndSurfaceIsNotLitWell
import com.simplemobiletools.calculator.extensions.config
@Stable
sealed class Theme : CommonTheme {
data class SystemDefaultMaterialYou(
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class White(
val accentColor: Int,
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class Dark(
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class BlackAndWhite(
val accentColor: Int,
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
data class Custom(
override val primaryColorInt: Int,
override val backgroundColorInt: Int,
override val appIconColorInt: Int,
override val textColorInt: Int
) : Theme()
companion object {
@Composable
fun systemDefaultMaterialYou() = SystemDefaultMaterialYou(
appIconColorInt = LocalContext.current.config.appIconColor,
primaryColorInt = LocalContext.current.config.primaryColor,
backgroundColorInt = LocalContext.current.config.backgroundColor,
textColorInt = (if (isInDarkThemeAndSurfaceIsNotLitWell()) Color.White else Color.Black).toArgb()
)
}
}