fix(ui): prevent NaN division crash in TvChannelGrid and fix playlist silent failure

- tv_channel_grid.dart: guard screenWidth <= 0 / NaN / Infinite on first
  Flutter Web layout pass (previously caused NaN ~/ 225.03 crash cascade).
  Also use .clamp(1.0, infinity) on item width for belt-and-suspenders safety.
  Fix invalid 'padding.vertical as double?' cast in TvHorizontalList by using
  padding.resolve(TextDirection.ltr).top instead.

- playlist_api_service.dart: remove silent catch-and-return-empty in
  getPlaylists(). Exceptions now propagate to the Riverpod FutureProvider
  so the UI shows the real error state (with Retry button) instead of
  a misleading 'No playlists available' when the API call actually failed
  (e.g., 401 Unauthorized or network error).
This commit is contained in:
Michael committed 2026-03-26 16:24:18 +01:00
1 parent 288bf9e6ee
commit 9755f51af5
2 files changed
+40 -28

No files matched your search

+21 -20
View File
@@ -5,28 +5,29 @@ import '../models/playlist_config.dart';
class PlaylistApiService {
final ApiClient _api = ApiClient();
/// Get all playlists for current user
/// Get all playlists for current user.
///
/// Throws on API error so the Riverpod [FutureProvider] can expose the
/// [AsyncError] state — ensuring the UI shows a proper error with Retry,
/// instead of silently rendering an empty list.
Future<List<PlaylistConfig>> getPlaylists() async {
try {
final response = await _api.get('/api/playlists');
final data = response.data as Map<String, dynamic>;
final playlistsData = data['playlists'] as List<dynamic>;
final response = await _api.get('/api/playlists');
final data = response.data as Map<String, dynamic>;
final playlistsData = data['playlists'] as List<dynamic>;
return playlistsData.map((p) {
final playlist = p as Map<String, dynamic>;
return PlaylistConfig(
id: playlist['id'] as String,
name: playlist['name'] as String,
dns: playlist['serverUrl'] as String? ?? playlist['dns'] as String,
username: playlist['username'] as String,
password: playlist['password'] as String,
createdAt: DateTime.tryParse(playlist['createdAt'] as String? ?? '') ?? DateTime.now(),
);
}).toList();
} catch (e) {
print('Error fetching playlists: $e');
return [];
}
return playlistsData.map((p) {
final playlist = p as Map<String, dynamic>;
return PlaylistConfig(
id: playlist['id'] as String,
name: playlist['name'] as String,
dns: playlist['serverUrl'] as String? ?? playlist['dns'] as String,
username: playlist['username'] as String,
password: playlist['password'] as String,
createdAt:
DateTime.tryParse(playlist['createdAt'] as String? ?? '') ??
DateTime.now(),
);
}).toList();
}
/// Create a new playlist