Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Custom Theme #1473

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open

Conversation

WoLeo-Z
Copy link
Contributor

@WoLeo-Z WoLeo-Z commented Jan 9, 2025

#1450

Discussion needed:

  1. SettingsPage APPEARANCE 应该被重命名为 UISETTINGSAPPEARANCE 应该被用作主题页。现在用的是 THEME
  2. 设置 - 界面 里的选项太杂乱,有些应该放到 “杂项” 里面。
  3. AniApp.android.kt (现在是 AppTheme.android.kt) 的设置系统栏样式的代码有什么作用?MainActivity 中已经有了。删除的话可以合并三个平台的 AniTheme 简洁一点
  4. 有没有考虑 Windows 系统强调色。不需要的话就把 desktop 和 ios 合并到 skiko
  5. ThemePreference 的调色板显示组件。

Help needed:

  1. 我代码写得很烂
  2. ProvideCompositionLocalsForPreview 里如何正确引用我的 themeSettings

Known Problems:

  1. 点击 ColorButton 切换主题色时,布局短暂偏移

@WoLeo-Z WoLeo-Z marked this pull request as ready for review January 9, 2025 12:59
@Him188 Him188 added the s: ui 子系统: UI label Jan 9, 2025
@Him188 Him188 added this to the 4.4.0 milestone Jan 9, 2025
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有没有设置页效果截图? 所有涉及的页面

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Light Dark
image image
image image

image

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认是什么颜色?仍然是 M3 紫色吗,我觉得非必要不修改默认色

data class ThemeSettings(
val darkMode: DarkMode = DarkMode.AUTO,
val useDynamicTheme: Boolean = false, // default "true" on Android && Build.VERSION.SDK_INT >= 31
val isAmoled: Boolean = false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这听起来不对吧, amoled 是设备自己的属性, 应当实时检测, 不是设置. 如果这个的作用是让背景颜色为纯黑, 那就应当用直接的名字例如 useBlackBackgroundColor

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

更深层次的原因是,设备是否是 oled 屏和是否使用纯黑背景不是强制绑定的关系,如果我的设备不是 oled 屏但我也想用纯黑背景,那 isAmoled 这个参数名字就不能表示正确的意义

Copy link
Contributor Author

@WoLeo-Z WoLeo-Z Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. StageGuard 说得对。
  2. 我这个名字取得不好。改成 useTrueBlackTheme
  3. 推荐在 AMOLED 设备上使用纯黑背景。
  4. 这玩意对于大多数人没用。纯黑背景对 AMOLED 看起来只是省电。视觉效果肯定是有背景色好看。

综上废弃了。懒得弄,以后再说。
定义这个完全只是因为 rememberDynamicColorScheme 必须传入这个参数
我设置页没放 Switch

@Immutable
data class ThemeSettings(
val darkMode: DarkMode = DarkMode.AUTO,
val useDynamicTheme: Boolean = false, // default "true" on Android && Build.VERSION.SDK_INT >= 31
Copy link
Member

@Him188 Him188 Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注释与实际默认值不符. 我觉得可以考虑默认 true

@StageGuard

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

必须默认 false

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个设置放在欢迎页里就行了
不过我觉得可以考虑默认 true。优先使用用户系统 Monet 颜色。但是需要判断 on Android && Build.VERSION.SDK_INT >= 31。dynamicThemeSupported

@@ -122,14 +120,15 @@ fun ProvideCompositionLocalsForPreview(
override val lifecycle: Lifecycle get() = TestGlobalLifecycle
}
},
// TODO: LocalThemeSettings provides themeSettings,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要实现这个, 否则破坏所有 preview

@Him188
Copy link
Member

Him188 commented Jan 9, 2025

回答 discussions

  1. ok
  2. 确实, 但是这个 PR 可以不用改
  3. Application 里的是为了实现启动时读配置之前的流畅效果; composable 里的才是真正根据设置的深色/浅色设置状态栏.
  4. 可以做, 这个 PR 里可以不需要做. 就先这样吧, 重复量不多.
  5. https://github.com/skydoves/colorpicker-compose 看起来值得一试

// Set statusBarStyle & navigationBarStyle
val activity = LocalContext.current.findActivity() as? ComponentActivity
if (activity != null) {
DisposableEffect(activity, isDark) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里有必要吗? MainActivity#onCreate 里已经有了,如果去掉没有影响那就去掉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我也提到了(Discussion needed 3),我觉得可以去掉。你们本来也是有这段代码的。

Him188:

3. Application 里的是为了实现启动时读配置之前的流畅效果; composable 里的才是真正根据设置的深色/浅色设置状态栏.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有必要

@@ -252,3 +261,7 @@ data class NavigationMotionScheme(
val LocalNavigationMotionScheme = compositionLocalOf<NavigationMotionScheme> {
error("No LocalNavigationMotionScheme provided")
}

val LocalThemeSettings = compositionLocalOf<ThemeSettings> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前这个 provider 看起来有很大的问题,会导致所有使用 aniColorTheme 的地方直接强制依赖 LocalThemeSettings,而 ThemeSettings 是数据层的数据类,最终会导致 ui-foundation 模块又增加了对 app-data 模块的耦合程度。
实际上 ui-foundation 模块不应该有对 app-data 的依赖,未来也会考虑去掉这个,所以目前请不要增加耦合度。

以下为去掉 LocalThemeSettings 的一种思路

  • 把上面的 aniColorThemeAniTheme 使用的 ThemeSettings 属性直接作为参数传递给 composable,不用担心参数过多
@Composable
expect fun aniColorTheme(
    seedColor: Color,
    useDynamicScheme: Boolean,
    isAmoled: Boolean,
    isDark: Boolean = isSystemInDarkTheme()
): ColorScheme
  • 查找业务 UI 中所有强制指定亮暗色的地方,例如 MaterialTheme(aniColorTheme(isDark = true)),改为 AniTheme(isDark = true),避免直接在业务中使用 aniColorTheme,而是使用 AniTheme
  • 去掉 LocalThemeSettings

Copy link
Contributor Author

@WoLeo-Z WoLeo-Z Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

把上面的 aniColorTheme 和 AniTheme 使用的 ThemeSettings 属性直接作为参数传递给 composable

抱歉没理解这句是什么意思

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

把上面的 aniColorTheme 和 AniTheme 使用的 ThemeSettings 属性直接作为参数传递给 composable

抱歉没理解这句是什么意思

我给了代码示例

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我想问,具体怎么把 ThemeSettings 传递给 composable

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

具体怎么把 ThemeSettings 传递给 composable

  1. 把 AniTheme 里的 DisposableEffect 拿到外面, 例如 @Composable fun SystemBarColorEffect(isDark).

  2. AniTheme 增加参数 isDark: Boolean.
    AniApp 里有 AniAppViewModel, 可以读配置获取 ThemeSettings. 将根据设置判断是否采用 dark 的逻辑挪到 AniApp 里.

  3. aniColorTheme 改成这个结构, 所有参数都直接由函数传入, 不依赖 ThemeSettings.

@Composable
expect fun aniColorTheme(
    seedColor: Color,
    useDynamicScheme: Boolean,
    isAmoled: Boolean,
    isDark: Boolean = isSystemInDarkTheme()
): ColorScheme

最终在 AniApp 的以下地方实现默认主题.

MaterialTheme(
overrideColorTheme ?: currentPlatformColorTheme(theme.darkMode, theme.dynamicTheme),
) {

例如改成:

val isDark = ...

SystemBarColorEffect(isDark)
AniTheme(isDark) {
    ....
}

对于那些覆盖主题颜色为深色/浅色的地方, 使用 AniTheme(isDark = true) { }

@StageGuard
Copy link
Member

S50110-12452842_me him188 ani debug2

显示有问题,如果没办法解决就换成 FlowRow 或者 LazyRow

@WoLeo-Z
Copy link
Contributor Author

WoLeo-Z commented Jan 10, 2025

显示有问题,如果没办法解决就换成 FlowRow 或者 LazyRow

复现方法?

@WoLeo-Z WoLeo-Z force-pushed the feature/custom-theme branch from 4585c93 to 1012ab3 Compare January 10, 2025 08:22
@StageGuard
Copy link
Member

显示有问题,如果没办法解决就换成 FlowRow 或者 LazyRow

复现方法?

我 100% 复现,你可以在 desktop 模拟更窄的屏幕试试。看你上面的图可以显示完整的 4 个按钮,如果屏幕不够宽或者 DPI 低而没办法显示可能就会有这个问题

@WoLeo-Z
Copy link
Contributor Author

WoLeo-Z commented Jan 10, 2025

显示有问题,如果没办法解决就换成 FlowRow 或者 LazyRow

复现方法?

我 100% 复现,你可以在 desktop 模拟更窄的屏幕试试。看你上面的图可以显示完整的 4 个按钮,如果屏幕不够宽或者 DPI 低而没办法显示可能就会有这个问题

成功复现。用 FlowRow 了。谢谢

@Him188
Copy link
Member

Him188 commented Jan 10, 2025

好了之后 request review 我

@WoLeo-Z WoLeo-Z requested a review from Him188 January 10, 2025 12:05
@WoLeo-Z WoLeo-Z force-pushed the feature/custom-theme branch from 1b8020e to 46d2b70 Compare January 10, 2025 12:07
@WoLeo-Z WoLeo-Z force-pushed the feature/custom-theme branch from 46d2b70 to cd64c01 Compare January 10, 2025 12:09
@Him188
Copy link
Member

Him188 commented Jan 10, 2025

ci failed

你可以本地跑 ./gradlew check 测试

@Him188
Copy link
Member

Him188 commented Jan 10, 2025

请尽量避免 force push

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
s: ui 子系统: UI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants