Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ce8a581
Compose rewrite milestone #1
Maxr1998 Jun 13, 2023
b9591d8
Checkpoint: add more player controls to UI
Maxr1998 Aug 16, 2023
7af79f3
Checkpoint: handle fullscreen, restructure layout
Maxr1998 Aug 17, 2023
1e9aaee
Checkpoint: handle fullscreen, restructure layout
Maxr1998 Aug 17, 2023
110d3cd
Rework layout and add playback info
Maxr1998 Aug 18, 2023
1f90d74
Fix fullscreen and status bar colors
Maxr1998 Aug 18, 2023
6f2b837
Implement lock button
Maxr1998 Aug 18, 2023
7532ed3
Improve center button style
Maxr1998 Aug 18, 2023
7a72b3b
Too many changes to list
Maxr1998 Aug 19, 2023
f39e6f0
More tweaks
Maxr1998 Aug 20, 2023
0f12faa
Improve gesture detection
Maxr1998 Aug 20, 2023
33b270b
Also lock orientation in lock screen mode
Maxr1998 Aug 20, 2023
43d7bcd
Repackage
Maxr1998 Aug 20, 2023
7c02bdc
Swipe gestures
Maxr1998 Aug 20, 2023
61e2886
Add more menus
Maxr1998 Aug 21, 2023
09c9721
Update and tweak seeker
Maxr1998 Aug 22, 2023
d1dba06
Tweak buffering indicator size
Maxr1998 Aug 22, 2023
43cd73c
Extract and move constants
Maxr1998 Aug 22, 2023
ca82f15
Tweak controls handling
Maxr1998 Aug 22, 2023
a3b5374
Extract controls visibility handling to new view model
Maxr1998 Aug 22, 2023
25afb42
Fix previous/next handling
Maxr1998 Aug 22, 2023
e16791a
Audio selection and initial cleanup
Maxr1998 Aug 22, 2023
90bdd91
Extract some PlayerViewModel code
Maxr1998 Aug 22, 2023
b024226
Revert fullscreen interceptor changes
Maxr1998 Aug 24, 2023
bac5644
Add tooling and preview for Compose
Maxr1998 Jun 11, 2023
184180e
Fix double tap gestures
Maxr1998 Aug 25, 2023
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
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ dependencies {

// Jetpack Compose
implementation(libs.bundles.compose)
debugImplementation(libs.compose.ui.tooling)
implementation(libs.compose.ui.tooling.preview)
implementation(libs.seeker)

// Network
val sdkVersion = findProperty("sdk.version")?.toString()
Expand Down
10 changes: 8 additions & 2 deletions app/src/main/java/org/jellyfin/mobile/app/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ import org.jellyfin.mobile.bridge.NativePlayer
import org.jellyfin.mobile.events.ActivityEventHandler
import org.jellyfin.mobile.player.audio.car.LibraryBrowser
import org.jellyfin.mobile.player.deviceprofile.DeviceProfileBuilder
import org.jellyfin.mobile.player.interaction.PlayerEvent
import org.jellyfin.mobile.player.interaction.ApiHelper
import org.jellyfin.mobile.player.interaction.WebAppCommand
import org.jellyfin.mobile.player.interaction.WebAppCommandHandler
import org.jellyfin.mobile.player.qualityoptions.QualityOptionsProvider
import org.jellyfin.mobile.player.source.MediaSourceResolver
import org.jellyfin.mobile.player.ui.PlayerFragment
import org.jellyfin.mobile.player.ui.utils.PlaybackInfoBuilder
import org.jellyfin.mobile.setup.ConnectionHelper
import org.jellyfin.mobile.utils.Constants
import org.jellyfin.mobile.utils.PermissionRequestHelper
Expand All @@ -51,14 +54,15 @@ val applicationModule = module {
single { ImageLoader(androidApplication()) }
single { PermissionRequestHelper() }
single { RemoteVolumeProvider(get()) }
single(named(PLAYER_EVENT_CHANNEL)) { Channel<PlayerEvent>() }
single(named(PLAYER_EVENT_CHANNEL)) { Channel<WebAppCommand>() }

// Controllers
single { ApiClientController(get(), get(), get(), get(), get()) }

// Event handlers and channels
single { ActivityEventHandler(get()) }
single { WebappFunctionChannel() }
factory { WebAppCommandHandler(get(named(PLAYER_EVENT_CHANNEL))) }

// Bridge interfaces
single { NativePlayer(get(), get(), get(named(PLAYER_EVENT_CHANNEL))) }
Expand All @@ -74,9 +78,11 @@ val applicationModule = module {
single { ConnectionHelper(get(), get()) }

// Media player helpers
factory { ApiHelper(get(), get()) }
single { MediaSourceResolver(get()) }
single { DeviceProfileBuilder(get()) }
single { QualityOptionsProvider() }
single { PlaybackInfoBuilder(get()) }

// ExoPlayer factories
single<DataSource.Factory> {
Expand Down
18 changes: 9 additions & 9 deletions app/src/main/java/org/jellyfin/mobile/bridge/NativePlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.jellyfin.mobile.app.AppPreferences
import org.jellyfin.mobile.events.ActivityEvent
import org.jellyfin.mobile.events.ActivityEventHandler
import org.jellyfin.mobile.player.interaction.PlayOptions
import org.jellyfin.mobile.player.interaction.PlayerEvent
import org.jellyfin.mobile.player.interaction.WebAppCommand
import org.jellyfin.mobile.settings.VideoPlayerType
import org.jellyfin.mobile.utils.Constants
import org.json.JSONObject
Expand All @@ -15,7 +15,7 @@ import org.json.JSONObject
class NativePlayer(
private val appPreferences: AppPreferences,
private val activityEventHandler: ActivityEventHandler,
private val playerEventChannel: Channel<PlayerEvent>,
private val webAppCommandChannel: Channel<WebAppCommand>,
) {

@JavascriptInterface
Expand All @@ -30,36 +30,36 @@ class NativePlayer(

@JavascriptInterface
fun pausePlayer() {
playerEventChannel.trySend(PlayerEvent.Pause)
webAppCommandChannel.trySend(WebAppCommand.Pause)
}

@JavascriptInterface
fun resumePlayer() {
playerEventChannel.trySend(PlayerEvent.Resume)
webAppCommandChannel.trySend(WebAppCommand.Resume)
}

@JavascriptInterface
fun stopPlayer() {
playerEventChannel.trySend(PlayerEvent.Stop)
webAppCommandChannel.trySend(WebAppCommand.Stop)
}

@JavascriptInterface
fun destroyPlayer() {
playerEventChannel.trySend(PlayerEvent.Destroy)
webAppCommandChannel.trySend(WebAppCommand.Destroy)
}

@JavascriptInterface
fun seek(ticks: Long) {
playerEventChannel.trySend(PlayerEvent.Seek(ticks / Constants.TICKS_PER_MILLISECOND))
webAppCommandChannel.trySend(WebAppCommand.Seek(ticks / Constants.TICKS_PER_MILLISECOND))
}

@JavascriptInterface
fun seekMs(ms: Long) {
playerEventChannel.trySend(PlayerEvent.Seek(ms))
webAppCommandChannel.trySend(WebAppCommand.Seek(ms))
}

@JavascriptInterface
fun setVolume(volume: Int) {
playerEventChannel.trySend(PlayerEvent.SetVolume(volume))
webAppCommandChannel.trySend(WebAppCommand.SetVolume(volume))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.Intent
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Bundle
import androidx.core.view.WindowCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
Expand All @@ -15,7 +16,7 @@ import org.jellyfin.mobile.MainActivity
import org.jellyfin.mobile.R
import org.jellyfin.mobile.bridge.JavascriptCallback
import org.jellyfin.mobile.player.ui.PlayerFragment
import org.jellyfin.mobile.player.ui.PlayerFullscreenHelper
import org.jellyfin.mobile.player.ui.utils.FullscreenHelper
import org.jellyfin.mobile.settings.SettingsFragment
import org.jellyfin.mobile.utils.Constants
import org.jellyfin.mobile.utils.extensions.addFragment
Expand Down Expand Up @@ -45,14 +46,16 @@ class ActivityEventHandler(
private fun MainActivity.handleEvent(event: ActivityEvent) {
when (event) {
is ActivityEvent.ChangeFullscreen -> {
val fullscreenHelper = PlayerFullscreenHelper(window)
val fullscreenHelper = FullscreenHelper(window)
if (event.isFullscreen) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
WindowCompat.setDecorFitsSystemWindows(window, false)
fullscreenHelper.enableFullscreen()
window.setBackgroundDrawable(null)
} else {
// Reset screen orientation
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
WindowCompat.setDecorFitsSystemWindows(window, true)
fullscreenHelper.disableFullscreen()
// Reset window background color
window.setBackgroundDrawableResource(R.color.theme_background)
Expand Down
Loading