mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-04-01 17:40:32 +02:00
- Bound Deezer cache with LRU eviction and periodic cleanup - Configure Flutter image cache limits (240 entries / 60 MiB) - Add ResizeImage wrapper for precacheImage calls - Add memCacheWidth/cacheWidth to cover images across screens - Add DownloadedEmbeddedCoverResolver as centralized cover service - Throttle download progress notifications with dedup checks - Normalize progress/speed/bytes values to reduce UI rebuilds - Optimize queue list with per-item ConsumerWidget and RepaintBoundary - Preserve derived indexes in LocalLibraryState.copyWith - Skip non-error logs when detailed logging disabled - Use async file stat and early-break loops in queue filters
82 lines
2.5 KiB
Dart
82 lines
2.5 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:spotiflac_android/app.dart';
|
|
import 'package:spotiflac_android/providers/download_queue_provider.dart';
|
|
import 'package:spotiflac_android/providers/extension_provider.dart';
|
|
import 'package:spotiflac_android/services/notification_service.dart';
|
|
import 'package:spotiflac_android/services/share_intent_service.dart';
|
|
import 'package:spotiflac_android/services/cover_cache_manager.dart';
|
|
|
|
void main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
_configureImageCache();
|
|
|
|
runApp(
|
|
ProviderScope(child: const _EagerInitialization(child: SpotiFLACApp())),
|
|
);
|
|
}
|
|
|
|
void _configureImageCache() {
|
|
final imageCache = PaintingBinding.instance.imageCache;
|
|
// Keep memory cache bounded so cover-heavy pages don't retain too many
|
|
// full-resolution images simultaneously.
|
|
imageCache.maximumSize = 240;
|
|
imageCache.maximumSizeBytes = 60 << 20; // 60 MiB
|
|
}
|
|
|
|
/// Widget to eagerly initialize providers that need to load data on startup
|
|
class _EagerInitialization extends ConsumerStatefulWidget {
|
|
const _EagerInitialization({required this.child});
|
|
final Widget child;
|
|
|
|
@override
|
|
ConsumerState<_EagerInitialization> createState() =>
|
|
_EagerInitializationState();
|
|
}
|
|
|
|
class _EagerInitializationState extends ConsumerState<_EagerInitialization> {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_initializeAppServices();
|
|
_initializeExtensions();
|
|
ref.read(downloadHistoryProvider);
|
|
}
|
|
|
|
Future<void> _initializeAppServices() async {
|
|
try {
|
|
await CoverCacheManager.initialize();
|
|
await Future.wait([
|
|
NotificationService().initialize(),
|
|
ShareIntentService().initialize(),
|
|
]);
|
|
} catch (e) {
|
|
debugPrint('Failed to initialize app services: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> _initializeExtensions() async {
|
|
try {
|
|
final appDir = await getApplicationDocumentsDirectory();
|
|
final extensionsDir = '${appDir.path}/extensions';
|
|
final dataDir = '${appDir.path}/extension_data';
|
|
|
|
await Directory(extensionsDir).create(recursive: true);
|
|
await Directory(dataDir).create(recursive: true);
|
|
|
|
await ref
|
|
.read(extensionProvider.notifier)
|
|
.initialize(extensionsDir, dataDir);
|
|
} catch (e) {
|
|
debugPrint('Failed to initialize extensions: $e');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return widget.child;
|
|
}
|
|
}
|