import 'dart:io'; import 'package:fluent_reader_lite/models/feeds_model.dart'; import 'package:fluent_reader_lite/models/global_model.dart'; import 'package:fluent_reader_lite/models/groups_model.dart'; import 'package:fluent_reader_lite/models/items_model.dart'; import 'package:fluent_reader_lite/models/service.dart'; import 'package:fluent_reader_lite/models/source.dart'; import 'package:fluent_reader_lite/models/services/feedbin.dart'; import 'package:fluent_reader_lite/models/services/fever.dart'; import 'package:fluent_reader_lite/models/services/greader.dart'; import 'package:fluent_reader_lite/models/sources_model.dart'; import 'package:fluent_reader_lite/models/sync_model.dart'; import 'package:fluent_reader_lite/utils/db.dart'; import 'package:fluent_reader_lite/utils/font_manager.dart'; import 'package:fluent_reader_lite/utils/store.dart'; import 'package:flutter/cupertino.dart'; import 'package:jaguar/jaguar.dart'; import 'package:jaguar_flutter_asset/jaguar_flutter_asset.dart'; import 'package:sqflite/sqflite.dart'; abstract class Global { static bool _initialized = false; static late GlobalModel globalModel; static late SourcesModel sourcesModel; static late ItemsModel itemsModel; static late FeedsModel feedsModel; static late GroupsModel groupsModel; static late SyncModel syncModel; static ServiceHandler? service; static late Database db; static Jaguar? server; static final GlobalKey tabletPanel = GlobalKey(); static void init() { assert(!_initialized); _initialized = true; globalModel = GlobalModel(); sourcesModel = SourcesModel(); itemsModel = ItemsModel(); feedsModel = FeedsModel(); groupsModel = GroupsModel(); var serviceType = SyncService.values[Store.sp.getInt(StoreKeys.SYNC_SERVICE) ?? 0]; switch (serviceType) { case SyncService.None: break; case SyncService.Fever: service = FeverServiceHandler(); break; case SyncService.Feedbin: service = FeedbinServiceHandler(); break; case SyncService.GReader: case SyncService.Inoreader: service = GReaderServiceHandler(); break; } syncModel = SyncModel(); _initContents(); } static void _initContents() async { db = await DatabaseHelper.getDatabase(); await db.delete( "items", where: "date < ? AND starred = 0", whereArgs: [ DateTime.now() .subtract(Duration(days: globalModel.keepItemsDays)) .millisecondsSinceEpoch, ], ); server = Jaguar(address: "127.0.0.1",port: 9000); server!.addRoute(serveFlutterAssets()); // Serve custom font files from app documents directory final fontsDir = await FontManager.getFontsDirectory(); server!.get('/custom-fonts/:filename*', (ctx) async { final filename = ctx.pathParams['filename']; if (filename == null || filename.isEmpty) { return Response(statusCode: 404); } // Security: only allow font file extensions final lowerFilename = filename.toLowerCase(); if (!FontManager.supportedExtensions.any((ext) => lowerFilename.endsWith(ext))) { return Response(statusCode: 403); } final file = File('${fontsDir.path}/$filename'); if (!await file.exists()) { return Response(statusCode: 404); } String mimeType = 'application/octet-stream'; if (lowerFilename.endsWith('.ttf')) mimeType = 'font/ttf'; else if (lowerFilename.endsWith('.otf')) mimeType = 'font/otf'; else if (lowerFilename.endsWith('.woff2')) mimeType = 'font/woff2'; else if (lowerFilename.endsWith('.woff')) mimeType = 'font/woff'; final bytes = await file.readAsBytes(); return ByteResponse(body: bytes, mimeType: mimeType); }); await server!.serve(); await sourcesModel.init(); await feedsModel.all.init(); if (globalModel.syncOnStart) await syncModel.syncWithService(); } static Brightness currentBrightness(BuildContext context) { return globalModel.getBrightness() ?? MediaQuery.of(context).platformBrightness; } static SourceOpenTarget resolveOpenTarget(RSSSource source) { var groupName = groupsModel.findGroupForSource(source.id); var groupTarget = groupName != null ? groupsModel.getGroupOpenTarget(groupName) : SourceOpenTarget.Inherit; return resolveOpenTargetCascade( source.openTarget, groupTarget, globalModel.globalOpenTarget, ); } static bool get isTablet => tabletPanel.currentWidget != null; static NavigatorState responsiveNavigator(BuildContext context) { return tabletPanel.currentWidget != null ? Global.tabletPanel.currentState! : Navigator.of(context, rootNavigator: true); } }