Skip to content

feat: add the custom theme #1234

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

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 66 additions & 5 deletions lib/app/view/desktop_musicpod_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import 'package:yaru/yaru.dart';
import '../../app_config.dart';
import '../../l10n/l10n.dart';
import '../../settings/settings_model.dart';
import '../../common/view/gradient_background.dart';

import 'back_button_wrapper.dart';
import 'desktop_home_page.dart';

Expand All @@ -33,15 +35,63 @@ class DesktopMusicPodApp extends StatelessWidget with WatchItMixin {
final color = accent ?? const Color(0xFFed3c63);
final phoenix = phoenixTheme(color: color);

// 读取自定义主题设置
final isCustomTheme = themeIndex == 3; // 索引3表示自定义主题
final customColors =
watchPropertyValue((SettingsModel m) => m.customThemeColors);
final useGradient =
watchPropertyValue((SettingsModel m) => m.useGradientTheme);

// 创建自定义主题
ThemeData? customLightTheme;
if (isCustomTheme && customColors.isNotEmpty) {
final primaryColor = customColors.first;

// 创建更明显的自定义主题
customLightTheme = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: primaryColor,
brightness: Brightness.light,
// 使用更轻的背景色以便渐变更明显
surface: Colors.white,
surfaceContainerHighest: Colors.white.withValues(alpha: 230),
),
// 自定义组件样式
appBarTheme: AppBarTheme(
backgroundColor: useGradient && customColors.length > 1
? customColors.first.withValues(alpha: 204)
: primaryColor.withValues(alpha: 204),
elevation: 0,
),
scaffoldBackgroundColor: Colors.white, // 设置为白色让渐变更明显
cardTheme: CardTheme(
color: Colors.white,
elevation: 4,
shadowColor: primaryColor.withValues(alpha: 77),
),
// 设置按钮颜色
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
),
),
);
}

// 创建应用实例
return MaterialApp(
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.values[themeIndex],
themeMode: ThemeMode.values[themeIndex < 3 ? themeIndex : 0],
highContrastTheme: highContrastTheme,
highContrastDarkTheme: highContrastDarkTheme,
theme: lightTheme ??
(AppConfig.yaruStyled
? createYaruLightTheme(primaryColor: color)
: phoenix.lightTheme),
theme: isCustomTheme
? customLightTheme
: (lightTheme ??
(AppConfig.yaruStyled
? createYaruLightTheme(primaryColor: color)
: phoenix.lightTheme)),
darkTheme: darkTheme ??
(AppConfig.yaruStyled
? createYaruDarkTheme(primaryColor: color)
Expand All @@ -59,6 +109,17 @@ class DesktopMusicPodApp extends StatelessWidget with WatchItMixin {
PointerDeviceKind.trackpad,
},
),
builder: (context, child) {
// 如果是自定义主题且启用了渐变,则应用渐变效果
if (isCustomTheme && useGradient && customColors.length > 1) {
return GradientAppWrapper(
colors: customColors,
opacity: 0.35, // 增加透明度使渐变更明显
child: child!,
);
}
return child!;
},
);
}
}
93 changes: 93 additions & 0 deletions lib/common/view/custom_gradient_scaffold.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:watch_it/watch_it.dart';

import '../../settings/settings_model.dart';
import 'gradient_background.dart';

/// 自定义带渐变效果的Scaffold
///
/// 此组件会根据用户的自定义主题设置,自动应用渐变效果
class CustomGradientScaffold extends StatelessWidget with WatchItMixin {
/// 创建一个可能带有渐变效果的Scaffold
const CustomGradientScaffold({
super.key,
required this.body,
this.appBar,
this.floatingActionButton,
this.drawer,
this.endDrawer,
this.bottomNavigationBar,
});

/// 页面内容
final Widget body;

/// 应用栏
final PreferredSizeWidget? appBar;

/// 浮动操作按钮
final Widget? floatingActionButton;

/// 抽屉菜单
final Widget? drawer;

/// 右侧抽屉
final Widget? endDrawer;

/// 底部导航栏
final Widget? bottomNavigationBar;

@override
Widget build(BuildContext context) {
final themeIndex = watchPropertyValue((SettingsModel m) => m.themeIndex);
final isCustomTheme = themeIndex == 3; // 索引3表示自定义主题

// 如果不是自定义主题,直接使用普通Scaffold
if (!isCustomTheme) {
return Scaffold(
appBar: appBar,
body: body,
floatingActionButton: floatingActionButton,
drawer: drawer,
endDrawer: endDrawer,
bottomNavigationBar: bottomNavigationBar,
);
}

// 获取自定义主题设置
final customColors =
watchPropertyValue((SettingsModel m) => m.customThemeColors);
final useGradient =
watchPropertyValue((SettingsModel m) => m.useGradientTheme);

// 如果自定义主题没有启用渐变效果或颜色不足,使用普通Scaffold
if (!useGradient || customColors.length < 2) {
return Scaffold(
appBar: appBar,
// 单色背景时也添加微弱的颜色
backgroundColor: customColors.isNotEmpty
? customColors.first.withValues(
alpha: 13,
) // 0.05 * 255 = 13,使用 withValues 替代 withOpacity
: null,
body: body,
floatingActionButton: floatingActionButton,
drawer: drawer,
endDrawer: endDrawer,
bottomNavigationBar: bottomNavigationBar,
);
}

// 使用带渐变效果的Scaffold
return GradientScaffold(
colors: customColors,
appBar: appBar,
body: body,
floatingActionButton: floatingActionButton,
drawer: drawer,
endDrawer: endDrawer,
bottomNavigationBar: bottomNavigationBar,
opacity: 0.12,
);
}
}
205 changes: 205 additions & 0 deletions lib/common/view/gradient_background.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import 'package:flutter/material.dart';

/// 渐变背景组件
///
/// 为应用添加渐变背景效果,可应用于任何组件
class GradientBackground extends StatelessWidget {
/// 创建一个渐变背景
///
/// [colors] 渐变使用的颜色列表,至少需要2种颜色
/// [child] 子组件
/// [begin] 渐变开始位置
/// [end] 渐变结束位置
/// [opacity] 渐变透明度
const GradientBackground({
super.key,
required this.colors,
required this.child,
this.begin = Alignment.topLeft,
this.end = Alignment.bottomRight,
this.opacity = 0.15,
}) : assert(colors.length >= 1, '颜色列表至少需要一种颜色');

/// 渐变颜色列表
final List<Color> colors;

/// 子组件
final Widget child;

/// 渐变开始位置
final AlignmentGeometry begin;

/// 渐变结束位置
final AlignmentGeometry end;

/// 渐变透明度
final double opacity;

@override
Widget build(BuildContext context) {
// 如果只有一种颜色,则使用单色背景
if (colors.length == 1) {
final alpha = (opacity * 255).toInt(); // 转换为int
return ColoredBox(
color: colors.first
.withAlpha(alpha), // 使用withAlpha替代withValues和withOpacity
child: child,
);
}

// 否则使用渐变背景
return DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: colors.map((e) {
final alpha = (opacity * 255).toInt(); // 转换为int
return e.withAlpha(alpha); // 使用withAlpha替代withValues和withOpacity
}).toList(),
begin: begin,
end: end,
),
),
child: child,
);
}
}

/// 创建一个将渐变背景应用到某个Material组件的包装器
class GradientScaffold extends StatelessWidget {
/// 创建一个带渐变背景的Scaffold
const GradientScaffold({
super.key,
required this.colors,
required this.body,
this.appBar,
this.floatingActionButton,
this.drawer,
this.endDrawer,
this.bottomNavigationBar,
this.begin = Alignment.topLeft,
this.end = Alignment.bottomRight,
this.opacity = 0.1,
});

/// 渐变颜色列表
final List<Color> colors;

/// 页面内容
final Widget body;

/// 应用栏
final PreferredSizeWidget? appBar;

/// 浮动操作按钮
final Widget? floatingActionButton;

/// 抽屉菜单
final Widget? drawer;

/// 右侧抽屉
final Widget? endDrawer;

/// 底部导航栏
final Widget? bottomNavigationBar;

/// 渐变开始位置
final AlignmentGeometry begin;

/// 渐变结束位置
final AlignmentGeometry end;

/// 渐变透明度
final double opacity;

@override
Widget build(BuildContext context) {
return Scaffold(
// 将背景色设为透明,以便显示渐变效果
backgroundColor: Colors.transparent,
appBar: appBar,
floatingActionButton: floatingActionButton,
drawer: drawer,
endDrawer: endDrawer,
bottomNavigationBar: bottomNavigationBar,
// 包装内容于渐变背景中
body: GradientBackground(
colors: colors,
begin: begin,
end: end,
opacity: opacity,
child: body,
),
);
}
}

/// 为整个应用添加渐变背景的包装器
class GradientAppWrapper extends StatelessWidget {
/// 创建一个可以为整个应用添加渐变背景的包装器
///
/// 这个组件会保持应用原有的结构,只在顶层添加一个渐变层
const GradientAppWrapper({
super.key,
required this.colors,
required this.child,
this.begin = Alignment.topLeft,
this.end = Alignment.bottomRight,
this.opacity = 0.15,
});

/// 渐变颜色列表
final List<Color> colors;

/// 子应用
final Widget child;

/// 渐变开始位置
final AlignmentGeometry begin;

/// 渐变结束位置
final AlignmentGeometry end;

/// 渐变透明度
final double opacity;

@override
Widget build(BuildContext context) {
// 使用Stack布局,在底层放置渐变背景,顶层放置应用内容

// 渐变颜色列表,确保至少有两种颜色
final gradientColors = colors.length < 2
? [
colors.first,
Color.fromARGB(
colors.first.a.toInt(), // 使用原始属性,避免类型转换问题
colors.first.r.toInt(),
colors.first.g.toInt(),
(colors.first.b.toInt() + 50) % 256,
),
]
: colors;

return Stack(
children: [
// 渐变背景层
Positioned.fill(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: gradientColors.map((e) {
final alpha = (opacity * 255).toInt(); // 转换为int
return e
.withAlpha(alpha); // 使用withAlpha替代withValues和withOpacity
}).toList(),
begin: begin,
end: end,
),
),
),
),
// 应用内容层
child,
],
);
}
}
Loading