Skip to content

Conversation

@iseruuuuu
Copy link
Owner

@iseruuuuu iseruuuuu commented Dec 7, 2025

Issue

概要

  • Splash画面にアニメーションを入れました

追加したPackage

- motor

Screenshot

RPReplay_Final1765107868.mov

備考

Summary by CodeRabbit

  • New Features

    • Added animated branding overlay to the splash screen with smooth reveal transitions.
  • Style

    • Removed splash image layers from launch background on Android.
    • Adjusted splash screen window display settings across Android versions.
    • Updated iOS launch screen image sizing.
  • Chores

    • Added animation library dependency.
    • Updated splash screen configuration for better platform-specific rendering.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Walkthrough

Removes the platform splash bitmap layers, disables fullscreen/system-bar-drawing in Android launch themes, adjusts iOS launch image size, adds a Motor-driven branding overlay and navigation timing to the Flutter splash screen, and updates pubspec splash configuration and dependencies.

Changes

Cohort / File(s) Summary
Android launch backgrounds
android/app/src/main/res/drawable-v21/launch_background.xml, android/app/src/main/res/drawable/launch_background.xml
Removed the centered splash bitmap layer from the launch background layer-list; only the background bitmap remains.
Android styles (fullscreen & system bar)
android/app/src/main/res/values/styles.xml, android/app/src/main/res/values-night/styles.xml, android/app/src/main/res/values-v31/styles.xml, android/app/src/main/res/values-night-v31/styles.xml
In LaunchTheme, changed android:windowFullscreen and android:windowDrawsSystemBarBackgrounds from true to false across variants.
Android animated icon removal
android/app/src/main/res/values-v31/styles.xml, android/app/src/main/res/values-night-v31/styles.xml
Removed android:windowSplashScreenAnimatedIcon from LaunchTheme in Android 12+ style files.
iOS launch screen & plist formatting
ios/Runner/Base.lproj/LaunchScreen.storyboard, ios/Runner/Info.plist
Updated LaunchImage dimensions from 1300×1300 to 168×185 in storyboard; Info.plist changes are whitespace/reformatting only.
Flutter splash screen implementation
lib/ui/screen/splash/splash_screen.dart
Added motor usage, public state fields titleProgress and showBranding, a post-frame animation for titleProgress, a 2s branding delay, conditional navigation (registered → tab, else → newAccount), and a Stack-based branding overlay with animated text/icon.
Dependencies & splash config
pubspec.yaml
Added dependency motor: ^1.1.0; refactored flutter_native_splash config (removed global image/fullscreen, moved color under android_12.color).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • Inspect lib/ui/screen/splash/splash_screen.dart for animation timing, state exposure, and navigation correctness.
  • Verify Android style variants (values*) and removal of animated icon do not cause unexpected behavior on Android 12+.
  • Ensure flutter_native_splash config changes and new motor dependency align with build settings.

Possibly related PRs

  • Splach画面を改善する #675 — Modifies the same splash/launch resources and Android style attributes; likely directly related and may conflict with or duplicate splash changes.

Poem

🐰
I hopped upon the launch screen light,
White backdrop steady, letters bright,
Motor hums, the title grows,
Two seconds, then the app life flows,
Hooray — a branded, bouncy flight! ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Splash画面にアニメーションを入れました' accurately describes the main change: adding animation to the splash screen, which aligns with the actual code modifications throughout the pull request.
Linked Issues check ✅ Passed The PR successfully addresses issue #863 by implementing animation on the splash screen. Changes include adding motor dependency, refactoring splash UI with animated overlays, and adjusting animation timing.
Out of Scope Changes check ✅ Passed All changes are focused on implementing splash screen animation. Android layout/style modifications remove old splash imagery, iOS storyboard updates resize assets, pubspec adds motor dependency, and Dart code implements the animation logic—all within scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/refactor-splash

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@iseruuuuu iseruuuuu added the enhancement New feature or request label Dec 7, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/ui/screen/splash/splash_screen.dart (1)

36-47: Add mounted check after async gap to prevent crashes.

After await Future.delayed(...), the widget may have been disposed. Calling setState or navigating without checking mounted can cause exceptions like "setState() called after dispose()".

   Future<void> redirect(BuildContext context, WidgetRef ref) async {
     await Future<void>.delayed(const Duration(seconds: 2));
+    if (!mounted) return;
     ref.read(currentUserProvider.notifier).update();
     setState(() {
       showBranding = false;
     });
+    if (!mounted) return;
     if (await ref.read(accountServiceProvider).isUserRegistered()) {
+      if (!mounted) return;
       context.pushReplacementNamed(RouterPath.tab);
     } else {
+      if (!mounted) return;
       context.pushReplacementNamed(RouterPath.newAccount);
     }
   }
🧹 Nitpick comments (2)
lib/ui/screen/splash/splash_screen.dart (2)

22-34: Call super.initState() before other initialization logic.

The Dart/Flutter convention is to call super.initState() at the beginning of the method, not at the end.

   @override
   void initState() {
+    super.initState();
     redirect(context, ref);
     // 1フレーム後に 0→1 へ更新して文字を順次表示
     WidgetsBinding.instance.addPostFrameCallback((_) {
       if (!mounted) {
         return;
       }
       setState(() {
         titleProgress = 1.0;
       });
     });
-    super.initState();
   }

91-93: Consider extracting layout constants.

The leftPadding, iconWidth, and gap values are defined inside the builder callback and recreated on every animation frame. Moving them to class-level constants or outside the builder would be marginally cleaner.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 055bbe2 and e029bc8.

⛔ Files ignored due to path filters (19)
  • android/app/src/main/res/drawable-hdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-hdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-mdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-mdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-night-hdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-night-mdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-night-xhdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-night-xxhdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-xhdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-xhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-xxhdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-xxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-xxxhdpi/android12splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-xxxhdpi/splash.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/LaunchImage.imageset/[email protected] is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/LaunchImage.imageset/[email protected] is excluded by !**/*.png
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • android/app/src/main/res/drawable-v21/launch_background.xml (0 hunks)
  • android/app/src/main/res/drawable/launch_background.xml (0 hunks)
  • android/app/src/main/res/values-night-v31/styles.xml (1 hunks)
  • android/app/src/main/res/values-night/styles.xml (1 hunks)
  • android/app/src/main/res/values-v31/styles.xml (1 hunks)
  • android/app/src/main/res/values/styles.xml (1 hunks)
  • ios/Runner/Base.lproj/LaunchScreen.storyboard (1 hunks)
  • ios/Runner/Info.plist (1 hunks)
  • lib/ui/screen/splash/splash_screen.dart (3 hunks)
  • pubspec.yaml (2 hunks)
💤 Files with no reviewable changes (2)
  • android/app/src/main/res/drawable-v21/launch_background.xml
  • android/app/src/main/res/drawable/launch_background.xml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (9)
ios/Runner/Info.plist (1)

4-287: Formatting-only changes acknowledged.

The diff shows re-indentation of the plist structure with no functional changes to keys or values.

ios/Runner/Base.lproj/LaunchScreen.storyboard (1)

41-41: LaunchImage dimension change acknowledged.

The image size reduction from 1300×1300 to 168×185 aligns with the PR's approach of delegating the animated branding to the Flutter layer while keeping the native launch screen minimal.

pubspec.yaml (2)

95-100: Native splash configuration simplified correctly.

The configuration properly sets up a white background for both platforms and includes the android_12 block required for Android 12+ splash screen API compatibility.


53-53: New dependency for animation is valid.

The motor package (version 1.1.0 published on pub.dev) provides the SingleMotionBuilder used for the text reveal animation in the splash screen. The version constraint is appropriate.

lib/ui/screen/splash/splash_screen.dart (1)

82-120: Text reveal animation implementation looks well-crafted.

The SingleMotionBuilder approach with gradual character reveal, scale, and letter-spacing transitions creates a polished effect. The animation parameters (1800ms duration, easeOutCubic curve) provide smooth visual feedback.

android/app/src/main/res/values-night-v31/styles.xml (1)

6-7: Launch theme changes align with the new splash approach.

Disabling fullscreen mode and system bar background drawing during launch is appropriate since the animated branding is now handled at the Flutter layer. The system bars will remain visible during the brief native splash phase.

android/app/src/main/res/values/styles.xml (1)

9-10: Consistent with v31 variant changes—fullscreen disabled in default light theme.

The same fullscreen and system bar background changes applied to the default light theme. Consistency across all variants is maintained.

android/app/src/main/res/values-night/styles.xml (1)

9-10: Consistent with other variants—fullscreen disabled in dark theme.

The changes are identical to the light and v31 variants, maintaining consistency across all theme configurations for the splash screen startup behavior.

android/app/src/main/res/values-v31/styles.xml (1)

6-7: Fullscreen and system bar changes consistently applied across all style variants.

These changes disable fullscreen mode and prevent the app from drawing system bar backgrounds during splash, allowing system UI to remain visible. The settings are consistently applied across all four style variants (values, values-v31, values-night, and values-night-v31) and align with the animation-focused splash screen redesign.

The custom Flutter animation implementation in splash_screen.dart properly replaces the removed android:windowSplashScreenAnimatedIcon, using motor package and standard Flutter AnimatedBuilder with titleProgress animation to handle the splash screen animation sequence.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/ui/screen/splash/splash_screen.dart (1)

35-45: Guard async redirect with mounted checks to avoid setState / navigation after dispose.

Because redirect awaits a delay and isUserRegistered(), the SplashScreenState might be disposed before those futures complete (e.g., user backs out quickly). In that case setState or pushReplacementNamed can throw.

Add mounted / context.mounted guards around the async boundaries:

   Future<void> redirect(BuildContext context, WidgetRef ref) async {
-    await Future<void>.delayed(const Duration(seconds: 2));
-    ref.read(currentUserProvider.notifier).update();
-    setState(() {
-      showBranding = false;
-    });
-    if (await ref.read(accountServiceProvider).isUserRegistered()) {
-      context.pushReplacementNamed(RouterPath.tab);
-    } else {
-      context.pushReplacementNamed(RouterPath.newAccount);
-    }
+    await Future<void>.delayed(const Duration(seconds: 2));
+    if (!mounted) {
+      return;
+    }
+
+    ref.read(currentUserProvider.notifier).update();
+
+    setState(() {
+      showBranding = false;
+    });
+
+    final isRegistered =
+        await ref.read(accountServiceProvider).isUserRegistered();
+    if (!mounted || !context.mounted) {
+      return;
+    }
+
+    if (isRegistered) {
+      context.pushReplacementNamed(RouterPath.tab);
+    } else {
+      context.pushReplacementNamed(RouterPath.newAccount);
+    }
   }

Optionally, if you want the fade‑out animation to complete before navigation, you could also await Future<void>.delayed(const Duration(milliseconds: 300)); after toggling showBranding and before checking isUserRegistered() / navigating.

🧹 Nitpick comments (2)
lib/ui/screen/splash/splash_screen.dart (2)

22-33: Call super.initState() first to follow Flutter/Riverpod conventions.

super.initState() should run before doing work like kicking off redirects or scheduling post‑frame callbacks. This avoids surprises if the superclass (or ConsumerState) ever relies on its own initialization happening first.

You can simplify initState like this:

  @override
  void initState() {
-    redirect(context, ref);
-    WidgetsBinding.instance.addPostFrameCallback((_) {
-      if (!mounted) {
-        return;
-      }
-      setState(() {
-        titleProgress = 1.0;
-      });
-    });
-    super.initState();
+    super.initState();
+
+    redirect(context, ref);
+
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      if (!mounted) {
+        return;
+      }
+      setState(() {
+        titleProgress = 1.0;
+      });
+    });
   }

52-121: Branding overlay and Motor animation look good; consider de‑duplicating icon sizing.

The layered Stack + AnimatedOpacity and SingleMotionBuilder usage is coherent and should give a nice branding effect.

One small nit: the icon is rendered at width: 90, height: 90, but the text offset assumes iconWidth = 80. To avoid subtle misalignment if the icon size changes later, you could share a single constant:

-                        child:
-                            Assets.image.appIcon.image(width: 90, height: 90),
+                        const double iconSize = 90;
+                        child: Assets.image.appIcon.image(
+                          width: iconSize,
+                          height: iconSize,
+                        ),
...
-                        const double iconWidth = 80;
+                        const double iconWidth = iconSize;

(or hoist iconSize as a static const on the state class if you prefer).

Purely a maintainability/layout consistency tweak; the current code is functionally fine.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e029bc8 and c46ffa7.

📒 Files selected for processing (1)
  • lib/ui/screen/splash/splash_screen.dart (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (2)
lib/ui/screen/splash/splash_screen.dart (2)

8-8: Motor import looks appropriate; just confirm dependency wiring.

The extra motor import matches the new animation usage below and is fine. Please just double‑check that pubspec.yaml declares a compatible motor version so this stays in sync with your dependency graph.


18-20: State flags for animation and branding are clear and reasonable.

titleProgress starting at 0 and showBranding at true match the intended “animate in, then fade branding out” flow. No changes needed here.

Copy link
Owner Author

@iseruuuuu iseruuuuu left a comment

Choose a reason for hiding this comment

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

LGTM

@iseruuuuu iseruuuuu merged commit 5632da8 into main Dec 7, 2025
3 checks passed
@iseruuuuu iseruuuuu deleted the feature/refactor-splash branch December 7, 2025 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Splash画面にアニメーションを入れたい

2 participants