mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-14 03:31:06 +02:00
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:
17 files changed
+287
-155
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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('?');
|
||||
|
||||
Reference in new issue
Block a user