feat: implement a new splash screen with custom branding, assets, and routing for both Android and iOS.

This commit is contained in:
pradeepkumar
2026-03-10 22:46:48 +05:30
parent 5e2f42af2f
commit 792965f717
14 changed files with 142 additions and 16 deletions

View File

@@ -1,12 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- Gradient background from #c4d9d4 (top) to #f0f5fc (bottom) -->
<item android:drawable="@drawable/splash_gradient" />
<!-- You can insert your own image assets here -->
<!-- <item>
<!-- House illustration centered -->
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
android:src="@drawable/splash_house" />
</item>
<!-- RE-Quest logo below center -->
<item
android:gravity="center_horizontal|bottom"
android:bottom="200dp">
<bitmap
android:gravity="center"
android:src="@drawable/splash_logo" />
</item>
</layer-list>

View File

@@ -1,12 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- Gradient background from #c4d9d4 (top) to #f0f5fc (bottom) -->
<item android:drawable="@drawable/splash_gradient" />
<!-- You can insert your own image assets here -->
<!-- <item>
<!-- House illustration centered -->
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
android:src="@drawable/splash_house" />
</item>
<!-- RE-Quest logo below center -->
<item
android:gravity="center_horizontal|bottom"
android:bottom="200dp">
<bitmap
android:gravity="center"
android:src="@drawable/splash_logo" />
</item>
</layer-list>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#c4d9d4"
android:endColor="#f0f5fc"
android:angle="270" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -19,7 +19,7 @@
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" red="0.87058823529" green="0.90588235294" blue="0.86666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
@@ -32,6 +32,6 @@
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
<image name="LaunchImage" width="590" height="423"/>
</resources>
</document>

View File

@@ -0,0 +1,90 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:real_estate_mobile/core/constants/app_colors.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _fadeAnimation;
Timer? _navigationTimer;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 800),
);
_fadeAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
);
_controller.forward();
_navigationTimer = Timer(const Duration(seconds: 3), () {
if (mounted) {
context.go('/home');
}
});
}
@override
void dispose() {
_navigationTimer?.cancel();
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
AppColors.gradientStart,
AppColors.gradientEnd,
],
),
),
child: FadeTransition(
opacity: _fadeAnimation,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/splash_house.png',
width: 150,
fit: BoxFit.contain,
semanticLabel: 'House illustration',
),
const SizedBox(height: 35),
Image.asset(
'assets/images/splash_logo.png',
width: 264,
fit: BoxFit.contain,
semanticLabel: 'RE-Quest logo',
),
],
),
),
),
);
}
}

View File

@@ -20,6 +20,7 @@ import 'package:real_estate_mobile/features/profile/presentation/screens/profile
import 'package:real_estate_mobile/features/notifications/presentation/screens/notifications_screen.dart';
import 'package:real_estate_mobile/features/agents/presentation/screens/agent_edit_profile_screen.dart';
import 'package:real_estate_mobile/features/profile/presentation/screens/payment_success_screen.dart';
import 'package:real_estate_mobile/features/splash/presentation/screens/splash_screen.dart';
final routerProvider = Provider<GoRouter>((ref) {
final authRefreshNotifier = _AuthRefreshNotifier();
@@ -37,7 +38,7 @@ final routerProvider = Provider<GoRouter>((ref) {
const authRoutes = ['/login', '/signup'];
return GoRouter(
initialLocation: '/home',
initialLocation: '/splash',
refreshListenable: authRefreshNotifier,
redirect: (context, state) {
final authState = ref.read(authProvider);
@@ -50,6 +51,9 @@ final routerProvider = Provider<GoRouter>((ref) {
(route) => location == route || location.startsWith('$route/'),
);
// Never redirect away from splash — it handles its own navigation
if (location == '/splash') return null;
// While checking auth status, don't redirect
if (isLoading) return null;
@@ -65,6 +69,12 @@ final routerProvider = Provider<GoRouter>((ref) {
return null;
},
routes: [
// Splash screen (full screen, no shell)
GoRoute(
path: '/splash',
builder: (context, state) => const SplashScreen(),
),
// Auth routes (no shell — full screen)
GoRoute(
path: '/login',