mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
The iOS local-network permission prompt fires on the first local-network access. That used to be the user's "Test" tap in settings, so the prompt appeared mid-request and the first connection attempt always failed. Provoke the prompt at launch instead via an mDNS multicast datagram, so the permission is settled before the user reaches settings. Platform exclusion is handled with a conditional import: web gets a no-op stub (keeping dart:io out of web builds) and the native path no-ops off iOS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
87 lines
2.3 KiB
Dart
87 lines
2.3 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:frontend/theme/catppuccin_mocha_theme.dart';
|
|
import 'package:frontend/utils/local_network_permission.dart';
|
|
import 'package:frontend/utils/pref_utils.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'navigation.dart';
|
|
import 'theme/gruvbox_theme.dart';
|
|
|
|
void main() {
|
|
runZonedGuarded(
|
|
() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
FlutterError.onError = (details) {
|
|
FlutterError.presentError(details);
|
|
debugPrint('FlutterError: ${details.exceptionAsString()}');
|
|
};
|
|
PlatformDispatcher.instance.onError = (error, stack) {
|
|
debugPrint('Uncaught platform error: $error\n$stack');
|
|
return true;
|
|
};
|
|
|
|
try {
|
|
await PrefUtil.init();
|
|
} catch (e, stack) {
|
|
debugPrint(
|
|
'PrefUtil.init failed, continuing with defaults: $e\n$stack',
|
|
);
|
|
}
|
|
|
|
// Settle iOS's local-network permission now, at launch, so it isn't
|
|
// still being decided when the user first taps "Test" in settings.
|
|
unawaited(requestLocalNetworkPermission());
|
|
|
|
runApp(const MainApp());
|
|
},
|
|
(error, stack) {
|
|
debugPrint('Uncaught zone error: $error\n$stack');
|
|
},
|
|
);
|
|
}
|
|
|
|
final class MainApp extends StatelessWidget {
|
|
const MainApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ChangeNotifierProvider(
|
|
create: (context) => AppState(),
|
|
child: Consumer<AppState>(
|
|
builder: (context, appState, _) => MaterialApp.router(
|
|
title: 'OOTT',
|
|
theme: appState.theme,
|
|
routerConfig: router,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
final _themes = {
|
|
'catppuccin_mocha': catppuccinMochaDarkTheme,
|
|
'gruvbox_dark': gruvboxDarkTheme,
|
|
};
|
|
|
|
class AppState extends ChangeNotifier {
|
|
AppState() {
|
|
final saved = PrefUtil.getValue('theme', 'gruvbox_dark') as String;
|
|
_themeKey = _themes.containsKey(saved) ? saved : 'gruvbox_dark';
|
|
}
|
|
|
|
late String _themeKey;
|
|
String get themeKey => _themeKey;
|
|
ThemeData get theme => _themes[_themeKey]!;
|
|
|
|
Future<bool> setTheme(String key) async {
|
|
if (!_themes.containsKey(key)) return false;
|
|
if (key == _themeKey) return true;
|
|
_themeKey = key;
|
|
notifyListeners();
|
|
return PrefUtil.setValue('theme', key);
|
|
}
|
|
}
|