mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-10 18:04:06 +02:00
perf: optimize state management, add HTTPS validation, improve UI performance
- Add HTTPS-only validation for APK downloads and update checks - Use .select() for Riverpod providers to prevent unnecessary rebuilds - Add keys to all list builders for efficient updates - Implement request cancellation for outdated API requests - Debounce all network requests (URLs and searches) - Limit file existence cache to 500 entries - Add ref.onDispose for timer cleanup - Add error handling for share intent stream - Redesign About page with Material Expressive 3 style - Rename Search tab to Home - Remove Features section from README
This commit is contained in:
1 parent
a7c5afdd20
commit
08bca30fcd
12 files changed
+395
-245
No files matched your search
@@ -249,6 +249,12 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
|
||||
@override
|
||||
DownloadQueueState build() {
|
||||
// Cleanup timer when provider is disposed
|
||||
ref.onDispose(() {
|
||||
_progressTimer?.cancel();
|
||||
_progressTimer = null;
|
||||
});
|
||||
|
||||
// Initialize output directory and load persisted queue asynchronously
|
||||
Future.microtask(() async {
|
||||
await _initOutputDir();
|
||||
|
||||
@@ -81,12 +81,21 @@ class ArtistAlbum {
|
||||
}
|
||||
|
||||
class TrackNotifier extends Notifier<TrackState> {
|
||||
/// Request ID to track and cancel outdated requests
|
||||
int _currentRequestId = 0;
|
||||
|
||||
@override
|
||||
TrackState build() {
|
||||
return const TrackState();
|
||||
}
|
||||
|
||||
/// Check if request is still valid (not cancelled by newer request)
|
||||
bool _isRequestValid(int requestId) => requestId == _currentRequestId;
|
||||
|
||||
Future<void> fetchFromUrl(String url) async {
|
||||
// Increment request ID to cancel any pending requests
|
||||
final requestId = ++_currentRequestId;
|
||||
|
||||
// Save current state for back navigation (only if we have content or it's empty)
|
||||
final savedState = state.hasContent ? TrackState(
|
||||
tracks: state.tracks,
|
||||
@@ -102,9 +111,12 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
|
||||
try {
|
||||
final parsed = await PlatformBridge.parseSpotifyUrl(url);
|
||||
if (!_isRequestValid(requestId)) return; // Request cancelled
|
||||
|
||||
final type = parsed['type'] as String;
|
||||
|
||||
final metadata = await PlatformBridge.getSpotifyMetadata(url);
|
||||
if (!_isRequestValid(requestId)) return; // Request cancelled
|
||||
|
||||
if (type == 'track') {
|
||||
final trackData = metadata['track'] as Map<String, dynamic>;
|
||||
@@ -152,11 +164,15 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!_isRequestValid(requestId)) return; // Request cancelled
|
||||
state = TrackState(isLoading: false, error: e.toString(), previousState: savedState);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> search(String query) async {
|
||||
// Increment request ID to cancel any pending requests
|
||||
final requestId = ++_currentRequestId;
|
||||
|
||||
// Save current state for back navigation
|
||||
final savedState = state.hasContent ? TrackState(
|
||||
tracks: state.tracks,
|
||||
@@ -172,6 +188,8 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
|
||||
try {
|
||||
final results = await PlatformBridge.searchSpotify(query, limit: 20);
|
||||
if (!_isRequestValid(requestId)) return; // Request cancelled
|
||||
|
||||
final trackList = results['tracks'] as List<dynamic>? ?? [];
|
||||
final tracks = trackList.map((t) => _parseSearchTrack(t as Map<String, dynamic>)).toList();
|
||||
state = TrackState(
|
||||
@@ -180,6 +198,7 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
previousState: savedState,
|
||||
);
|
||||
} catch (e) {
|
||||
if (!_isRequestValid(requestId)) return; // Request cancelled
|
||||
state = TrackState(isLoading: false, error: e.toString(), previousState: savedState);
|
||||
}
|
||||
}
|
||||
@@ -242,6 +261,9 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
|
||||
/// Fetch album from artist view - saves current artist state for back navigation
|
||||
Future<void> fetchAlbumFromArtist(String albumId) async {
|
||||
// Increment request ID to cancel any pending requests
|
||||
final requestId = ++_currentRequestId;
|
||||
|
||||
// Save current artist state before fetching album
|
||||
final savedState = TrackState(
|
||||
artistName: state.artistName,
|
||||
@@ -258,6 +280,7 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
try {
|
||||
final url = 'https://open.spotify.com/album/$albumId';
|
||||
final metadata = await PlatformBridge.getSpotifyMetadata(url);
|
||||
if (!_isRequestValid(requestId)) return; // Request cancelled
|
||||
|
||||
final albumInfo = metadata['album_info'] as Map<String, dynamic>;
|
||||
final trackList = metadata['track_list'] as List<dynamic>;
|
||||
@@ -271,6 +294,7 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
previousState: savedState,
|
||||
);
|
||||
} catch (e) {
|
||||
if (!_isRequestValid(requestId)) return; // Request cancelled
|
||||
state = TrackState(
|
||||
isLoading: false,
|
||||
error: e.toString(),
|
||||
|
||||
Reference in new issue
Block a user