first commit

This commit is contained in:
2026-08-11 13:16:33 +05:30
parent 18531bf46b
commit c8350563d9
388 changed files with 69656 additions and 0 deletions

View 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(),
);
}
}