Animate the splash and fix the web preview hanging on the logo

The splash now raises the sun in the mark and over a painted valley, floats
four feature chips around the mark, shimmers the wordmark, shows a three-beat
"how it works" card, drifts light motes upward and walks a status line
through the session check. A tap skips it.

The web build hung on the native splash because the asset manifest could not
be published: "assets/icons/splash_orb.png" is 27 characters, so its length
prefix in AssetManifest.bin is an ESC byte. Renamed it to splash_mark.png and
removed the unused anchor assets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhQh614DMeYoQEH9SoMRUw
This commit is contained in:
alvocool
2026-11-02 12:59:34 +03:00
parent fe268cb8aa
commit 36bc41509d
9 changed files with 443 additions and 137 deletions

View File

@@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<!-- Grounded mark: a horizon line with a weight resting on it. The bar is
the ground; the block is what you are carrying. -->
<rect width="512" height="512" fill="#141414"/>
<!-- The block -->
<rect x="176" y="146" width="160" height="160" rx="34" fill="#EDEEEA"/>
<!-- The notch — a debt taken out of the block -->
<rect x="236" y="146" width="40" height="86" rx="20" fill="#141414"/>
<!-- The ground line -->
<rect x="120" y="348" width="272" height="26" rx="13" fill="#2F6F4E"/>
<!-- Shadow beneath, shortened: the weight sits on the line -->
<rect x="168" y="396" width="176" height="14" rx="7" fill="#EDEEEA" opacity="0.22"/>
</svg>

Before

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -26,6 +26,9 @@ class SceneArt extends StatelessWidget {
/// Darkens the lower half so white type laid over it stays legible. /// Darkens the lower half so white type laid over it stays legible.
final bool shade; final bool shade;
/// Lowers the sun behind the ridges; animate it for a sunrise.
final double sunLift;
const SceneArt({ const SceneArt({
super.key, super.key,
required this.palette, required this.palette,
@@ -34,6 +37,7 @@ class SceneArt extends StatelessWidget {
this.figureScale = 0.5, this.figureScale = 0.5,
this.figureAlignment = const Alignment(0.35, 0.15), this.figureAlignment = const Alignment(0.35, 0.15),
this.shade = false, this.shade = false,
this.sunLift = 1,
}); });
@override @override
@@ -50,7 +54,8 @@ class SceneArt extends StatelessWidget {
child: Stack( child: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
CustomPaint(painter: ScenePainter(palette, seed)), CustomPaint(
painter: ScenePainter(palette, seed, sunLift: sunLift)),
if (figure != null) if (figure != null)
Align( Align(
alignment: figureAlignment, alignment: figureAlignment,

View File

@@ -11,7 +11,10 @@ class ScenePainter extends CustomPainter {
final int seed; final int seed;
ScenePainter(this.palette, this.seed); /// 1 → the sun sits in its place; 0 → it is down behind the ridges.
final double sunLift;
ScenePainter(this.palette, this.seed, {this.sunLift = 1});
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
@@ -36,7 +39,7 @@ class ScenePainter extends CustomPainter {
final double radius = math.min(w, h) * (0.13 + random.nextDouble() * 0.05); final double radius = math.min(w, h) * (0.13 + random.nextDouble() * 0.05);
final Offset sun = Offset( final Offset sun = Offset(
w * (0.18 + random.nextDouble() * 0.64), w * (0.18 + random.nextDouble() * 0.64),
h * (0.26 + random.nextDouble() * 0.12), h * (0.26 + random.nextDouble() * 0.12) + h * 0.5 * (1 - sunLift),
); );
canvas.drawCircle( canvas.drawCircle(
sun, sun,
@@ -109,6 +112,8 @@ class ScenePainter extends CustomPainter {
@override @override
bool shouldRepaint(covariant ScenePainter oldDelegate) { bool shouldRepaint(covariant ScenePainter oldDelegate) {
return oldDelegate.seed != seed || oldDelegate.palette != palette; return oldDelegate.seed != seed ||
oldDelegate.palette != palette ||
oldDelegate.sunLift != sunLift;
} }
} }

View File

@@ -1,11 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_animate/flutter_animate.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import '../../about/internal/application/MeDescription.dart'; import '../../about/internal/application/MeDescription.dart';
import '../../about/internal/application/NavigatorType.dart'; import '../../about/internal/application/NavigatorType.dart';
import '../../about/internal/application/RoutineKind.dart';
import '../../about/internal/application/TextType.dart'; import '../../about/internal/application/TextType.dart';
import '../../configs/Navigator.dart'; import '../../configs/Navigator.dart';
import '../../designs/AmbientBackground.dart'; import '../../designs/AmbientBackground.dart';
@@ -15,6 +17,7 @@ import '../../designs/Responsive.dart';
import '../../designs/scene/SceneArt.dart'; import '../../designs/scene/SceneArt.dart';
import '../../designs/text/Text.dart'; import '../../designs/text/Text.dart';
import '../../utils/Colors.dart'; import '../../utils/Colors.dart';
import '../../utils/CommonUtils.dart';
import '../home/Home.dart'; import '../home/Home.dart';
import '../login/Login.dart'; import '../login/Login.dart';
import 'ConnectSplash.dart'; import 'ConnectSplash.dart';
@@ -24,6 +27,28 @@ import 'ViewSplash.dart';
class SplashState extends State<Splash> implements ConnectSplash { class SplashState extends State<Splash> implements ConnectSplash {
ViewSplash? _model; ViewSplash? _model;
Timer? _statusTimer;
int _status = 0;
/// Set once the session check has been asked for, so a tap and the timer
/// never both fire it.
bool _launched = false;
/// What the loader says while it fills — the app's three jobs, in order.
static const List<String> _statuses = <String>[
"Loading your plan",
"Checking what's overdue",
"Lining up today's routines",
"Ready",
];
@override
void dispose() {
_statusTimer?.cancel();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ViewModelBuilder<ViewSplash>.reactive( return ViewModelBuilder<ViewSplash>.reactive(
@@ -51,136 +76,329 @@ class SplashState extends State<Splash> implements ConnectSplash {
} }
Future<void> _initiate() async { Future<void> _initiate() async {
// Long enough for the mark to land and take one breath, then the session _statusTimer = Timer.periodic(
// decides where we land. const Duration(milliseconds: 1000), _onStatusTick);
await Future.delayed(const Duration(milliseconds: 2200));
// Long enough to watch the sun come up and read the screen once; a tap
// skips straight on.
await Future.delayed(const Duration(milliseconds: 4200));
_launch();
}
void _onStatusTick(Timer timer) {
if (!mounted) {
return;
}
setState(() {
_status = (_status + 1).clamp(0, _statuses.length - 1);
});
}
void _onSkip() {
_launch();
}
void _launch() {
if (_launched || !mounted) {
return;
}
_launched = true;
_statusTimer?.cancel();
_model?.initialize(); _model?.initialize();
} }
String _greeting() {
final int hour = DateTime.now().hour;
if (hour < 5) {
return "Still up";
}
if (hour < 12) {
return "Good morning";
}
if (hour < 18) {
return "Good afternoon";
}
return "Good evening";
}
Widget _mobileView(BoxConstraints constraints) { Widget _mobileView(BoxConstraints constraints) {
return AmbientBackground( return GestureDetector(
child: Stack( onTap: _onSkip,
children: [ behavior: HitTestBehavior.opaque,
// The landscape rising from the bottom edge — the same painted world child: AmbientBackground(
// the routine cards live in. child: Stack(
Positioned( children: [
left: 0, _landscape(constraints),
right: 0, ..._motes(constraints),
bottom: 0, SafeArea(
height: constraints.maxHeight * 0.34, child: Padding(
child: ShaderMask( padding: const EdgeInsets.fromLTRB(24, 14, 24, 22),
shaderCallback: (Rect bounds) => const LinearGradient( child: Column(
begin: Alignment.topCenter, crossAxisAlignment: CrossAxisAlignment.stretch,
end: Alignment.bottomCenter, children: [
colors: <Color>[Color(0x00000000), Color(0xFF000000)], _topRow(),
stops: <double>[0.0, 0.45], const Spacer(flex: 2),
).createShader(bounds), _hero(),
blendMode: BlendMode.dstIn, const SizedBox(height: 26),
child: const SceneArt(palette: sceneWorkout, seed: 11), _wordmark(),
) const Spacer(flex: 2),
.animate() _howItWorks(),
.fadeIn(duration: 1200.ms, curve: Curves.easeOut) const Spacer(flex: 1),
.slideY(begin: 0.25, end: 0, duration: 1400.ms, _loader(),
curve: Curves.easeOutCubic), ],
), ),
SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(28, 18, 28, 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
text("Grounded", 17, TextType.Regular, color: colorInk),
text("Daily discipline", 17, TextType.Regular,
color: colorInkSoft),
],
).animate().fadeIn(duration: 600.ms, delay: 200.ms),
const Spacer(flex: 3),
Center(child: _mark()),
const SizedBox(height: 40),
_wordmark(),
const Spacer(flex: 4),
_loader(),
],
), ),
), ),
), ],
], ),
), ),
); );
} }
/// The mark on glass, inside rings that breathe outward. /// The painted valley rising from the bottom edge while its sun comes up.
Widget _mark() { Widget _landscape(BoxConstraints constraints) {
return Positioned(
left: 0,
right: 0,
bottom: 0,
height: constraints.maxHeight * 0.42,
child: ShaderMask(
shaderCallback: (Rect bounds) => const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[Color(0x00000000), Color(0xFF000000)],
stops: <double>[0.0, 0.4],
).createShader(bounds),
blendMode: BlendMode.dstIn,
child: TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0, end: 1),
duration: const Duration(milliseconds: 3200),
curve: Curves.easeOutCubic,
builder: (context, lift, child) => SceneArt(
palette: sceneWorkout,
seed: 11,
sunLift: lift,
),
),
)
.animate()
.fadeIn(duration: 900.ms)
.slideY(begin: 0.3, end: 0, duration: 1400.ms,
curve: Curves.easeOutCubic),
);
}
/// Specks of light drifting up out of the valley.
List<Widget> _motes(BoxConstraints constraints) {
const List<double> xs = <double>[0.12, 0.27, 0.41, 0.58, 0.7, 0.84, 0.93];
return List<Widget>.generate(xs.length, (index) {
final double size = 4.0 + (index % 3) * 2;
return Positioned(
left: constraints.maxWidth * xs[index],
bottom: constraints.maxHeight * (0.08 + (index % 4) * 0.05),
child: IgnorePointer(
child: Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colorWhite,
boxShadow: <BoxShadow>[
BoxShadow(
color: colorWhite.withValues(alpha: 0.8), blurRadius: 8),
],
),
)
.animate(onPlay: (controller) => controller.repeat())
.fadeIn(duration: 600.ms, delay: (index * 260).ms)
.moveY(
begin: 0,
end: -140 - index * 12.0,
duration: (2600 + index * 240).ms,
delay: (index * 260).ms,
curve: Curves.easeOut,
)
.fadeOut(
duration: 900.ms, delay: (2000 + index * 240).ms),
),
);
});
}
Widget _topRow() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
const GroundedMark(size: 26),
const SizedBox(width: 8),
text("Grounded", 16, TextType.Medium, color: colorInk),
],
),
GlassSurface(
radius: BorderRadius.circular(99),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(CupertinoIcons.sun_max_fill,
size: 13, color: colorStandingWarned),
const SizedBox(width: 6),
text(_greeting(), 12, TextType.Medium, color: colorInk),
],
),
),
],
).animate().fadeIn(duration: 600.ms, delay: 150.ms).slideY(
begin: -0.4, end: 0, duration: 600.ms, delay: 150.ms);
}
/// The mark in breathing rings, with the four things the app holds you to
/// floating around it.
Widget _hero() {
return SizedBox( return SizedBox(
width: 230, height: 270,
height: 230,
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
for (int ring = 0; ring < 3; ring++) for (int ring = 0; ring < 3; ring++)
Container( Container(
width: 120, width: 140,
height: 120, height: 140,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(
color: colorWhite.withValues(alpha: 0.9), width: 1.4), color: colorWhite.withValues(alpha: 0.95), width: 1.4),
), ),
) )
.animate(onPlay: (controller) => controller.repeat()) .animate(onPlay: (controller) => controller.repeat())
.scale( .scale(
begin: const Offset(1, 1), begin: const Offset(1, 1),
end: const Offset(1.9, 1.9), end: const Offset(1.85, 1.85),
duration: 2400.ms, duration: 2700.ms,
delay: (ring * 800).ms, delay: (ring * 900).ms,
curve: Curves.easeOutCubic, curve: Curves.easeOutCubic,
) )
.fadeOut(duration: 2400.ms, delay: (ring * 800).ms), .fadeOut(duration: 2700.ms, delay: (ring * 900).ms),
GlassSurface( _mark(),
radius: BorderRadius.circular(44), _chip(const Alignment(-1, -1), sceneWorkout,
padding: const EdgeInsets.all(10), kindIcon(RoutineKind.Workout), "Workout routines", 0),
child: Container( _chip(const Alignment(1, -0.62), sceneMeditation,
decoration: BoxDecoration( kindIcon(RoutineKind.Meditation), "Breathing sessions", 1),
borderRadius: BorderRadius.circular(32), _chip(const Alignment(-1, 0.62), sceneMustDo,
boxShadow: <BoxShadow>[ kindIcon(RoutineKind.MustDo), "Must-do chains", 2),
BoxShadow( _chip(const Alignment(1, 1), goalScene(goalAccents[4]),
color: colorPrimary.withValues(alpha: 0.35), CupertinoIcons.flag_fill, "Goals with deadlines", 3),
blurRadius: 40,
offset: const Offset(0, 16),
),
],
),
// The sun rises out of the ground line, then the arcs light.
child: TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0, end: 1),
duration: const Duration(milliseconds: 1700),
builder: (context, t, child) => GroundedMark(
size: 132,
rise: Curves.easeOutCubic
.transform((t / 0.6).clamp(0.0, 1.0)),
arcs: Curves.easeOut
.transform(((t - 0.45) / 0.55).clamp(0.0, 1.0)),
),
),
),
)
.animate()
.scale(
begin: const Offset(0.6, 0.6),
end: const Offset(1, 1),
duration: 900.ms,
curve: Curves.easeOutBack,
)
.fadeIn(duration: 500.ms),
], ],
), ),
); );
} }
/// Two-tone, like the greeting on the home screen. Widget _mark() {
return GlassSurface(
radius: BorderRadius.circular(46),
padding: const EdgeInsets.all(10),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(34),
boxShadow: <BoxShadow>[
BoxShadow(
color: colorPrimary.withValues(alpha: 0.4),
blurRadius: 40,
offset: const Offset(0, 16),
),
],
),
// The sun rises out of the ground line, then the arcs light.
child: TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0, end: 1),
duration: const Duration(milliseconds: 1800),
builder: (context, t, child) => GroundedMark(
size: 128,
rise: Curves.easeOutCubic.transform((t / 0.6).clamp(0.0, 1.0)),
arcs: Curves.easeOut
.transform(((t - 0.45) / 0.55).clamp(0.0, 1.0)),
),
),
),
)
.animate()
.scale(
begin: const Offset(0.6, 0.6),
end: const Offset(1, 1),
duration: 900.ms,
curve: Curves.easeOutBack,
)
.fadeIn(duration: 500.ms);
}
/// A frosted chip with a painted thumbnail. It drifts in, then bobs.
Widget _chip(Alignment alignment, List<Color> palette, IconData icon,
String label, int index) {
return Align(
alignment: alignment,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(99),
boxShadow: const [
BoxShadow(
color: Color(0x142A3A30),
blurRadius: 16,
offset: Offset(0, 6),
),
],
),
child: GlassSurface(
radius: BorderRadius.circular(99),
tint: colorGlassStrong,
padding: const EdgeInsets.fromLTRB(4, 4, 12, 4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 28,
height: 28,
child: ClipOval(
child: SceneArt(
palette: palette,
seed: 5 + index * 9,
figure: icon,
figureScale: 0.52,
figureAlignment: const Alignment(0, 0.2),
),
),
),
const SizedBox(width: 8),
text(label, 12, TextType.Medium, color: colorInk),
],
),
),
)
.animate()
.fadeIn(duration: 500.ms, delay: (900 + index * 180).ms)
.slideX(
begin: alignment.x < 0 ? -0.3 : 0.3,
end: 0,
duration: 600.ms,
delay: (900 + index * 180).ms,
curve: Curves.easeOutCubic,
)
.then()
.animate(onPlay: (controller) => controller.repeat(reverse: true))
.moveY(
begin: -3,
end: 3,
duration: (1800 + index * 260).ms,
curve: Curves.easeInOut,
),
);
}
/// Two tones, like the greeting on the home screen; the name catches the
/// light once as it lands.
Widget _wordmark() { Widget _wordmark() {
return Column( return Column(
children: [ children: [
@@ -189,9 +407,11 @@ class SplashState extends State<Splash> implements ConnectSplash {
.animate() .animate()
.fadeIn(duration: 700.ms, delay: 350.ms) .fadeIn(duration: 700.ms, delay: 350.ms)
.slideY(begin: 0.3, end: 0, duration: 700.ms, delay: 350.ms, .slideY(begin: 0.3, end: 0, duration: 700.ms, delay: 350.ms,
curve: Curves.easeOutCubic), curve: Curves.easeOutCubic)
const SizedBox(height: 10), .then(delay: 300.ms)
text("A to-do app that\ndoesn't believe you.", 22, TextType.Light, .shimmer(duration: 1200.ms, color: colorLime),
const SizedBox(height: 8),
text("A to-do app that\ndoesn't believe you.", 21, TextType.Regular,
color: colorInkSoft, align: TextAlign.center, height: 1.3) color: colorInkSoft, align: TextAlign.center, height: 1.3)
.animate() .animate()
.fadeIn(duration: 700.ms, delay: 650.ms) .fadeIn(duration: 700.ms, delay: 650.ms)
@@ -201,7 +421,80 @@ class SplashState extends State<Splash> implements ConnectSplash {
); );
} }
/// A glass capsule that fills while the session resolves. /// The whole idea in three beats, on glass over the valley.
Widget _howItWorks() {
return GlassSurface(
radius: BorderRadius.circular(24),
tint: colorGlassStrong,
padding: const EdgeInsets.fromLTRB(14, 14, 14, 14),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: _beat(CupertinoIcons.hand_raised_fill, "Commit",
"Say it and set a window", 0)),
_beatArrow(0),
Expanded(
child: _beat(CupertinoIcons.timer, "Do it",
"Inside the window, with proof", 1)),
_beatArrow(1),
Expanded(
child: _beat(CupertinoIcons.exclamationmark_triangle_fill,
"Or owe it", "Misses turn into debt", 2)),
],
),
).animate().fadeIn(duration: 600.ms, delay: 1500.ms).slideY(
begin: 0.25, end: 0, duration: 700.ms, delay: 1500.ms,
curve: Curves.easeOutCubic);
}
Widget _beat(IconData icon, String title, String caption, int index) {
final List<Color> tones = <Color>[
colorPrimary,
colorKindMeditation,
colorStandingGrounded,
];
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: tones[index].withValues(alpha: 0.12),
),
child: Icon(icon, size: 16, color: tones[index]),
)
.animate()
.scale(
begin: const Offset(0.4, 0.4),
end: const Offset(1, 1),
duration: 500.ms,
delay: (1700 + index * 250).ms,
curve: Curves.easeOutBack,
),
const SizedBox(height: 8),
text(title, 13, TextType.Medium, color: colorInk),
const SizedBox(height: 2),
text(caption, 10, TextType.Regular,
color: colorInkSoft, align: TextAlign.center, maxLines: 2),
],
);
}
Widget _beatArrow(int index) {
return Padding(
padding: const EdgeInsets.only(top: 12),
child: Icon(CupertinoIcons.chevron_right, size: 12, color: colorInkSoft)
.animate()
.fadeIn(duration: 400.ms, delay: (1900 + index * 250).ms),
);
}
/// A glass capsule that fills while the session resolves, and a status
/// line that walks through what is being checked.
Widget _loader() { Widget _loader() {
return Column( return Column(
children: [ children: [
@@ -209,33 +502,50 @@ class SplashState extends State<Splash> implements ConnectSplash {
radius: BorderRadius.circular(99), radius: BorderRadius.circular(99),
padding: const EdgeInsets.all(3), padding: const EdgeInsets.all(3),
child: SizedBox( child: SizedBox(
width: 140, width: 150,
height: 6, height: 6,
child: Align( child: Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Container( child: Container(
width: 140, width: 150,
decoration: BoxDecoration( decoration: BoxDecoration(
color: colorNight, color: colorNight,
borderRadius: BorderRadius.circular(99), borderRadius: BorderRadius.circular(99),
), ),
) ).animate().scaleX(
.animate()
.scaleX(
begin: 0.04, begin: 0.04,
end: 1, end: 1,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
duration: 2000.ms, duration: 4000.ms,
curve: Curves.easeInOutCubic, curve: Curves.easeInOutCubic,
), ),
), ),
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 10),
text("Checking what you promised", 12, TextType.Regular, AnimatedSwitcher(
color: colorWhite.withValues(alpha: 0.9)), duration: const Duration(milliseconds: 300),
transitionBuilder: (child, animation) => FadeTransition(
opacity: animation,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.4),
end: Offset.zero,
).animate(animation),
child: child,
),
),
child: KeyedSubtree(
key: ValueKey<int>(_status),
child: text(_statuses[_status], 12, TextType.Medium,
color: colorWhite),
),
),
const SizedBox(height: 4),
text("Tap anywhere to skip", 10, TextType.Regular,
color: colorWhite.withValues(alpha: 0.7)),
], ],
).animate().fadeIn(duration: 500.ms, delay: 900.ms); ).animate().fadeIn(duration: 500.ms, delay: 600.ms);
} }
@override @override

View File

@@ -3,7 +3,7 @@ const String imagePath = "assets/images";
const String iconPath = "assets/icons"; const String iconPath = "assets/icons";
/// The mark on a night disc, as the native splash shows it. /// The mark on a night disc, as the native splash shows it.
const String splashMark = "$iconPath/splash_orb.png"; const String splashMark = "$iconPath/splash_mark.png";
const String logoMark = "$iconPath/icon.png"; const String logoMark = "$iconPath/icon.png";

View File

@@ -122,10 +122,10 @@ flutter_launcher_icons:
# the OS screen to the app is invisible. # the OS screen to the app is invisible.
flutter_native_splash: flutter_native_splash:
color: "#EAEFE6" color: "#EAEFE6"
image: "assets/icons/splash_orb.png" image: "assets/icons/splash_mark.png"
android_12: android_12:
color: "#EAEFE6" color: "#EAEFE6"
image: "assets/icons/splash_orb.png" image: "assets/icons/splash_mark.png"
icon_background_color: "#EAEFE6" icon_background_color: "#EAEFE6"
android: true android: true
ios: true ios: true

View File

@@ -34,6 +34,8 @@
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<style id="splash-screen-style"> <style id="splash-screen-style">
html { html {
height: 100% height: 100%
@@ -108,6 +110,7 @@
</picture> </picture>
<!-- <!--
You can customize the "flutter_bootstrap.js" script. You can customize the "flutter_bootstrap.js" script.
This is useful to provide a custom configuration to the Flutter loader This is useful to provide a custom configuration to the Flutter loader