mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-08 23:18:16 -07:00
Init repo
This commit is contained in:
commit
764b6034e3
566 changed files with 212335 additions and 0 deletions
339
lib/main.dart
Normal file
339
lib/main.dart
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fladder/models/syncing/i_synced_item.dart';
|
||||
import 'package:fladder/providers/settings/client_settings_provider.dart';
|
||||
import 'package:fladder/providers/sync_provider.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import 'package:fladder/models/account_model.dart';
|
||||
import 'package:fladder/providers/shared_provider.dart';
|
||||
import 'package:fladder/providers/user_provider.dart';
|
||||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/routes/app_routes.dart';
|
||||
import 'package:fladder/routes/build_routes/route_builder.dart';
|
||||
import 'package:fladder/screens/login/lock_screen.dart';
|
||||
import 'package:fladder/theme.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/application_info.dart';
|
||||
import 'package:fladder/util/string_extensions.dart';
|
||||
import 'package:fladder/util/themes_data.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
bool get _isDesktop {
|
||||
if (kIsWeb) return false;
|
||||
return [
|
||||
TargetPlatform.windows,
|
||||
TargetPlatform.linux,
|
||||
TargetPlatform.macOS,
|
||||
].contains(defaultTargetPlatform);
|
||||
}
|
||||
|
||||
class CustomCacheManager {
|
||||
static const key = 'customCacheKey';
|
||||
static CacheManager instance = CacheManager(
|
||||
Config(
|
||||
key,
|
||||
stalePeriod: const Duration(days: 3),
|
||||
maxNrOfCacheObjects: 500,
|
||||
repo: JsonCacheInfoRepository(databaseName: key),
|
||||
fileService: HttpFileService(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void main() async {
|
||||
if (kIsWeb) {
|
||||
usePathUrlStrategy();
|
||||
html.document.onContextMenu.listen((event) => event.preventDefault());
|
||||
GoRouter.optionURLReflectsImperativeAPIs = true;
|
||||
}
|
||||
_setupLogging();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
Directory isarPath = Directory("");
|
||||
Directory applicationDirectory = Directory("");
|
||||
|
||||
if (!kIsWeb) {
|
||||
applicationDirectory = await getApplicationDocumentsDirectory();
|
||||
isarPath = Directory(path.joinAll([applicationDirectory.path, 'Fladder', 'Database']));
|
||||
await isarPath.create(recursive: true);
|
||||
}
|
||||
|
||||
if (_isDesktop) {
|
||||
await WindowManager.instance.ensureInitialized();
|
||||
}
|
||||
|
||||
final applicationInfo = ApplicationInfo(
|
||||
name: kIsWeb ? "${packageInfo.appName.capitalize()} Web" : packageInfo.appName.capitalize(),
|
||||
version: "${packageInfo.version}(${packageInfo.buildNumber})",
|
||||
os: defaultTargetPlatform.name.capitalize(),
|
||||
);
|
||||
|
||||
runApp(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
sharedPreferencesProvider.overrideWith((ref) => sharedPreferences),
|
||||
applicationInfoProvider.overrideWith((ref) => applicationInfo),
|
||||
syncProvider.overrideWith((ref) => SyncNotifier(
|
||||
ref,
|
||||
!kIsWeb
|
||||
? Isar.open(
|
||||
schemas: [ISyncedItemSchema],
|
||||
directory: isarPath.path,
|
||||
)
|
||||
: null,
|
||||
applicationDirectory,
|
||||
))
|
||||
],
|
||||
child: AdaptiveLayoutBuilder(
|
||||
fallBack: LayoutState.phone,
|
||||
layoutPoints: [
|
||||
LayoutPoints(start: 0, end: 599, type: LayoutState.phone),
|
||||
LayoutPoints(start: 600, end: 1919, type: LayoutState.tablet),
|
||||
LayoutPoints(start: 1920, end: 3180, type: LayoutState.desktop),
|
||||
],
|
||||
child: const Main(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _setupLogging() {
|
||||
Logger.root.level = Level.ALL;
|
||||
Logger.root.onRecord.listen((rec) {
|
||||
if (kDebugMode) {
|
||||
print('${rec.level.name}: ${rec.time}: ${rec.message}');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class Main extends ConsumerStatefulWidget with WindowListener {
|
||||
const Main({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<ConsumerStatefulWidget> createState() => _MainState();
|
||||
}
|
||||
|
||||
class _MainState extends ConsumerState<Main> with WindowListener, WidgetsBindingObserver {
|
||||
DateTime dateTime = DateTime.now();
|
||||
bool hidden = false;
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) async {
|
||||
if (ref.read(lockScreenActiveProvider) || ref.read(userProvider) == null) {
|
||||
dateTime = DateTime.now();
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case AppLifecycleState.resumed:
|
||||
enableTimeOut();
|
||||
break;
|
||||
case AppLifecycleState.hidden:
|
||||
break;
|
||||
case AppLifecycleState.paused:
|
||||
hidden = true;
|
||||
dateTime = DateTime.now();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void enableTimeOut() async {
|
||||
final timeOut = ref.read(clientSettingsProvider).timeOut;
|
||||
|
||||
if (timeOut == null) return;
|
||||
|
||||
final difference = DateTime.now().difference(dateTime).abs();
|
||||
|
||||
if (difference > timeOut && ref.read(userProvider)?.authMethod != Authentication.autoLogin && hidden) {
|
||||
hidden = false;
|
||||
dateTime = DateTime.now();
|
||||
|
||||
// Stop playback if the user was still watching a video
|
||||
await ref.read(videoPlayerProvider).pause();
|
||||
|
||||
if (context.mounted) {
|
||||
AdaptiveLayout.of(context).router.push(LockScreenRoute().route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
windowManager.addListener(this);
|
||||
_init();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
windowManager.removeListener(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowClose() {
|
||||
ref.read(videoPlayerProvider).stop();
|
||||
super.onWindowClose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowResize() async {
|
||||
final size = await windowManager.getSize();
|
||||
ref.read(clientSettingsProvider.notifier).setWindowSize(size);
|
||||
super.onWindowResize();
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowResized() async {
|
||||
final size = await windowManager.getSize();
|
||||
ref.read(clientSettingsProvider.notifier).setWindowSize(size);
|
||||
super.onWindowResized();
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowMove() async {
|
||||
final position = await windowManager.getPosition();
|
||||
ref.read(clientSettingsProvider.notifier).setWindowPosition(position);
|
||||
super.onWindowMove();
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowMoved() async {
|
||||
final position = await windowManager.getPosition();
|
||||
ref.read(clientSettingsProvider.notifier).setWindowPosition(position);
|
||||
super.onWindowMoved();
|
||||
}
|
||||
|
||||
void _init() async {
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
ref.read(sharedUtilityProvider).loadSettings();
|
||||
|
||||
final clientSettings = ref.read(clientSettingsProvider);
|
||||
|
||||
if (_isDesktop) {
|
||||
WindowOptions windowOptions = WindowOptions(
|
||||
size: Size(clientSettings.size.x, clientSettings.size.y),
|
||||
center: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
skipTaskbar: false,
|
||||
titleBarStyle: TitleBarStyle.hidden,
|
||||
title: packageInfo.appName.capitalize());
|
||||
|
||||
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||
await windowManager.show();
|
||||
await windowManager.focus();
|
||||
});
|
||||
} else {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: []);
|
||||
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
systemNavigationBarColor: Colors.transparent,
|
||||
systemNavigationBarDividerColor: Colors.transparent,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final themeMode = ref.watch(clientSettingsProvider.select((value) => value.themeMode));
|
||||
final themeColor = ref.watch(clientSettingsProvider.select((value) => value.themeColor));
|
||||
final amoledBlack = ref.watch(clientSettingsProvider.select((value) => value.amoledBlack));
|
||||
final mouseDrag = ref.watch(clientSettingsProvider.select((value) => value.mouseDragSupport));
|
||||
final language = ref.watch(clientSettingsProvider
|
||||
.select((value) => value.selectedLocale ?? WidgetsBinding.instance.platformDispatcher.locale));
|
||||
final scrollBehaviour = const MaterialScrollBehavior();
|
||||
return Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
||||
},
|
||||
child: DynamicColorBuilder(builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
||||
final lightTheme = themeColor == null
|
||||
? FladderTheme.theme(lightDynamic ?? FladderTheme.defaultScheme(Brightness.light))
|
||||
: FladderTheme.theme(themeColor.schemeLight);
|
||||
final darkTheme = (themeColor == null
|
||||
? FladderTheme.theme(darkDynamic ?? FladderTheme.defaultScheme(Brightness.dark))
|
||||
: FladderTheme.theme(themeColor.schemeDark));
|
||||
final amoledOverwrite = amoledBlack ? Colors.black : null;
|
||||
return ThemesData(
|
||||
light: lightTheme,
|
||||
dark: darkTheme,
|
||||
child: MaterialApp.router(
|
||||
onGenerateTitle: (context) => ref.watch(currentTitleProvider),
|
||||
theme: lightTheme,
|
||||
scrollBehavior: scrollBehaviour.copyWith(
|
||||
dragDevices: {
|
||||
...scrollBehaviour.dragDevices,
|
||||
mouseDrag ? PointerDeviceKind.mouse : null,
|
||||
}.whereNotNull().toSet(),
|
||||
),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
builder: (context, child) => Localizations.override(
|
||||
context: context,
|
||||
locale: AppLocalizations.supportedLocales.firstWhere(
|
||||
(element) => element.languageCode == language.languageCode,
|
||||
orElse: () => Locale('en', "GB"),
|
||||
),
|
||||
child: ScaffoldMessenger(child: child ?? Container()),
|
||||
),
|
||||
darkTheme: darkTheme.copyWith(
|
||||
scaffoldBackgroundColor: amoledOverwrite,
|
||||
cardColor: amoledOverwrite,
|
||||
canvasColor: amoledOverwrite,
|
||||
colorScheme: darkTheme.colorScheme.copyWith(
|
||||
surface: amoledOverwrite,
|
||||
surfaceContainerHighest: amoledOverwrite,
|
||||
),
|
||||
),
|
||||
themeMode: themeMode,
|
||||
routerConfig: AdaptiveLayout.of(context).router,
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
List<RouteBase> getRoutes(LayoutState state) {
|
||||
switch (state) {
|
||||
case LayoutState.phone:
|
||||
return AppRoutes.linearRoutes;
|
||||
case LayoutState.tablet:
|
||||
case LayoutState.desktop:
|
||||
return AppRoutes.nestedRoutes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final currentTitleProvider = StateProvider<String>((ref) {
|
||||
return "Fladder";
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue