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:
parent
8ac3a222c1
commit
dad37faecb
|
|
@ -10,6 +10,7 @@ void main() {
|
||||||
backgroundColor: const Color(0xFFFFFFFF),
|
backgroundColor: const Color(0xFFFFFFFF),
|
||||||
textColor: const Color(0xFF1F2937),
|
textColor: const Color(0xFF1F2937),
|
||||||
mutedTextColor: const Color(0xFF6B7280),
|
mutedTextColor: const Color(0xFF6B7280),
|
||||||
|
splashImage: const AssetImage('assets/branding/splash.png'),
|
||||||
initialUrl: "http://192.168.2.57:8080/test_bridge.html",
|
initialUrl: "http://192.168.2.57:8080/test_bridge.html",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -61,10 +61,8 @@ flutter:
|
||||||
# the material Icons class.
|
# the material Icons class.
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
assets:
|
||||||
# assets:
|
- assets/branding/
|
||||||
# - images/a_dot_burr.jpeg
|
|
||||||
# - images/a_dot_ham.jpeg
|
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/to/resolution-aware-images
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ class ShellEnvironment {
|
||||||
required this.backgroundColor,
|
required this.backgroundColor,
|
||||||
required this.textColor,
|
required this.textColor,
|
||||||
required this.mutedTextColor,
|
required this.mutedTextColor,
|
||||||
|
this.splashImage,
|
||||||
this.initialUrl,
|
this.initialUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -32,6 +33,9 @@ class ShellEnvironment {
|
||||||
/// 品牌次要文字色
|
/// 品牌次要文字色
|
||||||
final Color mutedTextColor;
|
final Color mutedTextColor;
|
||||||
|
|
||||||
|
/// 可选的品牌启动页图标;为空时使用默认图标。
|
||||||
|
final ImageProvider? splashImage;
|
||||||
|
|
||||||
/// 可选的初始地址;为空时使用默认地址。
|
/// 可选的初始地址;为空时使用默认地址。
|
||||||
final String? initialUrl;
|
final String? initialUrl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,64 +17,86 @@ class LaunchOverlay extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final splashImage = _env.splashImage;
|
||||||
|
|
||||||
return ColoredBox(
|
return ColoredBox(
|
||||||
color: _shellBackgroundColor,
|
color: _shellBackgroundColor,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
// ── 品牌 Logo ──
|
||||||
width: 88,
|
if (splashImage != null)
|
||||||
height: 88,
|
Container(
|
||||||
decoration: BoxDecoration(
|
width: 88,
|
||||||
gradient: LinearGradient(
|
height: 88,
|
||||||
colors: <Color>[const Color(0xFF66E59A), _shellAccentColor],
|
decoration: BoxDecoration(
|
||||||
begin: Alignment.topLeft,
|
borderRadius: BorderRadius.circular(24),
|
||||||
end: Alignment.bottomRight,
|
boxShadow: <BoxShadow>[
|
||||||
|
BoxShadow(
|
||||||
|
color: _shellAccentColor.withValues(alpha: 0.2),
|
||||||
|
blurRadius: 20,
|
||||||
|
offset: const Offset(0, 6),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(24),
|
child: ClipRRect(
|
||||||
boxShadow: <BoxShadow>[
|
borderRadius: BorderRadius.circular(24),
|
||||||
BoxShadow(
|
child: Image(
|
||||||
color: _shellAccentColor.withValues(alpha: 0.3),
|
image: splashImage,
|
||||||
blurRadius: 20,
|
width: 88,
|
||||||
offset: const Offset(0, 6),
|
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),
|
const SizedBox(height: 24),
|
||||||
|
// ── 品牌名称 ──
|
||||||
Text(
|
Text(
|
||||||
'页面加载中',
|
_env.appName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
color: _shellTextColor,
|
color: _shellTextColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
|
||||||
Text(
|
|
||||||
'正在为你启动 H5 页面',
|
|
||||||
style: TextStyle(color: _shellMutedTextColor, fontSize: 14),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 36),
|
const SizedBox(height: 36),
|
||||||
Padding(
|
// ── 不定态转圈 ──
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 64),
|
SizedBox(
|
||||||
child: ClipRRect(
|
width: 32,
|
||||||
borderRadius: BorderRadius.circular(6),
|
height: 32,
|
||||||
child: LinearProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
minHeight: 6,
|
strokeWidth: 3,
|
||||||
value: hasMeasuredProgress ? progress / 100 : null,
|
valueColor: AlwaysStoppedAnimation<Color>(_shellAccentColor),
|
||||||
backgroundColor: const Color(0xFFE7F3EB),
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
|
||||||
_shellAccentColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -83,3 +105,4 @@ class LaunchOverlay extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,9 @@ Future<void> main(List<String> args) async {
|
||||||
// 7. 生成图标与启动页配置
|
// 7. 生成图标与启动页配置
|
||||||
await _generateBrandingAssets(brand, appDir, config);
|
await _generateBrandingAssets(brand, appDir, config);
|
||||||
|
|
||||||
|
// 8. 在 pubspec.yaml 中注册 Flutter assets
|
||||||
|
await _registerFlutterAssets(appDir);
|
||||||
|
|
||||||
print('\x1B[32m✔ 应用 $brand 已生成到 $appDir!\x1B[0m');
|
print('\x1B[32m✔ 应用 $brand 已生成到 $appDir!\x1B[0m');
|
||||||
print('\x1B[34m构建应用请执行:\x1B[0m');
|
print('\x1B[34m构建应用请执行:\x1B[0m');
|
||||||
print(' cd $appDir && flutter build apk');
|
print(' cd $appDir && flutter build apk');
|
||||||
|
|
@ -201,6 +204,7 @@ void main() {
|
||||||
backgroundColor: const Color($bgColor),
|
backgroundColor: const Color($bgColor),
|
||||||
textColor: const Color($textColor),
|
textColor: const Color($textColor),
|
||||||
mutedTextColor: const Color($mutedTextColor),
|
mutedTextColor: const Color($mutedTextColor),
|
||||||
|
splashImage: const AssetImage('assets/branding/splash.png'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -337,3 +341,19 @@ flutter_native_splash:
|
||||||
}
|
}
|
||||||
print('\x1B[32m✔ 启动页已生成。\x1B[0m');
|
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');
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue