Files
doormile_milderapp/lib/helpers/app_bootstrap.dart
2026-08-11 13:16:33 +05:30

129 lines
4.8 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:miler/views/helpers/constants/Colorconstants.dart';
import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:miler/controllers/auth.dart';
import 'package:miler/views/introscreens/introscreen.dart';
import 'package:miler/views/onboardscreens/Mpin.dart';
import 'package:miler/views/onboardscreens/Sign_in.dart';
import 'package:miler/widget/Bottom_page.dart';
/// Decides which screen the app opens on, and nothing else.
///
/// This replaces the old animated splash screen. The splash held two very
/// different jobs: a four-second brand animation, and the routing rules that
/// decide login vs. intro vs. home. Only the second one is load-bearing.
///
/// The four seconds were pure cost for a rider who opens this app 30–50 times
/// a shift — the native launch image already covers the cold-start gap, so the
/// animation was time added on top of it, every single time. Removing it is
/// the single biggest latency win on the whole flow.
///
/// What survives is the routing, unchanged in behaviour:
/// • app version changed since last run → force re-verification (MPIN if the
/// rider was signed in, otherwise Sign In)
/// • signed in + on duty → straight to the dashboard
/// • signed in + off duty → the go-on-duty banner
/// • signed out, intro already seen → Sign In
/// • first ever launch → Introscreen
class AppBootstrap extends StatefulWidget {
const AppBootstrap({super.key});
@override
State<AppBootstrap> createState() => _AppBootstrapState();
}
class _AppBootstrapState extends State<AppBootstrap> {
bool _routed = false;
@override
void initState() {
super.initState();
// Route on the first frame — GetX needs a built navigator before `offAll`.
WidgetsBinding.instance.addPostFrameCallback((_) => _resolveStartScreen());
}
Future<void> _resolveStartScreen() async {
if (_routed) return;
_routed = true;
final prefs = await SharedPreferences.getInstance();
final bool isLoggedOut = prefs.getBool('logged_out') ?? false;
final bool hasSeenIntro = prefs.getBool('has_seen_intro') ?? false;
final int? savedUserId = prefs.getInt('userid');
// ── App update → force re-verification ──
try {
final packageInfo = await PackageInfo.fromPlatform();
final currentVersion = packageInfo.version;
final lastRunVersion = prefs.getString('last_run_version');
if (lastRunVersion != null && lastRunVersion != currentVersion) {
debugPrint(
'[BOOTSTRAP] App update detected: $lastRunVersion -> $currentVersion. '
'Forcing re-verification.',
);
final String? savedPhone = prefs.getString('contactno');
await prefs.setString('last_run_version', currentVersion);
if (savedUserId != null &&
savedPhone != null &&
savedPhone.isNotEmpty) {
debugPrint(
'[BOOTSTRAP] User was logged in. Redirecting to MPIN page.',
);
final auth = Get.put(AuthController());
auth.currentPhone = savedPhone;
await prefs.remove('userid');
await prefs.remove('partnerid');
await prefs.remove('onduty');
await prefs.setBool('logged_out', true);
if (mounted) Get.offAll(() => Mpin());
return;
}
debugPrint(
'[BOOTSTRAP] User was not logged in. Redirecting to Sign In.',
);
if (mounted) Get.offAll(() => const SignIn());
return;
}
await prefs.setString('last_run_version', currentVersion);
} catch (e) {
debugPrint('[BOOTSTRAP] Version check error: $e');
}
if (!mounted) return;
// ── Normal launch ──
//
// A signed-in rider lands on the tabs whether or not he is on duty. The
// duty gate that used to sit here made "open the app" and "start working"
// the same decision, so a rider checking his earnings between shifts had to
// pass a slider that put him back on the clock. Duty is a switch in Home's
// app bar, on the screen where the work is.
if (!isLoggedOut && savedUserId != null && savedUserId > 0) {
Get.offAll(() => const BottomPage());
} else {
Get.offAll(() => hasSeenIntro ? const SignIn() : Introscreen());
}
}
@override
Widget build(BuildContext context) {
// Held for the few milliseconds the prefs read takes. Plain white so it is
// indistinguishable from the native launch image — the rider should never
// perceive a screen here at all.
return Scaffold(
backgroundColor: ColorConstants.pureSurface,
body: SizedBox.expand(),
);
}
}