Skip to content

Commit

Permalink
Added composition locals for true dark and dynamic theme to Adaptable…
Browse files Browse the repository at this point in the history
…MaterialTheme.
  • Loading branch information
rohankhayech committed Sep 18, 2023
1 parent 3c64184 commit ef0c8da
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 28 deletions.
18 changes: 17 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
/*
* Copyright 2023 Rohan Khayech
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Top-level build file where you can add configuration options common to all sub-projects/modules.
group = "com.github.rohankhayech.AndroidUtils"
version = "0.1.0"
version = "0.2.0"

plugins {
id("com.android.application") version "8.1.0" apply false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,69 @@

package com.rohankhayech.android.util.ui.theme

import androidx.compose.foundation.layout.Column
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.rohankhayech.android.util.ui.preview.ColorSwatch
import com.rohankhayech.android.util.ui.preview.DarkPreview
import com.rohankhayech.android.util.ui.preview.ThemePreview

@Composable
private fun PreviewContent() {
Surface(color = MaterialTheme.colors.background) {
Column {
ColorSwatch()
Text("True dark: ${MaterialTheme.isTrueDark}")
Text("Dynamic color: ${MaterialTheme.isDynamicColor}")
}
}
}

@ThemePreview
@Composable
private fun Preview() {
AdaptableMaterialTheme {
ColorSwatch()
PreviewContent()
}
}

@DarkPreview
@Composable
private fun TrueDarkPreview() {
AdaptableMaterialTheme(trueDark = true) {
ColorSwatch()
PreviewContent()
}
}

@ThemePreview
@Composable
private fun DynamicPreview() {
AdaptableMaterialTheme(dynamicColor = true) {
ColorSwatch()
PreviewContent()
}
}

@DarkPreview
@Composable
private fun DynamicTrueDarkPreview() {
AdaptableMaterialTheme(trueDark = true, dynamicColor = true) {
ColorSwatch()
PreviewContent()
}
}

/** Preview of default composition local values. */
@Preview
@Composable
private fun DefaultPreview() {
MaterialTheme {
Surface(color = MaterialTheme.colors.background) {
Column {
Text("True dark: ${MaterialTheme.isTrueDark}")
Text("Dynamic color: ${MaterialTheme.isDynamicColor}")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ import androidx.compose.material.Typography
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.platform.LocalContext

/**
* Material theme that adapts to dark mode,
* with support for true black and dynamic color themes.
*
* It also provides composition locals for the true dark and dynamic color values.
* These can be accessed with the properties [MaterialTheme.isTrueDark] and [MaterialTheme.isDynamicColor] respectively.
* These properties both default to false if not provided.
*
* @param lightColors Colors to use in light mode.
* @param darkColors Colors to use in dark mode.
* @param trueDarkColors Colors to use in dark mode when [trueDark] is set to true.
Expand All @@ -44,6 +50,9 @@ import androidx.compose.ui.platform.LocalContext
* @param dynamicColor Whether to use a dynamic color theme, if available.
* @param content Content to display with this theme.
*
* @see MaterialTheme.isTrueDark
* @see MaterialTheme.isDynamicColor
*
* @author Rohan Khayech
*/
@Composable
Expand All @@ -64,26 +73,62 @@ fun AdaptableMaterialTheme(
// Use dynamic color if dynamicColor is true and version requirement is met.
val useDynamicColor = dynamicColor && Build.VERSION.SDK_INT > Build.VERSION_CODES.S

MaterialTheme(
colors = when {
useDynamicColor && darkTheme && trueDark ->
dynamicTrueDarkColors?.invoke()
?: dynamicTrueDarkColors(LocalContext.current)
useDynamicColor && darkTheme ->
dynamicDarkColors?.invoke()
?: dynamicDarkColors(LocalContext.current)
useDynamicColor ->
dynamicLightColors?.invoke()
?: dynamicLightColors(LocalContext.current)
darkTheme && trueDark ->
trueDarkColors
darkTheme ->
darkColors
else ->
lightColors
},
shapes = shapes,
typography = typography,
content = content
)
}
CompositionLocalProvider(
LocalTrueDarkTheme provides trueDark,
LocalDynamicColor provides useDynamicColor
) {
MaterialTheme(
colors = when {
useDynamicColor && darkTheme && trueDark ->
dynamicTrueDarkColors?.invoke()
?: dynamicTrueDarkColors(LocalContext.current)

useDynamicColor && darkTheme ->
dynamicDarkColors?.invoke()
?: dynamicDarkColors(LocalContext.current)

useDynamicColor ->
dynamicLightColors?.invoke()
?: dynamicLightColors(LocalContext.current)

darkTheme && trueDark ->
trueDarkColors

darkTheme ->
darkColors

else ->
lightColors
},
shapes = shapes,
typography = typography,
content = content
)
}
}

/** Composition local key representing whether the current theme uses true dark theme when dark mode is enabled. */
private val LocalTrueDarkTheme = compositionLocalOf { false }

/**
* Whether the current theme uses true dark theme when dark mode is enabled.
*
* Works in conjunction with the [AdaptableMaterialTheme] composable, and defaults to `false` otherwise.
* @see AdaptableMaterialTheme
*/
@Suppress("UnusedReceiverParameter")
val MaterialTheme.isTrueDark: Boolean
@Composable get() = LocalTrueDarkTheme.current

/** Composition local key representing whether the current theme uses dynamic color theme. */
private val LocalDynamicColor = compositionLocalOf { false }

/**
* Whether the current theme uses dynamic color theme.
*
* Works in conjunction with the [AdaptableMaterialTheme] composable, and defaults to `false` otherwise.
* @see AdaptableMaterialTheme
*/
@Suppress("UnusedReceiverParameter")
val MaterialTheme.isDynamicColor: Boolean
@Composable get() = LocalDynamicColor.current

0 comments on commit ef0c8da

Please sign in to comment.