perf: optimize providers, caching, and reduce rebuilds

- Cache SharedPreferences.getInstance() in providers (settings, theme, recent_access)
- Pre-compute download counts in queue provider to avoid repeated filtering
- Add identical() caching for RecentAccessView in HomeTab
- Use selective watching for exploreProvider (sections, greeting, isLoading only)
- Move isYTMusicQuickPicks computation to ExploreSection.fromJson()
- Hoist static RegExp patterns to avoid repeated compilation
- Use batch operations for iOS path migration in history_database
- Replace containsKey+lookup with single lookup in palette_service
- Pre-compute lowercase strings outside filter loops in logger
- Fix _isLoaded race condition in DownloadHistoryNotifier
This commit is contained in:
zarzet committed 2026-01-22 03:56:47 +07:00
1 parent 55b75dc48d
commit 6388f3a5b8
17 files changed
+287 -155

No files matched your search

+2 -1
View File
@@ -6,6 +6,7 @@ import 'package:spotiflac_android/utils/logger.dart';
class CsvImportService {
static final _log = AppLogger('CsvImportService');
static final RegExp _lineSplitPattern = RegExp(r'\r\n|\r|\n');
static Future<List<Track>> pickAndParseCsv({
void Function(int current, int total)? onProgress,
@@ -123,7 +124,7 @@ class CsvImportService {
static List<Track> _parseCsv(String content) {
final List<Track> tracks = [];
final lines = content.split(RegExp(r'\r\n|\r|\n'));
final lines = content.split(_lineSplitPattern);
if (lines.isEmpty) return tracks;
int startIdx = 0;
+9 -3
View File
@@ -7,6 +7,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotiflac_android/utils/logger.dart';
final _log = AppLogger('HistoryDatabase');
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
/// Cached current iOS container path for path normalization
String? _currentContainerPath;
@@ -135,7 +136,7 @@ class HistoryDatabase {
await _initContainerPath();
if (_currentContainerPath == null) return false;
final prefs = await SharedPreferences.getInstance();
final prefs = await _prefs;
final lastContainer = prefs.getString('ios_last_container_path');
// Skip if container hasn't changed
@@ -152,6 +153,7 @@ class HistoryDatabase {
// Get all items with iOS paths
final rows = await db.query('history', columns: ['id', 'file_path']);
int updatedCount = 0;
final batch = db.batch();
for (final row in rows) {
final id = row['id'] as String;
@@ -160,7 +162,7 @@ class HistoryDatabase {
if (oldPath != null && _iosContainerPattern.hasMatch(oldPath)) {
final newPath = _normalizeIosPath(oldPath);
if (newPath != oldPath) {
await db.update(
batch.update(
'history',
{'file_path': newPath},
where: 'id = ?',
@@ -171,6 +173,10 @@ class HistoryDatabase {
}
}
if (updatedCount > 0) {
await batch.commit(noResult: true);
}
// Save current container path
await prefs.setString('ios_last_container_path', _currentContainerPath!);
@@ -185,7 +191,7 @@ class HistoryDatabase {
/// Migrate data from SharedPreferences to SQLite
/// Returns true if migration was performed, false if already migrated
Future<bool> migrateFromSharedPreferences() async {
final prefs = await SharedPreferences.getInstance();
final prefs = await _prefs;
final migrationKey = 'history_migrated_to_sqlite';
if (prefs.getBool(migrationKey) == true) {
+3 -2
View File
@@ -19,8 +19,9 @@ class PaletteService {
return null;
}
if (_colorCache.containsKey(imageUrl)) {
return _colorCache[imageUrl];
final cached = _colorCache[imageUrl];
if (cached != null) {
return cached;
}
try {
+8 -4
View File
@@ -9,6 +9,12 @@ class ShareIntentService {
factory ShareIntentService() => _instance;
ShareIntentService._internal();
static final RegExp _spotifyUriPattern =
RegExp(r'spotify:(track|album|playlist|artist):[a-zA-Z0-9]+');
static final RegExp _spotifyUrlPattern = RegExp(
r'https?://open\.spotify\.com/(track|album|playlist|artist)/[a-zA-Z0-9]+(\?[^\s]*)?',
);
final _sharedUrlController = StreamController<String>.broadcast();
StreamSubscription<List<SharedMediaFile>>? _mediaSubscription;
bool _initialized = false;
@@ -57,14 +63,12 @@ class ShareIntentService {
String? _extractSpotifyUrl(String text) {
if (text.isEmpty) return null;
final uriMatch = RegExp(r'spotify:(track|album|playlist|artist):[a-zA-Z0-9]+').firstMatch(text);
final uriMatch = _spotifyUriPattern.firstMatch(text);
if (uriMatch != null) {
return uriMatch.group(0);
}
final urlMatch = RegExp(
r'https?://open\.spotify\.com/(track|album|playlist|artist)/[a-zA-Z0-9]+(\?[^\s]*)?',
).firstMatch(text);
final urlMatch = _spotifyUrlPattern.firstMatch(text);
if (urlMatch != null) {
final fullUrl = urlMatch.group(0)!;
final queryIndex = fullUrl.indexOf('?');