Skip to content
Merged
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
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import java.util.Properties
import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

val appVersionCode = 140
val appVersionName = "3.4.4"
val appVersionCode = 141
val appVersionName = "3.4.5"

plugins {
alias(libs.plugins.android.application)
Expand Down
43 changes: 7 additions & 36 deletions app/src/main/java/com/example/xtreamplayer/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,25 @@ package com.example.xtreamplayer
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.xtreamplayer.content.ContentRepository
import com.example.xtreamplayer.content.ContinueWatchingRepository
import com.example.xtreamplayer.content.FavoritesRepository
import com.example.xtreamplayer.content.HistoryRepository
import com.example.xtreamplayer.content.SubtitleRepository
import com.example.xtreamplayer.player.Media3PlaybackEngine
import com.example.xtreamplayer.settings.PlaybackSettingsController
import com.example.xtreamplayer.di.RootScreenEntryPoint
import dagger.hilt.android.AndroidEntryPoint
import okhttp3.OkHttpClient
import javax.inject.Inject
import dagger.hilt.android.EntryPointAccessors

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject lateinit var playbackSettingsController: PlaybackSettingsController

@Inject lateinit var playbackEngine: Media3PlaybackEngine

@Inject lateinit var contentRepository: ContentRepository

@Inject lateinit var favoritesRepository: FavoritesRepository

@Inject lateinit var historyRepository: HistoryRepository

@Inject lateinit var continueWatchingRepository: ContinueWatchingRepository

@Inject lateinit var subtitleRepository: SubtitleRepository

@Inject lateinit var okHttpClient: OkHttpClient

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
RootScreen(
playbackSettingsController = playbackSettingsController,
playbackEngine = playbackEngine,
contentRepository = contentRepository,
favoritesRepository = favoritesRepository,
historyRepository = historyRepository,
continueWatchingRepository = continueWatchingRepository,
subtitleRepository = subtitleRepository,
updateHttpClient = okHttpClient
)
RootScreen()
}
}

override fun onDestroy() {
if (isFinishing) {
playbackEngine.release()
EntryPointAccessors.fromApplication(
applicationContext,
RootScreenEntryPoint::class.java
).playbackEngine().release()
}
super.onDestroy()
}
Expand Down
48 changes: 34 additions & 14 deletions app/src/main/java/com/example/xtreamplayer/MainActivityUi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,13 @@ import com.example.xtreamplayer.content.SeriesInfo
import com.example.xtreamplayer.content.SearchNormalizer
import com.example.xtreamplayer.content.SubtitleRepository
import com.example.xtreamplayer.content.shouldStoreContinueWatchingEntry
import com.example.xtreamplayer.di.RootScreenEntryPoint
import com.example.xtreamplayer.observability.AppDiagnostics
import com.example.xtreamplayer.player.Media3PlaybackEngine
import com.example.xtreamplayer.player.BufferProfile
import com.example.xtreamplayer.settings.PlaybackSettingsController
import com.example.xtreamplayer.settings.ClockFormatOption
import com.example.xtreamplayer.settings.SettingsRepository
import com.example.xtreamplayer.settings.SettingsState
import com.example.xtreamplayer.settings.SettingsViewModel
import com.example.xtreamplayer.settings.SubtitleAppearanceSettings
Expand Down Expand Up @@ -193,8 +195,8 @@ import com.example.xtreamplayer.ui.theme.AppColors
import com.example.xtreamplayer.ui.theme.XtreamPlayerTheme
import com.example.xtreamplayer.viewmodel.BrowseViewModel
import com.example.xtreamplayer.viewmodel.PlayerViewModel
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import com.example.xtreamplayer.viewmodel.UpdateViewModel
import dagger.hilt.android.EntryPointAccessors
import java.util.Locale
import java.io.File
import android.provider.Settings
Expand All @@ -209,7 +211,6 @@ import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withContext
import timber.log.Timber
import kotlin.LazyThreadSafetyMode
import kotlin.math.max
import kotlin.math.min

Expand All @@ -226,7 +227,7 @@ private enum class UpdateCheckSource {
STARTUP
}

private data class UpdateUiState(
data class UpdateUiState(
val showDialog: Boolean = false,
val inProgress: Boolean = false,
val pendingRelease: UpdateRelease? = null
Expand Down Expand Up @@ -255,14 +256,37 @@ private const val PLAYBACK_PROGRESS_SAVE_INTERVAL_MS = 30_000L
private const val STARTUP_DEFER_NON_CRITICAL_MS = 1_000L

@Composable
fun RootScreen(
fun RootScreen() {
val context = LocalContext.current
val rootScreenEntryPoint = remember(context.applicationContext) {
EntryPointAccessors.fromApplication(
context.applicationContext,
RootScreenEntryPoint::class.java
)
}
RootScreenContent(
playbackSettingsController = rootScreenEntryPoint.playbackSettingsController(),
playbackEngine = rootScreenEntryPoint.playbackEngine(),
contentRepository = rootScreenEntryPoint.contentRepository(),
favoritesRepository = rootScreenEntryPoint.favoritesRepository(),
historyRepository = rootScreenEntryPoint.historyRepository(),
continueWatchingRepository = rootScreenEntryPoint.continueWatchingRepository(),
subtitleRepository = rootScreenEntryPoint.subtitleRepository(),
settingsRepository = rootScreenEntryPoint.settingsRepository(),
updateHttpClient = rootScreenEntryPoint.okHttpClient()
)
}

@Composable
private fun RootScreenContent(
playbackSettingsController: PlaybackSettingsController,
playbackEngine: Media3PlaybackEngine,
contentRepository: ContentRepository,
favoritesRepository: FavoritesRepository,
historyRepository: HistoryRepository,
continueWatchingRepository: ContinueWatchingRepository,
subtitleRepository: SubtitleRepository,
settingsRepository: SettingsRepository,
updateHttpClient: OkHttpClient
) {
val context = LocalContext.current
Expand All @@ -287,6 +311,7 @@ fun RootScreen(
val authViewModel: AuthViewModel = hiltViewModel()
val browseViewModel: BrowseViewModel = hiltViewModel()
val playerViewModel: PlayerViewModel = hiltViewModel()
val updateViewModel: UpdateViewModel = hiltViewModel()
val authState by authViewModel.uiState.collectAsStateWithLifecycle()
val savedConfig by authViewModel.savedConfig.collectAsStateWithLifecycle()
val savedConfigLoaded by authViewModel.savedConfigLoaded.collectAsStateWithLifecycle()
Expand All @@ -310,10 +335,10 @@ fun RootScreen(
var focusManageListsOnSettingsReturn by remember { mutableStateOf(false) }
var wasShowingAppearance by remember { mutableStateOf(false) }
var wasShowingManageLists by remember { mutableStateOf(false) }
var updateUiState by remember { mutableStateOf(UpdateUiState()) }
var updateCheckJob by remember { mutableStateOf<Job?>(null) }
var startupUpdateCheckEnabled by remember { mutableStateOf<Boolean?>(null) }
var startupUpdateCheckHandled by remember { mutableStateOf(false) }
var updateUiState by updateViewModel.updateUiState
var updateCheckJob by updateViewModel.updateCheckJob
var startupUpdateCheckEnabled by updateViewModel.startupUpdateCheckEnabled
var startupUpdateCheckHandled by updateViewModel.startupUpdateCheckHandled
val showApiKeyDialogState = remember { mutableStateOf(false) }
var showApiKeyDialog by showApiKeyDialogState
val showThemeDialogState = remember { mutableStateOf(false) }
Expand Down Expand Up @@ -369,11 +394,6 @@ fun RootScreen(
}

// Progressive sync coordinator
val settingsRepository by remember {
lazy(LazyThreadSafetyMode.NONE) {
com.example.xtreamplayer.settings.SettingsRepository(context)
}
}
LaunchedEffect(settings.subtitleCacheAutoClearIntervalMs, startupDeferredReady) {
if (!startupDeferredReady) {
return@LaunchedEffect
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.example.xtreamplayer.di

import com.example.xtreamplayer.content.ContentRepository
import com.example.xtreamplayer.content.ContinueWatchingRepository
import com.example.xtreamplayer.content.FavoritesRepository
import com.example.xtreamplayer.content.HistoryRepository
import com.example.xtreamplayer.content.SubtitleRepository
import com.example.xtreamplayer.player.Media3PlaybackEngine
import com.example.xtreamplayer.settings.PlaybackSettingsController
import com.example.xtreamplayer.settings.SettingsRepository
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient

@EntryPoint
@InstallIn(SingletonComponent::class)
interface RootScreenEntryPoint {
fun playbackSettingsController(): PlaybackSettingsController
fun playbackEngine(): Media3PlaybackEngine
fun contentRepository(): ContentRepository
fun favoritesRepository(): FavoritesRepository
fun historyRepository(): HistoryRepository
fun continueWatchingRepository(): ContinueWatchingRepository
fun subtitleRepository(): SubtitleRepository
fun settingsRepository(): SettingsRepository
fun okHttpClient(): OkHttpClient
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.xtreamplayer.viewmodel

import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import com.example.xtreamplayer.UpdateUiState
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.Job

@HiltViewModel
class UpdateViewModel @Inject constructor() : ViewModel() {
val updateUiState = mutableStateOf(UpdateUiState())
val updateCheckJob = mutableStateOf<Job?>(null)
val startupUpdateCheckEnabled = mutableStateOf<Boolean?>(null)
val startupUpdateCheckHandled = mutableStateOf(false)
}
4 changes: 4 additions & 0 deletions release-notes-3.4.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Changes:
- Refactored root screen dependency wiring through a Hilt entry point.
- Moved update dialog and startup-check state into a Hilt ViewModel.
- Kept player engine release handling in the activity teardown path.
Loading