first commit
This commit is contained in:
128
lib/helpers/app_bootstrap.dart
Normal file
128
lib/helpers/app_bootstrap.dart
Normal file
@@ -0,0 +1,128 @@
|
||||
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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user