Fix: Movie infinite scroll + Player controls auto-hide

- Added in-memory caching for movies/series pagination in XtreamServiceMobile
- Fixed player controls appearing then instantly disappearing on touch
- Updated refresh methods to clear cache on pull-to-refresh
- Added releases/ to gitignore (APKs too large for GitHub)
This commit is contained in:
Michael committed 2025-12-10 10:23:04 +01:00
1 parent 3888a21990
commit ccda497236
8 files changed
+330 -83

No files matched your search

@@ -18,7 +18,7 @@ class MobileSeriesTab extends ConsumerStatefulWidget {
ConsumerState<MobileSeriesTab> createState() => _MobileSeriesTabState();
}
class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> with AutomaticKeepAliveClientMixin {
final ScrollController _scrollController = ScrollController();
final TextEditingController _searchController = TextEditingController();
final List<Series> _series = [];
@@ -99,10 +99,12 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
try {
final service = await ref.read(mobileXtreamServiceProvider(widget.playlist).future);
// Add timeout to prevent infinite loading state
final newSeries = await service.getSeriesPaginated(
offset: _currentOffset,
limit: _pageSize,
);
).timeout(const Duration(seconds: 15));
if (mounted) {
setState(() {
@@ -113,12 +115,35 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
});
}
} catch (e) {
debugPrint('Error loading series: $e');
if (mounted) {
setState(() => _isLoading = false);
setState(() {
_isLoading = false;
// Do NOT set _hasMore to false on error
});
}
}
}
Future<void> _refresh() async {
// Clear service cache to force fresh data
try {
final service = await ref.read(mobileXtreamServiceProvider(widget.playlist).future);
service.clearCache();
} catch (_) {}
setState(() {
_series.clear();
_currentOffset = 0;
_hasMore = true;
_searchResults = null;
_searchQuery = '';
_searchController.clear();
_isLoading = false;
});
await _loadMoreSeries();
}
String? _formatRating(String? rating) {
if (rating == null || rating.isEmpty) return null;
final value = double.tryParse(rating);
@@ -146,8 +171,12 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
);
}
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context); // Required for AutomaticKeepAliveClientMixin
final settings = ref.watch(mobileSettingsProvider);
List<Series> displaySeries;
@@ -170,8 +199,13 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
return SafeArea(
bottom: false,
child: CustomScrollView(
child: RefreshIndicator(
onRefresh: _refresh,
color: AppColors.primary,
backgroundColor: AppColors.surface,
child: CustomScrollView(
controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
// Header & Search
SliverToBoxAdapter(
@@ -283,6 +317,7 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
),
],
),
),
);
}
}