mirror of
https://github.com/jellyfin/jellyfin-android.git
synced 2025-03-04 04:07:10 +00:00
Refactor application packages
This commit is contained in:
parent
ade07dbb62
commit
33a2d85595
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
@ -15,7 +15,7 @@
|
||||
}
|
||||
|
||||
# Keep Chromecast methods
|
||||
-keepclassmembers class org.jellyfin.mobile.cast.Chromecast {
|
||||
-keepclassmembers class org.jellyfin.mobile.player.cast.Chromecast {
|
||||
public *;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package org.jellyfin.mobile.cast
|
||||
package org.jellyfin.mobile.player.cast
|
||||
|
||||
import com.google.android.exoplayer2.Player
|
||||
import org.jellyfin.mobile.media.MediaService
|
||||
import org.jellyfin.mobile.player.audio.MediaService
|
||||
|
||||
class CastPlayerProvider(@Suppress("UNUSED_PARAMETER") mediaService: MediaService) : ICastPlayerProvider {
|
||||
override val isCastSessionAvailable: Boolean = false
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast
|
||||
package org.jellyfin.mobile.player.cast
|
||||
|
||||
import android.app.Activity
|
||||
import org.jellyfin.mobile.bridge.JavascriptCallback
|
@ -59,7 +59,7 @@
|
||||
<service android:name=".webapp.RemotePlayerService" />
|
||||
|
||||
<service
|
||||
android:name="org.jellyfin.mobile.media.MediaService"
|
||||
android:name="org.jellyfin.mobile.player.audio.MediaService"
|
||||
android:exported="true"
|
||||
tools:ignore="ExportedService">
|
||||
<intent-filter>
|
||||
|
@ -3,8 +3,9 @@ package org.jellyfin.mobile
|
||||
import android.app.Application
|
||||
import android.webkit.WebView
|
||||
import com.melegy.redscreenofdeath.RedScreenOfDeath
|
||||
import org.jellyfin.mobile.api.apiModule
|
||||
import org.jellyfin.mobile.model.databaseModule
|
||||
import org.jellyfin.mobile.app.apiModule
|
||||
import org.jellyfin.mobile.app.applicationModule
|
||||
import org.jellyfin.mobile.data.databaseModule
|
||||
import org.jellyfin.mobile.utils.JellyTree
|
||||
import org.jellyfin.mobile.utils.isWebViewSupported
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
|
@ -13,18 +13,16 @@ import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import org.jellyfin.mobile.cast.Chromecast
|
||||
import org.jellyfin.mobile.cast.IChromecast
|
||||
import org.jellyfin.mobile.fragment.ConnectFragment
|
||||
import org.jellyfin.mobile.fragment.WebViewFragment
|
||||
import org.jellyfin.mobile.player.PlayerFragment
|
||||
import org.jellyfin.mobile.player.cast.Chromecast
|
||||
import org.jellyfin.mobile.player.cast.IChromecast
|
||||
import org.jellyfin.mobile.setup.ConnectFragment
|
||||
import org.jellyfin.mobile.webapp.WebViewFragment
|
||||
import org.jellyfin.mobile.player.ui.PlayerFragment
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.PermissionRequestHelper
|
||||
import org.jellyfin.mobile.utils.SmartOrientationListener
|
||||
import org.jellyfin.mobile.utils.isWebViewSupported
|
||||
import org.jellyfin.mobile.utils.replaceFragment
|
||||
import org.jellyfin.mobile.viewmodel.MainViewModel
|
||||
import org.jellyfin.mobile.viewmodel.ServerState
|
||||
import org.jellyfin.mobile.utils.extensions.replaceFragment
|
||||
import org.jellyfin.mobile.webapp.RemotePlayerService
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.androidx.fragment.android.setupKoinFragmentFactory
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.viewmodel
|
||||
package org.jellyfin.mobile
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
@ -6,25 +6,25 @@ import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.controller.ApiController
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity
|
||||
import org.jellyfin.mobile.app.ApiClientController
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity
|
||||
|
||||
class MainViewModel(
|
||||
app: Application,
|
||||
private val apiController: ApiController,
|
||||
private val apiClientController: ApiClientController,
|
||||
) : AndroidViewModel(app) {
|
||||
private val _serverState: MutableStateFlow<ServerState> = MutableStateFlow(ServerState.Pending)
|
||||
val serverState: StateFlow<ServerState> get() = _serverState
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
apiController.migrateFromPreferences()
|
||||
apiClientController.migrateFromPreferences()
|
||||
refreshServer()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun refreshServer() {
|
||||
val server = apiController.loadSavedServer()
|
||||
val server = apiClientController.loadSavedServer()
|
||||
_serverState.value = server?.let { ServerState.Available(it) } ?: ServerState.Unset
|
||||
}
|
||||
}
|
@ -1,18 +1,17 @@
|
||||
package org.jellyfin.mobile.controller
|
||||
package org.jellyfin.mobile.app
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.model.sql.dao.ServerDao
|
||||
import org.jellyfin.mobile.model.sql.dao.UserDao
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity
|
||||
import org.jellyfin.mobile.data.dao.ServerDao
|
||||
import org.jellyfin.mobile.data.dao.UserDao
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity
|
||||
import org.jellyfin.sdk.Jellyfin
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.model.DeviceInfo
|
||||
import org.jellyfin.sdk.model.serializer.toUUID
|
||||
import java.util.*
|
||||
|
||||
class ApiController(
|
||||
class ApiClientController(
|
||||
private val appPreferences: AppPreferences,
|
||||
private val jellyfin: Jellyfin,
|
||||
private val apiClient: ApiClient,
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.api
|
||||
package org.jellyfin.mobile.app
|
||||
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.sdk.Jellyfin
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile
|
||||
package org.jellyfin.mobile.app
|
||||
|
||||
import android.content.Context
|
||||
import coil.ImageLoader
|
||||
@ -15,19 +15,18 @@ import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
|
||||
import com.google.android.exoplayer2.util.Util
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import okhttp3.OkHttpClient
|
||||
import org.jellyfin.mobile.api.DeviceProfileBuilder
|
||||
import org.jellyfin.mobile.MainViewModel
|
||||
import org.jellyfin.mobile.player.deviceprofile.DeviceProfileBuilder
|
||||
import org.jellyfin.mobile.bridge.ExternalPlayer
|
||||
import org.jellyfin.mobile.controller.ApiController
|
||||
import org.jellyfin.mobile.fragment.ConnectFragment
|
||||
import org.jellyfin.mobile.fragment.WebViewFragment
|
||||
import org.jellyfin.mobile.media.car.LibraryBrowser
|
||||
import org.jellyfin.mobile.player.PlayerEvent
|
||||
import org.jellyfin.mobile.player.PlayerFragment
|
||||
import org.jellyfin.mobile.setup.ConnectFragment
|
||||
import org.jellyfin.mobile.webapp.WebViewFragment
|
||||
import org.jellyfin.mobile.player.audio.car.LibraryBrowser
|
||||
import org.jellyfin.mobile.player.interaction.PlayerEvent
|
||||
import org.jellyfin.mobile.player.ui.PlayerFragment
|
||||
import org.jellyfin.mobile.player.source.MediaSourceResolver
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.PermissionRequestHelper
|
||||
import org.jellyfin.mobile.utils.isLowRamDevice
|
||||
import org.jellyfin.mobile.viewmodel.MainViewModel
|
||||
import org.jellyfin.mobile.webapp.RemoteVolumeProvider
|
||||
import org.jellyfin.mobile.webapp.WebappFunctionChannel
|
||||
import org.koin.android.ext.koin.androidApplication
|
||||
@ -49,7 +48,7 @@ val applicationModule = module {
|
||||
single(named(PLAYER_EVENT_CHANNEL)) { Channel<PlayerEvent>() }
|
||||
|
||||
// Controllers
|
||||
single { ApiController(get(), get(), get(), get(), get()) }
|
||||
single { ApiClientController(get(), get(), get(), get(), get()) }
|
||||
|
||||
// ViewModels
|
||||
viewModel { MainViewModel(get(), get()) }
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile
|
||||
package org.jellyfin.mobile.app
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
@ -12,9 +12,10 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.player.PlayerException
|
||||
import org.jellyfin.mobile.player.interaction.PlayOptions
|
||||
import org.jellyfin.mobile.player.source.ExternalSubtitleStream
|
||||
import org.jellyfin.mobile.player.source.JellyfinMediaSource
|
||||
import org.jellyfin.mobile.player.source.MediaSourceResolver
|
||||
|
@ -11,7 +11,7 @@ import android.webkit.JavascriptInterface
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.fragment.WebViewFragment
|
||||
import org.jellyfin.mobile.webapp.WebViewFragment
|
||||
import org.jellyfin.mobile.settings.SettingsFragment
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.Constants.EXTRA_ALBUM
|
||||
@ -25,11 +25,11 @@ import org.jellyfin.mobile.utils.Constants.EXTRA_ITEM_ID
|
||||
import org.jellyfin.mobile.utils.Constants.EXTRA_PLAYER_ACTION
|
||||
import org.jellyfin.mobile.utils.Constants.EXTRA_POSITION
|
||||
import org.jellyfin.mobile.utils.Constants.EXTRA_TITLE
|
||||
import org.jellyfin.mobile.utils.addFragment
|
||||
import org.jellyfin.mobile.utils.disableFullscreen
|
||||
import org.jellyfin.mobile.utils.enableFullscreen
|
||||
import org.jellyfin.mobile.utils.extensions.addFragment
|
||||
import org.jellyfin.mobile.utils.extensions.disableFullscreen
|
||||
import org.jellyfin.mobile.utils.extensions.enableFullscreen
|
||||
import org.jellyfin.mobile.utils.requestDownload
|
||||
import org.jellyfin.mobile.utils.requireMainActivity
|
||||
import org.jellyfin.mobile.utils.extensions.requireMainActivity
|
||||
import org.jellyfin.mobile.utils.runOnUiThread
|
||||
import org.jellyfin.mobile.webapp.RemotePlayerService
|
||||
import org.jellyfin.mobile.webapp.RemoteVolumeProvider
|
||||
|
@ -2,9 +2,10 @@ package org.jellyfin.mobile.bridge
|
||||
|
||||
import android.webkit.JavascriptInterface
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.PLAYER_EVENT_CHANNEL
|
||||
import org.jellyfin.mobile.player.PlayerEvent
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.app.PLAYER_EVENT_CHANNEL
|
||||
import org.jellyfin.mobile.player.interaction.PlayOptions
|
||||
import org.jellyfin.mobile.player.interaction.PlayerEvent
|
||||
import org.jellyfin.mobile.settings.VideoPlayerType
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.json.JSONObject
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.jellyfin.mobile.bridge
|
||||
|
||||
import org.jellyfin.mobile.player.interaction.PlayOptions
|
||||
|
||||
interface NativePlayerHost {
|
||||
fun loadNativePlayer(playOptions: PlayOptions)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.jellyfin.mobile.model
|
||||
package org.jellyfin.mobile.data
|
||||
|
||||
import androidx.room.Room
|
||||
import org.jellyfin.mobile.model.sql.JellyfinDatabase
|
||||
import org.koin.android.ext.koin.androidApplication
|
||||
import org.koin.dsl.module
|
||||
|
@ -1,11 +1,11 @@
|
||||
package org.jellyfin.mobile.model.sql
|
||||
package org.jellyfin.mobile.data
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import org.jellyfin.mobile.model.sql.dao.ServerDao
|
||||
import org.jellyfin.mobile.model.sql.dao.UserDao
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity
|
||||
import org.jellyfin.mobile.data.dao.ServerDao
|
||||
import org.jellyfin.mobile.data.dao.UserDao
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity
|
||||
import org.jellyfin.mobile.data.entity.UserEntity
|
||||
|
||||
@Database(entities = [ServerEntity::class, UserEntity::class], version = 2)
|
||||
abstract class JellyfinDatabase : RoomDatabase() {
|
@ -1,11 +1,11 @@
|
||||
package org.jellyfin.mobile.model.sql.dao
|
||||
package org.jellyfin.mobile.data.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity.Key.TABLE_NAME
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity.Key.TABLE_NAME
|
||||
|
||||
@Dao
|
||||
interface ServerDao {
|
@ -1,17 +1,17 @@
|
||||
package org.jellyfin.mobile.model.sql.dao
|
||||
package org.jellyfin.mobile.data.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerUser
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.ACCESS_TOKEN
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.ID
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.SERVER_ID
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.TABLE_NAME
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.USER_ID
|
||||
import org.jellyfin.mobile.data.entity.ServerUser
|
||||
import org.jellyfin.mobile.data.entity.UserEntity
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.ACCESS_TOKEN
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.ID
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.SERVER_ID
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.TABLE_NAME
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.USER_ID
|
||||
|
||||
@Dao
|
||||
@Suppress("TooManyFunctions")
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.model.sql.entity
|
||||
package org.jellyfin.mobile.data.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.ColumnInfo
|
||||
@ -6,8 +6,8 @@ import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity.Key.HOSTNAME
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity.Key.TABLE_NAME
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity.Key.HOSTNAME
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity.Key.TABLE_NAME
|
||||
|
||||
@Parcelize
|
||||
@Entity(tableName = TABLE_NAME, indices = [Index(value = arrayOf(HOSTNAME), unique = true)])
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.model.sql.entity
|
||||
package org.jellyfin.mobile.data.entity
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Relation
|
@ -1,13 +1,13 @@
|
||||
package org.jellyfin.mobile.model.sql.entity
|
||||
package org.jellyfin.mobile.data.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.SERVER_ID
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.TABLE_NAME
|
||||
import org.jellyfin.mobile.model.sql.entity.UserEntity.Key.USER_ID
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.SERVER_ID
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.TABLE_NAME
|
||||
import org.jellyfin.mobile.data.entity.UserEntity.Key.USER_ID
|
||||
|
||||
@Entity(
|
||||
tableName = TABLE_NAME,
|
@ -28,10 +28,14 @@ import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.BuildConfig
|
||||
import org.jellyfin.mobile.PLAYER_EVENT_CHANNEL
|
||||
import org.jellyfin.mobile.model.DisplayPreferences
|
||||
import org.jellyfin.mobile.app.PLAYER_EVENT_CHANNEL
|
||||
import org.jellyfin.mobile.player.ui.DisplayPreferences
|
||||
import org.jellyfin.mobile.player.interaction.PlayerEvent
|
||||
import org.jellyfin.mobile.player.interaction.PlayerLifecycleObserver
|
||||
import org.jellyfin.mobile.player.interaction.PlayerMediaSessionCallback
|
||||
import org.jellyfin.mobile.player.interaction.PlayerNotificationHelper
|
||||
import org.jellyfin.mobile.player.source.JellyfinMediaSource
|
||||
import org.jellyfin.mobile.player.source.MediaQueueManager
|
||||
import org.jellyfin.mobile.player.queue.QueueManager
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.Constants.SUPPORTED_VIDEO_PLAYER_PLAYBACK_ACTIONS
|
||||
import org.jellyfin.mobile.utils.applyDefaultAudioAttributes
|
||||
@ -39,11 +43,11 @@ import org.jellyfin.mobile.utils.applyDefaultLocalAudioAttributes
|
||||
import org.jellyfin.mobile.utils.getVolumeLevelPercent
|
||||
import org.jellyfin.mobile.utils.getVolumeRange
|
||||
import org.jellyfin.mobile.utils.logTracks
|
||||
import org.jellyfin.mobile.utils.scaleInRange
|
||||
import org.jellyfin.mobile.utils.extensions.scaleInRange
|
||||
import org.jellyfin.mobile.utils.seekToOffset
|
||||
import org.jellyfin.mobile.utils.setPlaybackState
|
||||
import org.jellyfin.mobile.utils.toMediaMetadata
|
||||
import org.jellyfin.mobile.utils.width
|
||||
import org.jellyfin.mobile.utils.extensions.width
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.api.client.exception.ApiClientException
|
||||
import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi
|
||||
@ -75,7 +79,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application),
|
||||
val notificationHelper: PlayerNotificationHelper by lazy { PlayerNotificationHelper(this) }
|
||||
|
||||
// Media source handling
|
||||
val mediaQueueManager = MediaQueueManager(this)
|
||||
val mediaQueueManager = QueueManager(this)
|
||||
val mediaSourceOrNull: JellyfinMediaSource?
|
||||
get() = mediaQueueManager.mediaQueue.value?.jellyfinMediaSource
|
||||
|
||||
@ -188,7 +192,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application),
|
||||
_player.value = null
|
||||
}
|
||||
|
||||
fun play(queueItem: MediaQueueManager.QueueItem.Loaded) {
|
||||
fun play(queueItem: QueueManager.QueueItem.Loaded) {
|
||||
val player = playerOrNull ?: return
|
||||
|
||||
player.setMediaSource(queueItem.exoMediaSource)
|
||||
@ -353,14 +357,14 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application),
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MediaQueueManager.selectAudioTrack
|
||||
* @see QueueManager.selectAudioTrack
|
||||
*/
|
||||
fun selectAudioTrack(streamIndex: Int): Boolean = mediaQueueManager.selectAudioTrack(streamIndex).also { success ->
|
||||
if (success) playerOrNull?.logTracks(analyticsCollector)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MediaQueueManager.selectSubtitle
|
||||
* @see QueueManager.selectSubtitle
|
||||
*/
|
||||
fun selectSubtitle(streamIndex: Int): Boolean = mediaQueueManager.selectSubtitle(streamIndex).also { success ->
|
||||
if (success) playerOrNull?.logTracks(analyticsCollector)
|
||||
|
@ -16,7 +16,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jellyfin.mobile.media
|
||||
package org.jellyfin.mobile.player.audio
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
@ -45,7 +45,7 @@ import org.koin.core.component.inject
|
||||
* A wrapper class for ExoPlayer's PlayerNotificationManager. It sets up the notification shown to
|
||||
* the user during audio playback and provides track metadata, such as track title and icon image.
|
||||
*/
|
||||
class MediaNotificationManager(
|
||||
class AudioNotificationManager(
|
||||
private val context: Context,
|
||||
sessionToken: MediaSessionCompat.Token,
|
||||
notificationListener: PlayerNotificationManager.NotificationListener
|
@ -1,6 +1,6 @@
|
||||
// Contains code adapted from https://github.com/android/uamp/blob/main/common/src/main/java/com/example/android/uamp/media/MediaService.kt
|
||||
|
||||
package org.jellyfin.mobile.media
|
||||
package org.jellyfin.mobile.player.audio
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
@ -36,11 +36,12 @@ import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.cast.CastPlayerProvider
|
||||
import org.jellyfin.mobile.cast.ICastPlayerProvider
|
||||
import org.jellyfin.mobile.controller.ApiController
|
||||
import org.jellyfin.mobile.media.car.LibraryBrowser
|
||||
import org.jellyfin.mobile.media.car.LibraryPage
|
||||
import org.jellyfin.mobile.player.cast.CastPlayerProvider
|
||||
import org.jellyfin.mobile.player.cast.ICastPlayerProvider
|
||||
import org.jellyfin.mobile.app.ApiClientController
|
||||
import org.jellyfin.mobile.player.audio.car.LibraryBrowser
|
||||
import org.jellyfin.mobile.player.audio.car.LibraryPage
|
||||
import org.jellyfin.mobile.utils.extensions.mediaUri
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.toast
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
@ -51,7 +52,7 @@ import timber.log.Timber
|
||||
import com.google.android.exoplayer2.MediaItem as ExoPlayerMediaItem
|
||||
|
||||
class MediaService : MediaBrowserServiceCompat() {
|
||||
private val apiController: ApiController by inject()
|
||||
private val apiClientController: ApiClientController by inject()
|
||||
private val apiClient: ApiClient by inject()
|
||||
private val libraryBrowser: LibraryBrowser by inject()
|
||||
|
||||
@ -64,7 +65,7 @@ class MediaService : MediaBrowserServiceCompat() {
|
||||
// remote playback through a Cast device).
|
||||
private lateinit var currentPlayer: Player
|
||||
|
||||
private lateinit var notificationManager: MediaNotificationManager
|
||||
private lateinit var notificationManager: AudioNotificationManager
|
||||
private lateinit var mediaController: MediaControllerCompat
|
||||
private lateinit var mediaSession: MediaSessionCompat
|
||||
private lateinit var mediaSessionConnector: MediaSessionConnector
|
||||
@ -98,7 +99,7 @@ class MediaService : MediaBrowserServiceCompat() {
|
||||
super.onCreate()
|
||||
|
||||
loadingJob = serviceScope.launch {
|
||||
apiController.loadSavedServerUser()
|
||||
apiClientController.loadSavedServerUser()
|
||||
}
|
||||
|
||||
val sessionActivityPendingIntent = packageManager?.getLaunchIntentForPackage(packageName)?.let { sessionIntent ->
|
||||
@ -112,7 +113,7 @@ class MediaService : MediaBrowserServiceCompat() {
|
||||
|
||||
sessionToken = mediaSession.sessionToken
|
||||
|
||||
notificationManager = MediaNotificationManager(
|
||||
notificationManager = AudioNotificationManager(
|
||||
this,
|
||||
mediaSession.sessionToken,
|
||||
PlayerNotificationListener()
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.media.car
|
||||
package org.jellyfin.mobile.player.audio.car
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
@ -12,17 +12,17 @@ import android.support.v4.media.MediaMetadataCompat
|
||||
import androidx.media.MediaBrowserServiceCompat
|
||||
import androidx.media.utils.MediaConstants
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.media.MediaService
|
||||
import org.jellyfin.mobile.media.mediaId
|
||||
import org.jellyfin.mobile.media.setAlbum
|
||||
import org.jellyfin.mobile.media.setAlbumArtUri
|
||||
import org.jellyfin.mobile.media.setAlbumArtist
|
||||
import org.jellyfin.mobile.media.setArtist
|
||||
import org.jellyfin.mobile.media.setDisplayIconUri
|
||||
import org.jellyfin.mobile.media.setMediaId
|
||||
import org.jellyfin.mobile.media.setMediaUri
|
||||
import org.jellyfin.mobile.media.setTitle
|
||||
import org.jellyfin.mobile.media.setTrackNumber
|
||||
import org.jellyfin.mobile.player.audio.MediaService
|
||||
import org.jellyfin.mobile.utils.extensions.mediaId
|
||||
import org.jellyfin.mobile.utils.extensions.setAlbum
|
||||
import org.jellyfin.mobile.utils.extensions.setAlbumArtUri
|
||||
import org.jellyfin.mobile.utils.extensions.setAlbumArtist
|
||||
import org.jellyfin.mobile.utils.extensions.setArtist
|
||||
import org.jellyfin.mobile.utils.extensions.setDisplayIconUri
|
||||
import org.jellyfin.mobile.utils.extensions.setMediaId
|
||||
import org.jellyfin.mobile.utils.extensions.setMediaUri
|
||||
import org.jellyfin.mobile.utils.extensions.setTitle
|
||||
import org.jellyfin.mobile.utils.extensions.setTrackNumber
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.api.client.exception.ApiClientException
|
||||
import org.jellyfin.sdk.api.client.extensions.genresApi
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.media.car
|
||||
package org.jellyfin.mobile.player.audio.car
|
||||
|
||||
object LibraryPage {
|
||||
/**
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast
|
||||
package org.jellyfin.mobile.player.cast
|
||||
|
||||
import com.google.android.exoplayer2.Player
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast
|
||||
package org.jellyfin.mobile.player.cast
|
||||
|
||||
import android.app.Activity
|
||||
import org.jellyfin.mobile.bridge.JavascriptCallback
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.deviceprofile
|
||||
|
||||
import android.media.MediaCodecInfo.CodecProfileLevel
|
||||
import android.media.MediaFormat
|
@ -1,12 +1,12 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.deviceprofile
|
||||
|
||||
import android.media.MediaCodecInfo.CodecCapabilities
|
||||
import android.util.Range
|
||||
import org.jellyfin.mobile.player.CodecHelpers.getAudioCodec
|
||||
import org.jellyfin.mobile.player.CodecHelpers.getAudioProfile
|
||||
import org.jellyfin.mobile.player.CodecHelpers.getVideoCodec
|
||||
import org.jellyfin.mobile.player.CodecHelpers.getVideoLevel
|
||||
import org.jellyfin.mobile.player.CodecHelpers.getVideoProfile
|
||||
import org.jellyfin.mobile.player.deviceprofile.CodecHelpers.getAudioCodec
|
||||
import org.jellyfin.mobile.player.deviceprofile.CodecHelpers.getAudioProfile
|
||||
import org.jellyfin.mobile.player.deviceprofile.CodecHelpers.getVideoCodec
|
||||
import org.jellyfin.mobile.player.deviceprofile.CodecHelpers.getVideoLevel
|
||||
import org.jellyfin.mobile.player.deviceprofile.CodecHelpers.getVideoProfile
|
||||
import java.util.*
|
||||
import kotlin.collections.HashSet
|
||||
import kotlin.math.max
|
@ -1,8 +1,7 @@
|
||||
package org.jellyfin.mobile.api
|
||||
package org.jellyfin.mobile.player.deviceprofile
|
||||
|
||||
import android.media.MediaCodecList
|
||||
import org.jellyfin.mobile.bridge.ExternalPlayer
|
||||
import org.jellyfin.mobile.player.DeviceCodec
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.sdk.model.api.CodecProfile
|
||||
import org.jellyfin.sdk.model.api.ContainerProfile
|
@ -1,8 +1,8 @@
|
||||
package org.jellyfin.mobile.bridge
|
||||
package org.jellyfin.mobile.player.interaction
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.jellyfin.mobile.utils.size
|
||||
import org.jellyfin.mobile.utils.extensions.size
|
||||
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.interaction
|
||||
|
||||
sealed class PlayerEvent {
|
||||
object Pause : PlayerEvent()
|
@ -1,7 +1,8 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.interaction
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import org.jellyfin.mobile.player.PlayerViewModel
|
||||
|
||||
class PlayerLifecycleObserver(private val viewModel: PlayerViewModel) : DefaultLifecycleObserver {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.interaction
|
||||
|
||||
import android.media.session.MediaSession
|
||||
import org.jellyfin.mobile.player.PlayerViewModel
|
||||
|
||||
class PlayerMediaSessionCallback(private val viewModel: PlayerViewModel) : MediaSession.Callback() {
|
||||
override fun onPlay() {
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.interaction
|
||||
|
||||
import android.app.Application
|
||||
import android.app.Notification
|
||||
@ -20,10 +20,11 @@ import com.google.android.exoplayer2.Player
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.BuildConfig
|
||||
import org.jellyfin.mobile.MainActivity
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.player.PlayerViewModel
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.Constants.VIDEO_PLAYER_NOTIFICATION_ID
|
||||
import org.jellyfin.mobile.utils.createMediaNotificationChannel
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player.source
|
||||
package org.jellyfin.mobile.player.queue
|
||||
|
||||
import android.app.Application
|
||||
import android.net.Uri
|
||||
@ -13,9 +13,11 @@ import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
||||
import com.google.android.exoplayer2.source.SingleSampleMediaSource
|
||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||
import org.jellyfin.mobile.bridge.PlayOptions
|
||||
import org.jellyfin.mobile.player.interaction.PlayOptions
|
||||
import org.jellyfin.mobile.player.PlayerException
|
||||
import org.jellyfin.mobile.player.PlayerViewModel
|
||||
import org.jellyfin.mobile.player.source.JellyfinMediaSource
|
||||
import org.jellyfin.mobile.player.source.MediaSourceResolver
|
||||
import org.jellyfin.mobile.utils.clearSelectionAndDisableRendererByType
|
||||
import org.jellyfin.mobile.utils.selectTrackByTypeAndGroup
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
@ -30,7 +32,7 @@ import org.koin.core.component.get
|
||||
import org.koin.core.component.inject
|
||||
import java.util.UUID
|
||||
|
||||
class MediaQueueManager(
|
||||
class QueueManager(
|
||||
private val viewModel: PlayerViewModel,
|
||||
) : KoinComponent {
|
||||
private val apiClient: ApiClient = get()
|
@ -1,6 +1,6 @@
|
||||
package org.jellyfin.mobile.player.source
|
||||
|
||||
import org.jellyfin.mobile.player.CodecHelpers
|
||||
import org.jellyfin.mobile.player.deviceprofile.CodecHelpers
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.model
|
||||
package org.jellyfin.mobile.player.ui
|
||||
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PictureInPictureParams
|
||||
@ -28,20 +28,22 @@ import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.ui.PlayerView
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.api.aspectRational
|
||||
import org.jellyfin.mobile.api.isLandscape
|
||||
import org.jellyfin.mobile.bridge.PlayOptions
|
||||
import org.jellyfin.mobile.utils.extensions.aspectRational
|
||||
import org.jellyfin.mobile.utils.extensions.isLandscape
|
||||
import org.jellyfin.mobile.player.interaction.PlayOptions
|
||||
import org.jellyfin.mobile.databinding.ExoPlayerControlViewBinding
|
||||
import org.jellyfin.mobile.databinding.FragmentPlayerBinding
|
||||
import org.jellyfin.mobile.player.PlayerException
|
||||
import org.jellyfin.mobile.player.PlayerViewModel
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.Constants.DEFAULT_CONTROLS_TIMEOUT_MS
|
||||
import org.jellyfin.mobile.utils.Constants.PIP_MAX_RATIONAL
|
||||
import org.jellyfin.mobile.utils.Constants.PIP_MIN_RATIONAL
|
||||
import org.jellyfin.mobile.utils.SmartOrientationListener
|
||||
import org.jellyfin.mobile.utils.brightness
|
||||
import org.jellyfin.mobile.utils.disableFullscreen
|
||||
import org.jellyfin.mobile.utils.enableFullscreen
|
||||
import org.jellyfin.mobile.utils.isFullscreen
|
||||
import org.jellyfin.mobile.utils.extensions.disableFullscreen
|
||||
import org.jellyfin.mobile.utils.extensions.enableFullscreen
|
||||
import org.jellyfin.mobile.utils.extensions.isFullscreen
|
||||
import org.jellyfin.mobile.utils.toast
|
||||
import org.jellyfin.sdk.model.api.MediaStream
|
||||
|
||||
@ -57,7 +59,7 @@ class PlayerFragment : Fragment() {
|
||||
private val playerControlsView: View get() = playerControlsBinding.root
|
||||
private val titleTextView: TextView get() = playerControlsBinding.trackTitle
|
||||
private val fullscreenSwitcher: ImageButton get() = playerControlsBinding.fullscreenSwitcher
|
||||
private var playbackMenus: PlaybackMenus? = null
|
||||
private var playerMenus: PlayerMenus? = null
|
||||
|
||||
lateinit var playerLockScreenHelper: PlayerLockScreenHelper
|
||||
lateinit var playerGestureHelper: PlayerGestureHelper
|
||||
@ -108,7 +110,7 @@ class PlayerFragment : Fragment() {
|
||||
|
||||
// Update title and player menus
|
||||
titleTextView.text = jellyfinMediaSource.name
|
||||
playbackMenus?.onQueueItemChanged(queueItem)
|
||||
playerMenus?.onQueueItemChanged(queueItem)
|
||||
}
|
||||
|
||||
// Handle fragment arguments, extract playback options and start playback
|
||||
@ -156,7 +158,7 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
|
||||
// Create playback menus
|
||||
playbackMenus = PlaybackMenus(this, playerBinding, playerControlsBinding)
|
||||
playerMenus = PlayerMenus(this, playerBinding, playerControlsBinding)
|
||||
|
||||
// Set controller timeout
|
||||
suppressControllerAutoHide(false)
|
||||
@ -318,7 +320,7 @@ class PlayerFragment : Fragment() {
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
||||
playerView.useController = !isInPictureInPictureMode
|
||||
if (isInPictureInPictureMode) {
|
||||
playbackMenus?.dismissPlaybackInfo()
|
||||
playerMenus?.dismissPlaybackInfo()
|
||||
playerLockScreenHelper.hideUnlockButton()
|
||||
}
|
||||
}
|
||||
@ -344,7 +346,7 @@ class PlayerFragment : Fragment() {
|
||||
// Set binding references to null
|
||||
_playerBinding = null
|
||||
_playerControlsBinding = null
|
||||
playbackMenus = null
|
||||
playerMenus = null
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.media.AudioManager
|
||||
@ -16,7 +16,7 @@ import androidx.core.view.isVisible
|
||||
import androidx.core.view.postDelayed
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||
import com.google.android.exoplayer2.ui.PlayerView
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.databinding.FragmentPlayerBinding
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.brightness
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.ui
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Build
|
||||
@ -9,7 +9,7 @@ import com.google.android.exoplayer2.ui.PlayerView
|
||||
import org.jellyfin.mobile.databinding.FragmentPlayerBinding
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.isAutoRotateOn
|
||||
import org.jellyfin.mobile.utils.lockOrientation
|
||||
import org.jellyfin.mobile.utils.extensions.lockOrientation
|
||||
|
||||
class PlayerLockScreenHelper(
|
||||
private val playerFragment: PlayerFragment,
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.player
|
||||
package org.jellyfin.mobile.player.ui
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
@ -12,14 +12,14 @@ import androidx.core.view.isVisible
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.databinding.ExoPlayerControlViewBinding
|
||||
import org.jellyfin.mobile.databinding.FragmentPlayerBinding
|
||||
import org.jellyfin.mobile.player.source.MediaQueueManager
|
||||
import org.jellyfin.mobile.player.queue.QueueManager
|
||||
import org.jellyfin.sdk.model.api.MediaStream
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Provides a menu UI for audio, subtitle and video stream selection
|
||||
*/
|
||||
class PlaybackMenus(
|
||||
class PlayerMenus(
|
||||
private val fragment: PlayerFragment,
|
||||
private val playerBinding: FragmentPlayerBinding,
|
||||
private val playerControlsBinding: ExoPlayerControlViewBinding
|
||||
@ -79,7 +79,7 @@ class PlaybackMenus(
|
||||
}
|
||||
}
|
||||
|
||||
fun onQueueItemChanged(queueItem: MediaQueueManager.QueueItem.Loaded) {
|
||||
fun onQueueItemChanged(queueItem: QueueManager.QueueItem.Loaded) {
|
||||
nextButton.isEnabled = queueItem.hasNext()
|
||||
|
||||
val mediaSource = queueItem.jellyfinMediaSource
|
||||
@ -152,7 +152,7 @@ class PlaybackMenus(
|
||||
}
|
||||
}
|
||||
}
|
||||
setOnDismissListener(this@PlaybackMenus)
|
||||
setOnDismissListener(this@PlayerMenus)
|
||||
}
|
||||
|
||||
private fun createAudioStreamsMenu() = PopupMenu(context, audioStreamsButton).apply {
|
||||
@ -167,7 +167,7 @@ class PlaybackMenus(
|
||||
}
|
||||
}
|
||||
}
|
||||
setOnDismissListener(this@PlaybackMenus)
|
||||
setOnDismissListener(this@PlayerMenus)
|
||||
}
|
||||
|
||||
private fun createSpeedMenu() = PopupMenu(context, speedButton).apply {
|
||||
@ -186,7 +186,7 @@ class PlaybackMenus(
|
||||
}
|
||||
}
|
||||
}
|
||||
setOnDismissListener(this@PlaybackMenus)
|
||||
setOnDismissListener(this@PlayerMenus)
|
||||
}
|
||||
|
||||
private fun buildMenuItems(menu: Menu, groupId: Int, mediaStreams: List<MediaStream>, selectedStream: MediaStream?, showNone: Boolean = false) {
|
@ -16,14 +16,14 @@ import de.Maxr1998.modernpreferences.helpers.screen
|
||||
import de.Maxr1998.modernpreferences.helpers.singleChoice
|
||||
import de.Maxr1998.modernpreferences.preferences.CheckBoxPreference
|
||||
import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.databinding.FragmentSettingsBinding
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.applyWindowInsetsAsMargins
|
||||
import org.jellyfin.mobile.utils.getDownloadsPaths
|
||||
import org.jellyfin.mobile.utils.isPackageInstalled
|
||||
import org.jellyfin.mobile.utils.requireMainActivity
|
||||
import org.jellyfin.mobile.utils.extensions.requireMainActivity
|
||||
import org.jellyfin.mobile.utils.withThemedContext
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.fragment
|
||||
package org.jellyfin.mobile.setup
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.os.Bundle
|
||||
@ -23,11 +23,11 @@ import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.controller.ApiController
|
||||
import org.jellyfin.mobile.app.ApiClientController
|
||||
import org.jellyfin.mobile.databinding.FragmentConnectBinding
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.applyWindowInsetsAsMargins
|
||||
import org.jellyfin.mobile.viewmodel.MainViewModel
|
||||
import org.jellyfin.mobile.MainViewModel
|
||||
import org.jellyfin.sdk.Jellyfin
|
||||
import org.jellyfin.sdk.discovery.LocalServerDiscovery
|
||||
import org.jellyfin.sdk.discovery.RecommendedServerInfo
|
||||
@ -40,7 +40,7 @@ import timber.log.Timber
|
||||
class ConnectFragment : Fragment() {
|
||||
private val mainViewModel: MainViewModel by sharedViewModel()
|
||||
private val jellyfin: Jellyfin by inject()
|
||||
private val apiController: ApiController by inject()
|
||||
private val apiClientController: ApiClientController by inject()
|
||||
|
||||
// UI
|
||||
private var _connectServerBinding: FragmentConnectBinding? = null
|
||||
@ -118,7 +118,7 @@ class ConnectFragment : Fragment() {
|
||||
val httpUrl = checkServerUrlAndConnection(enteredUrl)
|
||||
if (httpUrl != null) {
|
||||
serverList.clear()
|
||||
apiController.setupServer(httpUrl)
|
||||
apiClientController.setupServer(httpUrl)
|
||||
mainViewModel.refreshServer()
|
||||
}
|
||||
hostInput.isEnabled = true
|
@ -13,6 +13,7 @@ import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.analytics.AnalyticsCollector
|
||||
import org.jellyfin.mobile.player.source.JellyfinMediaSource
|
||||
import org.jellyfin.mobile.utils.extensions.width
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes as ExoPlayerAudioAttributes
|
||||
|
||||
inline fun MediaSession.applyDefaultLocalAudioAttributes(contentType: Int) {
|
||||
|
@ -24,10 +24,10 @@ import androidx.core.content.getSystemService
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.BuildConfig
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.fragment.WebViewFragment
|
||||
import org.jellyfin.mobile.webapp.WebViewFragment
|
||||
import org.jellyfin.mobile.settings.ExternalPlayerPackage
|
||||
import org.koin.android.ext.android.get
|
||||
import timber.log.Timber
|
||||
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.jellyfin.mobile.utils
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.pm.ActivityInfo
|
@ -0,0 +1,8 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.jellyfin.mobile.MainActivity
|
||||
|
||||
inline fun Fragment.requireMainActivity(): MainActivity = requireActivity() as MainActivity
|
@ -1,13 +1,12 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package org.jellyfin.mobile.utils
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.add
|
||||
import androidx.fragment.app.replace
|
||||
import org.jellyfin.mobile.MainActivity
|
||||
import org.jellyfin.mobile.R
|
||||
|
||||
inline fun <reified T : Fragment> FragmentManager.addFragment() {
|
||||
@ -20,5 +19,3 @@ inline fun <reified T : Fragment> FragmentManager.addFragment() {
|
||||
inline fun <reified T : Fragment> FragmentManager.replaceFragment(args: Bundle? = null) {
|
||||
beginTransaction().replace<T>(R.id.fragment_container, args = args).commit()
|
||||
}
|
||||
|
||||
inline fun Fragment.requireMainActivity(): MainActivity = requireActivity() as MainActivity
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package org.jellyfin.mobile.utils
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
|
||||
@ -12,12 +12,3 @@ inline fun Int.withFlag(flag: Int) = this or flag
|
||||
|
||||
@CheckResult
|
||||
inline fun Int.withoutFlag(flag: Int) = this and flag.inv()
|
||||
|
||||
@get:CheckResult
|
||||
val IntRange.width: Int
|
||||
get() = endInclusive - start
|
||||
|
||||
@CheckResult
|
||||
fun IntRange.scaleInRange(percent: Int): Int {
|
||||
return start + width * percent / Constants.PERCENT_MAX
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
|
||||
@get:CheckResult
|
||||
val IntRange.width: Int
|
||||
get() = endInclusive - start
|
||||
|
||||
@CheckResult
|
||||
fun IntRange.scaleInRange(percent: Int): Int {
|
||||
return start + width * percent / Constants.PERCENT_MAX
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.utils
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import org.json.JSONArray
|
||||
|
@ -1,15 +1,12 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package org.jellyfin.mobile.media
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.support.v4.media.MediaMetadataCompat
|
||||
import androidx.core.net.toUri
|
||||
|
||||
/**
|
||||
* Useful extensions for [MediaMetadataCompat].
|
||||
*/
|
||||
inline val MediaMetadataCompat.mediaId: String?
|
||||
get() = getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID)
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.api
|
||||
package org.jellyfin.mobile.utils.extensions
|
||||
|
||||
import android.util.Rational
|
||||
import org.jellyfin.sdk.model.api.MediaStream
|
@ -31,7 +31,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.MainActivity
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.fragment
|
||||
package org.jellyfin.mobile.webapp
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
@ -36,20 +36,21 @@ import androidx.webkit.WebViewCompat
|
||||
import androidx.webkit.WebViewFeature
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.app.AppPreferences
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.bridge.ExternalPlayer
|
||||
import org.jellyfin.mobile.bridge.NativeInterface
|
||||
import org.jellyfin.mobile.bridge.NativePlayer
|
||||
import org.jellyfin.mobile.bridge.NativePlayerHost
|
||||
import org.jellyfin.mobile.bridge.PlayOptions
|
||||
import org.jellyfin.mobile.controller.ApiController
|
||||
import org.jellyfin.mobile.player.interaction.PlayOptions
|
||||
import org.jellyfin.mobile.app.ApiClientController
|
||||
import org.jellyfin.mobile.databinding.FragmentWebviewBinding
|
||||
import org.jellyfin.mobile.model.sql.entity.ServerEntity
|
||||
import org.jellyfin.mobile.player.PlayerFragment
|
||||
import org.jellyfin.mobile.setup.ConnectFragment
|
||||
import org.jellyfin.mobile.data.entity.ServerEntity
|
||||
import org.jellyfin.mobile.player.ui.PlayerFragment
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.Constants.FRAGMENT_WEB_VIEW_EXTRA_SERVER
|
||||
import org.jellyfin.mobile.utils.addFragment
|
||||
import org.jellyfin.mobile.utils.extensions.addFragment
|
||||
import org.jellyfin.mobile.utils.applyDefault
|
||||
import org.jellyfin.mobile.utils.applyWindowInsetsAsMargins
|
||||
import org.jellyfin.mobile.utils.dip
|
||||
@ -57,10 +58,9 @@ import org.jellyfin.mobile.utils.fadeIn
|
||||
import org.jellyfin.mobile.utils.initLocale
|
||||
import org.jellyfin.mobile.utils.inject
|
||||
import org.jellyfin.mobile.utils.isOutdated
|
||||
import org.jellyfin.mobile.utils.replaceFragment
|
||||
import org.jellyfin.mobile.utils.extensions.replaceFragment
|
||||
import org.jellyfin.mobile.utils.requestNoBatteryOptimizations
|
||||
import org.jellyfin.mobile.utils.runOnUiThread
|
||||
import org.jellyfin.mobile.webapp.WebappFunctionChannel
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.koin.android.ext.android.inject
|
||||
@ -73,7 +73,7 @@ import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class WebViewFragment : Fragment(), NativePlayerHost {
|
||||
val appPreferences: AppPreferences by inject()
|
||||
private val apiController: ApiController by inject()
|
||||
private val apiClientController: ApiClientController by inject()
|
||||
private val webappFunctionChannel: WebappFunctionChannel by inject()
|
||||
private lateinit var assetsPathHandler: AssetsPathHandler
|
||||
private lateinit var externalPlayer: ExternalPlayer
|
||||
@ -194,7 +194,7 @@ class WebViewFragment : Fragment(), NativePlayerHost {
|
||||
val storedServer = credentials.getJSONArray("Servers").getJSONObject(0)
|
||||
val user = storedServer.getString("UserId")
|
||||
val token = storedServer.getString("AccessToken")
|
||||
apiController.setupUser(server.id, user, token)
|
||||
apiClientController.setupUser(server.id, user, token)
|
||||
webView.initLocale(user)
|
||||
}
|
||||
null
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast
|
||||
package org.jellyfin.mobile.player.cast
|
||||
|
||||
import android.content.Context
|
||||
import com.google.android.gms.cast.framework.CastOptions
|
@ -1,10 +1,10 @@
|
||||
package org.jellyfin.mobile.cast
|
||||
package org.jellyfin.mobile.player.cast
|
||||
|
||||
import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.ext.cast.CastPlayer
|
||||
import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
import org.jellyfin.mobile.media.MediaService
|
||||
import org.jellyfin.mobile.player.audio.MediaService
|
||||
|
||||
class CastPlayerProvider(private val mediaService: MediaService) : ICastPlayerProvider, SessionAvailabilityListener {
|
||||
private val castPlayer: CastPlayer? = try {
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast;
|
||||
package org.jellyfin.mobile.player.cast;
|
||||
|
||||
import android.app.Activity;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast;
|
||||
package org.jellyfin.mobile.player.cast;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
@ -24,6 +24,7 @@ import com.google.android.gms.cast.framework.SessionManagerListener;
|
||||
|
||||
import org.jellyfin.mobile.R;
|
||||
import org.jellyfin.mobile.bridge.JavascriptCallback;
|
||||
import org.jellyfin.mobile.player.cast.CastOptionsProvider;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast;
|
||||
package org.jellyfin.mobile.player.cast;
|
||||
|
||||
import android.app.Activity;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.jellyfin.mobile.cast;
|
||||
package org.jellyfin.mobile.player.cast;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Color;
|
Loading…
x
Reference in New Issue
Block a user