Files
FocusGram-Android/lib/main.dart
Ujwal 5232b8b0a9 UPDATES: updated UI from sidebar to topbar(again)
fixed external redirect on instagram m's settings.
fixed bug where it opened app session instead of reel session.
hided vertical scroll bar.
removed custom bottom bar.
fixed bug where it wasnt showing searchbar in /explore.

FIXED/ADDED/IMPROVED A LOT MORE THINGS.

Ready for Release
2026-02-24 00:04:23 +05:45

147 lines
4.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:app_links/app_links.dart';
import 'services/session_manager.dart';
import 'services/settings_service.dart';
import 'services/focusgram_router.dart';
import 'screens/onboarding_page.dart';
import 'screens/main_webview_page.dart';
import 'screens/breath_gate_screen.dart';
import 'screens/app_session_picker.dart';
import 'screens/cooldown_gate_screen.dart';
import 'services/notification_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Lock to portrait
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
final sessionManager = SessionManager();
final settingsService = SettingsService();
await sessionManager.init();
await settingsService.init();
await NotificationService().init();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: sessionManager),
ChangeNotifierProvider.value(value: settingsService),
],
child: const FocusGramApp(),
),
);
}
class FocusGramApp extends StatelessWidget {
const FocusGramApp({super.key});
@override
Widget build(BuildContext context) {
final settings = context.watch<SettingsService>();
final isDark = settings.isDarkMode;
return MaterialApp(
title: 'FocusGram',
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: isDark ? Brightness.dark : Brightness.light,
colorScheme: isDark
? ColorScheme.dark(
primary: Colors.blue.shade400,
surface: Colors.black,
)
: ColorScheme.light(primary: Colors.blue),
scaffoldBackgroundColor: isDark ? Colors.black : Colors.white,
useMaterial3: true,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
home: const InitialRouteHandler(),
);
}
}
/// Flow on every cold open:
/// 1. Onboarding (if first run)
/// 2. Cooldown Gate (if app-open cooldown active)
/// 3. Breath Gate (if enabled in settings)
/// 4. App Session Picker (always)
/// 5. Main WebView
class InitialRouteHandler extends StatefulWidget {
const InitialRouteHandler({super.key});
@override
State<InitialRouteHandler> createState() => _InitialRouteHandlerState();
}
class _InitialRouteHandlerState extends State<InitialRouteHandler> {
bool _breathCompleted = false;
bool _appSessionStarted = false;
bool _onboardingCompleted = false;
late AppLinks _appLinks;
@override
void initState() {
super.initState();
_appLinks = AppLinks();
_initDeepLinks();
}
Future<void> _initDeepLinks() async {
// 1. Handle background links while app is running
_appLinks.uriLinkStream.listen((uri) {
debugPrint('Incoming Deep Link: $uri');
FocusGramRouter.pendingUrl.value = uri.toString();
});
// 2. Handle the initial link that opened the app
final initialUri = await _appLinks.getInitialLink();
if (initialUri != null) {
debugPrint('Initial Deep Link: $initialUri');
FocusGramRouter.pendingUrl.value = initialUri.toString();
}
}
@override
Widget build(BuildContext context) {
final sm = context.watch<SessionManager>();
final settings = context.watch<SettingsService>();
// Step 1: Onboarding
if (settings.isFirstRun && !_onboardingCompleted) {
return OnboardingPage(
onFinish: () => setState(() => _onboardingCompleted = true),
);
}
// Step 2: Cooldown gate — if too soon since last session
if (sm.isAppOpenCooldownActive) {
return const CooldownGateScreen();
}
// Step 3: Breath gate
if (settings.showBreathGate && !_breathCompleted) {
return BreathGateScreen(
onFinish: () => setState(() => _breathCompleted = true),
);
}
// Step 4: App session picker
if (!_appSessionStarted) {
return AppSessionPickerScreen(
onSessionStarted: () => setState(() => _appSessionStarted = true),
);
}
// Step 5: Main app
return const MainWebViewPage();
}
}