mirror of
https://github.com/Ujwal223/FocusGram.git
synced 2026-04-02 17:41:16 +02:00
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
147 lines
4.1 KiB
Dart
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();
|
|
}
|
|
}
|