feat(launch_overlay): 使用品牌 Logo 和 AppName 替换通用图标

- ShellEnvironment 新增 splashImage 字段支持品牌启动图标
- LaunchOverlay 使用 splash.png 替换 Icons.language_rounded
- 标题改为品牌名称(appName),移除副标题
- 加载指示器改为 CircularProgressIndicator 不定态转圈
- 使用 accentColor 主题色
- generate_app.dart 自动注册 assets/branding/ 并生成 splashImage 配置
- quanxue pubspec.yaml 注册 assets/branding/ 目录
This commit is contained in:
Max 2026-03-20 10:14:43 +08:00
parent 8ac3a222c1
commit dad37faecb
5 changed files with 90 additions and 44 deletions

View File

@ -10,6 +10,7 @@ void main() {
backgroundColor: const Color(0xFFFFFFFF),
textColor: const Color(0xFF1F2937),
mutedTextColor: const Color(0xFF6B7280),
splashImage: const AssetImage('assets/branding/splash.png'),
initialUrl: "http://192.168.2.57:8080/test_bridge.html",
),
);

View File

@ -61,10 +61,8 @@ flutter:
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/branding/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images

View File

@ -11,6 +11,7 @@ class ShellEnvironment {
required this.backgroundColor,
required this.textColor,
required this.mutedTextColor,
this.splashImage,
this.initialUrl,
});
@ -32,6 +33,9 @@ class ShellEnvironment {
///
final Color mutedTextColor;
/// 使
final ImageProvider? splashImage;
/// 使
final String? initialUrl;
}

View File

@ -17,64 +17,86 @@ class LaunchOverlay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final splashImage = _env.splashImage;
return ColoredBox(
color: _shellBackgroundColor,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
width: 88,
height: 88,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: <Color>[const Color(0xFF66E59A), _shellAccentColor],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
// Logo
if (splashImage != null)
Container(
width: 88,
height: 88,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
boxShadow: <BoxShadow>[
BoxShadow(
color: _shellAccentColor.withValues(alpha: 0.2),
blurRadius: 20,
offset: const Offset(0, 6),
),
],
),
borderRadius: BorderRadius.circular(24),
boxShadow: <BoxShadow>[
BoxShadow(
color: _shellAccentColor.withValues(alpha: 0.3),
blurRadius: 20,
offset: const Offset(0, 6),
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Image(
image: splashImage,
width: 88,
height: 88,
fit: BoxFit.contain,
),
],
),
)
else
Container(
width: 88,
height: 88,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
const Color(0xFF66E59A),
_shellAccentColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(24),
boxShadow: <BoxShadow>[
BoxShadow(
color: _shellAccentColor.withValues(alpha: 0.3),
blurRadius: 20,
offset: const Offset(0, 6),
),
],
),
alignment: Alignment.center,
child: const Icon(
Icons.language_rounded,
size: 42,
color: Colors.white,
),
),
alignment: Alignment.center,
child: const Icon(
Icons.language_rounded,
size: 42,
color: Colors.white,
),
),
const SizedBox(height: 24),
//
Text(
'页面加载中',
_env.appName,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w800,
color: _shellTextColor,
),
),
const SizedBox(height: 10),
Text(
'正在为你启动 H5 页面',
style: TextStyle(color: _shellMutedTextColor, fontSize: 14),
),
const SizedBox(height: 36),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 64),
child: ClipRRect(
borderRadius: BorderRadius.circular(6),
child: LinearProgressIndicator(
minHeight: 6,
value: hasMeasuredProgress ? progress / 100 : null,
backgroundColor: const Color(0xFFE7F3EB),
valueColor: AlwaysStoppedAnimation<Color>(
_shellAccentColor,
),
),
//
SizedBox(
width: 32,
height: 32,
child: CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation<Color>(_shellAccentColor),
),
),
],
@ -83,3 +105,4 @@ class LaunchOverlay extends StatelessWidget {
);
}
}

View File

@ -78,6 +78,9 @@ Future<void> main(List<String> args) async {
// 7.
await _generateBrandingAssets(brand, appDir, config);
// 8. pubspec.yaml Flutter assets
await _registerFlutterAssets(appDir);
print('\x1B[32m✔ 应用 $brand 已生成到 $appDir\x1B[0m');
print('\x1B[34m构建应用请执行\x1B[0m');
print(' cd $appDir && flutter build apk');
@ -201,6 +204,7 @@ void main() {
backgroundColor: const Color($bgColor),
textColor: const Color($textColor),
mutedTextColor: const Color($mutedTextColor),
splashImage: const AssetImage('assets/branding/splash.png'),
),
);
}
@ -337,3 +341,19 @@ flutter_native_splash:
}
print('\x1B[32m✔ 启动页已生成。\x1B[0m');
}
Future<void> _registerFlutterAssets(String appDir) async {
print('\x1B[34m[信息] 正在注册 Flutter assets...\x1B[0m');
final File pubspecFile = File('$appDir/pubspec.yaml');
String content = await pubspecFile.readAsString();
// flutter: assets
if (!content.contains('assets:')) {
content = content.replaceFirst(
'flutter:\n',
'flutter:\n assets:\n - assets/branding/\n',
);
await pubspecFile.writeAsString(content);
}
print('\x1B[32m✔ Flutter assets 已注册。\x1B[0m');
}