Fix: Resume playback not working - Hive storage issues

- Fixed Hive Map type conversion with safe iteration
- Improved save logic to not require duration loaded
- Added debug logging for troubleshooting
- Save position even if duration not available yet
This commit is contained in:
Michael committed 2025-12-10 11:41:28 +01:00
1 parent bf5893e545
commit 451dd082b0
2 files changed
+37 -11

No files matched your search

@@ -263,22 +263,31 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen> {
/// Save resume position when exiting player
void _saveResumePositionOnExit() {
if (widget.streamType == StreamType.live) return;
if (_duration.inSeconds <= 0) return;
final progress = _position.inSeconds / _duration.inSeconds;
debugPrint('MediaKitPlayer: Saving position - pos: ${_position.inSeconds}s, dur: ${_duration.inSeconds}s, contentId: $_contentId');
// Don't save if almost finished (> 90%) or already marked as watched
if (progress > 0.90 || _hasMarkedAsWatched) {
// If already marked as watched, clear any saved position
if (_hasMarkedAsWatched) {
ref.read(mobileWatchHistoryProvider.notifier).clearResumePosition(_contentId);
debugPrint('MediaKitPlayer: Already watched, clearing position');
return;
}
// Save position
// Check if almost finished (> 90%)
if (_duration.inSeconds > 0) {
final progress = _position.inSeconds / _duration.inSeconds;
if (progress > 0.90) {
ref.read(mobileWatchHistoryProvider.notifier).clearResumePosition(_contentId);
debugPrint('MediaKitPlayer: Almost finished (${(progress * 100).toStringAsFixed(1)}%), clearing position');
return;
}
}
// Save position (saveResumePosition handles the 30s minimum check)
ref.read(mobileWatchHistoryProvider.notifier).saveResumePosition(
_contentId,
_position.inSeconds,
);
debugPrint('MediaKitPlayer: Saved resume position at ${_position.inSeconds}s');
}
/// Attempt to reconnect a live stream that stopped
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
@@ -166,12 +167,24 @@ class MobileWatchHistoryNotifier extends StateNotifier<MobileWatchHistory> {
final movies = _box?.get('watchedMovies', defaultValue: <String>[]) as List?;
final episodes = _box?.get('watchedEpisodes', defaultValue: <String>[]) as List?;
final positions = _box?.get('resumePositions', defaultValue: <String, dynamic>{}) as Map?;
final positionsRaw = _box?.get('resumePositions');
// Safe conversion for resumePositions map
Map<String, int> positions = {};
if (positionsRaw != null && positionsRaw is Map) {
positionsRaw.forEach((key, value) {
if (key is String && value is int) {
positions[key] = value;
} else if (key is String && value is num) {
positions[key] = value.toInt();
}
});
}
state = MobileWatchHistory(
watchedMovies: movies?.cast<String>().toSet() ?? {},
watchedEpisodes: episodes?.cast<String>().toSet() ?? {},
resumePositions: positions?.cast<String, int>() ?? {},
resumePositions: positions,
);
}
@@ -208,12 +221,16 @@ class MobileWatchHistoryNotifier extends StateNotifier<MobileWatchHistory> {
/// Save resume position for movie or episode
void saveResumePosition(String contentId, int positionSeconds) {
// Only save if position is meaningful (> 30 seconds and < 95% of typical content)
if (positionSeconds < 30) return;
// Only save if position is meaningful (> 30 seconds)
if (positionSeconds < 30) {
debugPrint('[WatchHistory] Position too short ($positionSeconds), skipping save');
return;
}
debugPrint('[WatchHistory] Saving position for $contentId: ${positionSeconds}s');
final positions = {...state.resumePositions, contentId: positionSeconds};
state = state.copyWith(resumePositions: positions);
_box?.put('resumePositions', positions);
_box?.put('resumePositions', Map<String, int>.from(positions));
}
/// Clear resume position (when content finished or user wants to restart)