Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature added: resume last playback #715

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion app/src/main/java/dev/anilbeesetti/nextplayer/ui/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import com.google.accompanist.permissions.ExperimentalPermissionsApi
Expand All @@ -46,6 +48,7 @@ import dev.anilbeesetti.nextplayer.core.ui.components.DoneButton
import dev.anilbeesetti.nextplayer.core.ui.components.NextCenterAlignedTopAppBar
import dev.anilbeesetti.nextplayer.core.ui.components.NextDialog
import dev.anilbeesetti.nextplayer.core.ui.designsystem.NextIcons
import dev.anilbeesetti.nextplayer.feature.player.PlayerViewModel
import dev.anilbeesetti.nextplayer.navigation.MEDIA_ROUTE
import dev.anilbeesetti.nextplayer.navigation.mediaNavGraph
import dev.anilbeesetti.nextplayer.navigation.startPlayerActivity
Expand All @@ -59,9 +62,11 @@ const val MAIN_ROUTE = "main_screen_route"
fun MainScreen(
permissionState: PermissionState,
mainNavController: NavHostController,
mediaNavController: NavHostController
mediaNavController: NavHostController,
playerViewModel: PlayerViewModel = hiltViewModel()
) {
val context = LocalContext.current
val preferences by playerViewModel.playerPrefs.collectAsStateWithLifecycle()
var showUrlDialog by rememberSaveable { mutableStateOf(false) }
val selectVideoFileLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent(),
Expand All @@ -74,6 +79,16 @@ fun MainScreen(
verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal))
) {
if (preferences.lastPlayback.isNotEmpty()) {
FloatingActionButton(
onClick = { context.startPlayerActivity(Uri.parse(preferences.lastPlayback)) }
) {
Icon(
imageVector = NextIcons.Play,
contentDescription = stringResource(id = R.string.resume_last_playback)
)
}
}
FloatingActionButton(
onClick = { selectVideoFileLauncher.launch("video/*") }
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ data class PlayerPreferences(
val seekIncrement: Int = 10,
val autoplay: Boolean = true,
val autoPip: Boolean = true,
val lastPlayback: String = "",
val lastNetworkPlaybackPosition: Long = 0L,

// Controls (Gestures)
val useSwipeControls: Boolean = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import androidx.compose.material.icons.rounded.Palette
import androidx.compose.material.icons.rounded.PhotoSizeSelectSmall
import androidx.compose.material.icons.rounded.PictureInPictureAlt
import androidx.compose.material.icons.rounded.Pinch
import androidx.compose.material.icons.rounded.PlayArrow
import androidx.compose.material.icons.rounded.PlayCircle
import androidx.compose.material.icons.rounded.PriorityHigh
import androidx.compose.material.icons.rounded.RadioButtonUnchecked
Expand Down Expand Up @@ -97,6 +98,7 @@ object NextIcons {
val PhotoSize = Icons.Rounded.PhotoSizeSelectSmall
val Pip = Icons.Rounded.PictureInPictureAlt
val Pinch = Icons.Rounded.Pinch
val Play = Icons.Rounded.PlayArrow
val Player = Icons.Rounded.PlayCircle
val Priority = Icons.Rounded.PriorityHigh
val Replay = Icons.Rounded.Replay10
Expand Down
1 change: 1 addition & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
<string name="example_url" translatable="false">http://example.com/example.mp4</string>
<string name="network_stream">Network Stream</string>
<string name="play_file">Open video file to play</string>
<string name="resume_last_playback">Resume last playback</string>
<string name="play_url">Enter video url to play</string>
<string name="default_name">Default</string>
<string name="monospace">Monospace</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,11 @@ class PlayerActivity : AppCompatActivity() {
super.onStart()
}

override fun onPause() {
playlistManager.getCurrent()?.let { savePlayerState(it) }
super.onPause()
}

override fun onStop() {
binding.volumeGestureLayout.visibility = View.GONE
binding.brightnessGestureLayout.visibility = View.GONE
Expand Down Expand Up @@ -519,10 +524,15 @@ class PlayerActivity : AppCompatActivity() {
playlistManager.updateCurrent(uri)
val isCurrentUriIsFromIntent = intent.data == uri

viewModel.saveCurrentPlayback(uri)

viewModel.updateState(getPath(uri))
if (isCurrentUriIsFromIntent && playerApi.hasPosition) {
viewModel.currentPlaybackPosition = playerApi.position?.toLong()
}
if (getPath(uri) == null && (uri.toString() == playerPreferences.lastPlayback)) {
viewModel.currentPlaybackPosition = playerPreferences.lastNetworkPlaybackPosition
}

// Get all subtitles for current uri
val apiSubs = if (isCurrentUriIsFromIntent) playerApi.getSubs() else emptyList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ class PlayerViewModel @Inject constructor(
currentSubtitleTrackIndex = subtitleTrackIndex
currentPlaybackSpeed = playbackSpeed

if (path == null) return
if (path == null) {
saveCurrentNetworkPlaybackPosition(position)
return
}

val newPosition = position.takeIf {
position < duration - END_POSITION_OFFSET
Expand All @@ -97,6 +100,22 @@ class PlayerViewModel @Inject constructor(
}
}

fun saveCurrentPlayback(uri: Uri) {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences {
it.copy(lastPlayback = uri.toString())
}
}
}

private fun saveCurrentNetworkPlaybackPosition(position: Long) {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences {
it.copy(lastNetworkPlaybackPosition = position)
}
}
}

fun setPlayerBrightness(value: Float) {
viewModelScope.launch {
preferencesRepository.updatePlayerPreferences { it.copy(playerBrightness = value) }
Expand Down