perf: lazy extension VM init, incremental startup maintenance, and UI optimizations

- Defer extension VM initialization until first use with lockReadyVM() pattern to eliminate TOCTOU races and reduce startup overhead
- Add validateExtensionLoad() to catch JS errors at install time without keeping VM alive
- Teardown VM on extension disable to free resources; re-init lazily on re-enable
- Replace full orphan cleanup with incremental cursor-based pagination across launches
- Batch DB writes (upsertBatch, replaceAll) with transactions for atomicity
- Parse JSON natively on Kotlin side to avoid double-serialization over MethodChannel
- Add identity-based memoization caches for unified items and path match keys in queue tab
- Use ValueListenableBuilder for targeted embedded cover refreshes instead of full setState
- Extract shared widgets (_buildAlbumGridItemCore, _buildFilterButton, _navigateWithUnfocus)
- Use libraryCollectionsProvider selector and MediaQuery.paddingOf for fewer rebuilds
- Simplify supporter chip tiers and localize remaining hardcoded strings
This commit is contained in:
zarzet
2026-03-25 19:55:02 +07:00
parent da9d64ccfd
commit 03fd734048
18 changed files with 1279 additions and 1133 deletions
+40
View File
@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
/// Reusable option tile for bottom sheets.
/// Used in playlist options, track options, cover options, etc.
class BottomSheetOptionTile extends StatelessWidget {
final IconData icon;
final Color? iconColor;
final String title;
final VoidCallback onTap;
const BottomSheetOptionTile({
super.key,
required this.icon,
this.iconColor,
required this.title,
required this.onTap,
});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 4),
leading: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(12),
),
child: Icon(
icon,
color: iconColor ?? colorScheme.onPrimaryContainer,
size: 20,
),
),
title: Text(title, style: const TextStyle(fontWeight: FontWeight.w500)),
onTap: onTap,
);
}
}
+3 -1
View File
@@ -303,7 +303,9 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
),
for (final ext in downloadExtensions)
_ServiceChip(
label: ext.displayName,
label: widget.recommendedService == ext.id
? '${ext.displayName} (Recommended)'
: ext.displayName,
isSelected: _selectedService == ext.id,
onTap: () => setState(() => _selectedService = ext.id),
iconPath: ext.iconPath,