refactor: replace SharedFlows with Channels for sending events

This commit is contained in:
Jarne Demeulemeester 2023-11-06 23:42:00 +01:00
parent 6c3360f8e7
commit 218b4f1af4
No known key found for this signature in database
GPG key ID: 1E5C6AFBD622E9F5
22 changed files with 170 additions and 116 deletions

View file

@ -42,6 +42,7 @@ import dev.jdtech.jellyfin.mpv.TrackType
import dev.jdtech.jellyfin.utils.PlayerGestureHelper
import dev.jdtech.jellyfin.utils.PreviewScrubListener
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
import dev.jdtech.jellyfin.viewmodels.PlayerEvents
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@ -169,8 +170,10 @@ class PlayerActivity : BasePlayerActivity() {
}
launch {
viewModel.navigateBack.collect {
if (it) finish()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is PlayerEvents.NavigateBack -> finish()
}
}
}
}

View file

@ -17,6 +17,7 @@ import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
import dev.jdtech.jellyfin.adapters.DiscoveredServerListAdapter
import dev.jdtech.jellyfin.databinding.FragmentAddServerBinding
import dev.jdtech.jellyfin.viewmodels.AddServerEvent
import dev.jdtech.jellyfin.viewmodels.AddServerViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -81,9 +82,9 @@ class AddServerFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.navigateToLogin.collect {
if (it) {
navigateToLoginFragment()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is AddServerEvent.NavigateToLogin -> navigateToLoginFragment()
}
}
}

View file

@ -20,6 +20,7 @@ import dev.jdtech.jellyfin.models.FindroidItem
import dev.jdtech.jellyfin.models.FindroidMovie
import dev.jdtech.jellyfin.models.FindroidShow
import dev.jdtech.jellyfin.utils.restart
import dev.jdtech.jellyfin.viewmodels.DownloadsEvent
import dev.jdtech.jellyfin.viewmodels.DownloadsViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -48,14 +49,18 @@ class DownloadsFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.connectionError.collect {
Snackbar.make(binding.root, CoreR.string.no_server_connection, Snackbar.LENGTH_INDEFINITE)
.setTextMaxLines(2)
.setAction(CoreR.string.offline_mode) {
appPreferences.offlineMode = true
activity?.restart()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is DownloadsEvent.ConnectionError -> {
Snackbar.make(binding.root, CoreR.string.no_server_connection, Snackbar.LENGTH_INDEFINITE)
.setTextMaxLines(2)
.setAction(CoreR.string.offline_mode) {
appPreferences.offlineMode = true
activity?.restart()
}
.show()
}
.show()
}
}
}
launch {

View file

@ -33,6 +33,7 @@ import dev.jdtech.jellyfin.models.UiText
import dev.jdtech.jellyfin.models.isDownloaded
import dev.jdtech.jellyfin.models.isDownloading
import dev.jdtech.jellyfin.utils.setIconTintColorAttribute
import dev.jdtech.jellyfin.viewmodels.EpisodeBottomSheetEvent
import dev.jdtech.jellyfin.viewmodels.EpisodeBottomSheetViewModel
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
import kotlinx.coroutines.launch
@ -122,14 +123,11 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
}
launch {
viewModel.downloadError.collect { uiText ->
createErrorDialog(uiText)
}
}
launch {
viewModel.navigateBack.collect {
if (it) findNavController().navigateUp()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is EpisodeBottomSheetEvent.NavigateBack -> findNavController().navigateUp()
is EpisodeBottomSheetEvent.DownloadError -> createErrorDialog(event.uiText)
}
}
}
}

View file

@ -19,6 +19,7 @@ import dev.jdtech.jellyfin.AppPreferences
import dev.jdtech.jellyfin.adapters.UserLoginListAdapter
import dev.jdtech.jellyfin.database.ServerDatabaseDao
import dev.jdtech.jellyfin.databinding.FragmentLoginBinding
import dev.jdtech.jellyfin.viewmodels.LoginEvent
import dev.jdtech.jellyfin.viewmodels.LoginViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -123,9 +124,9 @@ class LoginFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.navigateToMain.collect {
if (it) {
navigateToHomeFragment()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is LoginEvent.NavigateToHome -> navigateToHomeFragment()
}
}
}

View file

@ -37,6 +37,7 @@ import dev.jdtech.jellyfin.models.isDownloaded
import dev.jdtech.jellyfin.models.isDownloading
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
import dev.jdtech.jellyfin.utils.setIconTintColorAttribute
import dev.jdtech.jellyfin.viewmodels.MovieEvent
import dev.jdtech.jellyfin.viewmodels.MovieViewModel
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
import kotlinx.coroutines.launch
@ -118,14 +119,11 @@ class MovieFragment : Fragment() {
}
launch {
viewModel.downloadError.collect { uiText ->
createErrorDialog(uiText)
}
}
launch {
viewModel.navigateBack.collect {
if (it) findNavController().navigateUp()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is MovieEvent.NavigateBack -> findNavController().navigateUp()
is MovieEvent.DownloadError -> createErrorDialog(event.uiText)
}
}
}
}

View file

@ -20,6 +20,7 @@ import dev.jdtech.jellyfin.models.FindroidEpisode
import dev.jdtech.jellyfin.models.PlayerItem
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
import dev.jdtech.jellyfin.viewmodels.SeasonEvent
import dev.jdtech.jellyfin.viewmodels.SeasonViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -60,8 +61,10 @@ class SeasonFragment : Fragment() {
}
launch {
viewModel.navigateBack.collect {
if (it) findNavController().navigateUp()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is SeasonEvent.NavigateBack -> findNavController().navigateUp()
}
}
}
}

View file

@ -16,6 +16,7 @@ import dev.jdtech.jellyfin.adapters.ServerAddressAdapter
import dev.jdtech.jellyfin.databinding.FragmentServerAddressesBinding
import dev.jdtech.jellyfin.dialogs.AddServerAddressDialog
import dev.jdtech.jellyfin.dialogs.DeleteServerAddressDialog
import dev.jdtech.jellyfin.viewmodels.ServerAddressesEvent
import dev.jdtech.jellyfin.viewmodels.ServerAddressesViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -57,9 +58,9 @@ class ServerAddressesFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.navigateToMain.collect {
if (it) {
navigateToMainActivity()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is ServerAddressesEvent.NavigateToHome -> navigateToMainActivity()
}
}
}

View file

@ -14,6 +14,7 @@ import dagger.hilt.android.AndroidEntryPoint
import dev.jdtech.jellyfin.adapters.ServerGridAdapter
import dev.jdtech.jellyfin.databinding.FragmentServerSelectBinding
import dev.jdtech.jellyfin.dialogs.DeleteServerDialogFragment
import dev.jdtech.jellyfin.viewmodels.ServerSelectEvent
import dev.jdtech.jellyfin.viewmodels.ServerSelectViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -61,13 +62,11 @@ class ServerSelectFragment : Fragment() {
}
}
launch {
viewModel.navigateToMain.collect {
if (it) navigateToMainActivity()
}
}
launch {
viewModel.navigateToLogin.collect {
if (it) navigateToLoginFragment()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is ServerSelectEvent.NavigateToHome -> navigateToMainActivity()
is ServerSelectEvent.NavigateToLogin -> navigateToLoginFragment()
}
}
}
}

View file

@ -32,6 +32,7 @@ import dev.jdtech.jellyfin.models.isDownloaded
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
import dev.jdtech.jellyfin.utils.setIconTintColorAttribute
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
import dev.jdtech.jellyfin.viewmodels.ShowEvent
import dev.jdtech.jellyfin.viewmodels.ShowViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -79,8 +80,10 @@ class ShowFragment : Fragment() {
}
launch {
viewModel.navigateBack.collect {
if (it) findNavController().navigateUp()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is ShowEvent.NavigateBack -> findNavController().navigateUp()
}
}
}
}

View file

@ -16,6 +16,7 @@ import dev.jdtech.jellyfin.AppNavigationDirections
import dev.jdtech.jellyfin.adapters.UserListAdapter
import dev.jdtech.jellyfin.databinding.FragmentUsersBinding
import dev.jdtech.jellyfin.dialogs.DeleteUserDialogFragment
import dev.jdtech.jellyfin.viewmodels.UsersEvent
import dev.jdtech.jellyfin.viewmodels.UsersViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
@ -54,9 +55,9 @@ class UsersFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.navigateToMain.collect {
if (it) {
navigateToMainActivity()
viewModel.eventsChannelFlow.collect { event ->
when (event) {
is UsersEvent.NavigateToHome -> navigateToMainActivity()
}
}
}

View file

@ -15,10 +15,10 @@ import dev.jdtech.jellyfin.models.ServerAddress
import dev.jdtech.jellyfin.models.UiText
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.discovery.RecommendedServerInfo
@ -38,11 +38,12 @@ constructor(
) : ViewModel() {
private val _uiState = MutableStateFlow<UiState>(UiState.Normal)
val uiState = _uiState.asStateFlow()
private val _navigateToLogin = MutableSharedFlow<Boolean>()
val navigateToLogin = _navigateToLogin.asSharedFlow()
private val _discoveredServersState = MutableStateFlow<DiscoveredServersState>(DiscoveredServersState.Loading)
val discoveredServersState = _discoveredServersState.asStateFlow()
private val eventsChannel = Channel<AddServerEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
private val discoveredServers = mutableListOf<DiscoveredServer>()
private var serverFound = false
@ -206,7 +207,7 @@ constructor(
}
_uiState.emit(UiState.Normal)
_navigateToLogin.emit(true)
eventsChannel.send(AddServerEvent.NavigateToLogin)
}
/**
@ -269,3 +270,7 @@ constructor(
}
}
}
sealed interface AddServerEvent {
data object NavigateToLogin : AddServerEvent
}

View file

@ -11,11 +11,11 @@ import dev.jdtech.jellyfin.models.FindroidMovie
import dev.jdtech.jellyfin.models.FindroidShow
import dev.jdtech.jellyfin.models.UiText
import dev.jdtech.jellyfin.repository.JellyfinRepository
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -28,8 +28,9 @@ constructor(
) : ViewModel() {
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState = _uiState.asStateFlow()
private val _connectionError = MutableSharedFlow<Exception>()
val connectionError = _connectionError.asSharedFlow()
private val eventsChannel = Channel<DownloadsEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
sealed class UiState {
data class Normal(val sections: List<FavoriteSection>) : UiState()
@ -49,7 +50,7 @@ constructor(
// Give the UI a chance to load
delay(100)
} catch (e: Exception) {
_connectionError.emit(e)
eventsChannel.send(DownloadsEvent.ConnectionError(e))
}
}
}
@ -88,3 +89,7 @@ constructor(
}
}
}
sealed interface DownloadsEvent {
data class ConnectionError(val error: Exception) : DownloadsEvent
}

View file

@ -13,10 +13,10 @@ import dev.jdtech.jellyfin.models.UiText
import dev.jdtech.jellyfin.models.isDownloading
import dev.jdtech.jellyfin.repository.JellyfinRepository
import dev.jdtech.jellyfin.utils.Downloader
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import java.io.File
import java.util.UUID
@ -37,11 +37,8 @@ constructor(
private val _downloadStatus = MutableStateFlow(Pair(0, 0))
val downloadStatus = _downloadStatus.asStateFlow()
private val _downloadError = MutableSharedFlow<UiText>()
val downloadError = _downloadError.asSharedFlow()
private val _navigateBack = MutableSharedFlow<Boolean>()
val navigateBack = _navigateBack.asSharedFlow()
private val eventsChannel = Channel<EpisodeBottomSheetEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
private val handler = Handler(Looper.getMainLooper())
@ -75,7 +72,7 @@ constructor(
)
} catch (_: NullPointerException) {
// Navigate back because item does not exist (probably because it's been deleted)
_navigateBack.emit(true)
eventsChannel.send(EpisodeBottomSheetEvent.NavigateBack)
} catch (e: Exception) {
_uiState.emit(UiState.Error(e))
}
@ -133,7 +130,7 @@ constructor(
_downloadStatus.emit(Pair(10, Random.nextInt()))
if (result.second != null) {
_downloadError.emit(result.second!!)
eventsChannel.send(EpisodeBottomSheetEvent.DownloadError(result.second!!))
}
loadEpisode(item.id)
@ -188,3 +185,8 @@ constructor(
handler.removeCallbacksAndMessages(null)
}
}
sealed interface EpisodeBottomSheetEvent {
data object NavigateBack : EpisodeBottomSheetEvent
data class DownloadError(val uiText: UiText) : EpisodeBottomSheetEvent
}

View file

@ -11,11 +11,11 @@ import dev.jdtech.jellyfin.models.UiText
import dev.jdtech.jellyfin.models.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.extensions.authenticateWithQuickConnect
@ -38,8 +38,9 @@ constructor(
val usersState = _usersState.asStateFlow()
private val _quickConnectUiState = MutableStateFlow<QuickConnectUiState>(QuickConnectUiState.Disabled)
val quickConnectUiState = _quickConnectUiState.asStateFlow()
private val _navigateToMain = MutableSharedFlow<Boolean>()
val navigateToMain = _navigateToMain.asSharedFlow()
private val eventsChannel = Channel<LoginEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
private var quickConnectJob: Job? = null
@ -121,7 +122,7 @@ constructor(
saveAuthenticationResult(authenticationResult)
_uiState.emit(UiState.Normal)
_navigateToMain.emit(true)
eventsChannel.send(LoginEvent.NavigateToHome)
} catch (e: Exception) {
val message =
if (e.message?.contains("401") == true) {
@ -157,7 +158,7 @@ constructor(
saveAuthenticationResult(authenticationResult)
_quickConnectUiState.emit(QuickConnectUiState.Normal)
_navigateToMain.emit(true)
eventsChannel.send(LoginEvent.NavigateToHome)
} catch (_: Exception) {
_quickConnectUiState.emit(QuickConnectUiState.Normal)
}
@ -189,3 +190,7 @@ constructor(
}
}
}
sealed interface LoginEvent {
data object NavigateToHome : LoginEvent
}

View file

@ -21,10 +21,10 @@ import dev.jdtech.jellyfin.repository.JellyfinRepository
import dev.jdtech.jellyfin.utils.Downloader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Runnable
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.model.api.BaseItemPerson
@ -49,11 +49,8 @@ constructor(
private val _downloadStatus = MutableStateFlow(Pair(0, 0))
val downloadStatus = _downloadStatus.asStateFlow()
private val _downloadError = MutableSharedFlow<UiText>()
val downloadError = _downloadError.asSharedFlow()
private val _navigateBack = MutableSharedFlow<Boolean>()
val navigateBack = _navigateBack.asSharedFlow()
private val eventsChannel = Channel<MovieEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
private val handler = Handler(Looper.getMainLooper())
@ -115,7 +112,7 @@ constructor(
)
} catch (_: NullPointerException) {
// Navigate back because item does not exist (probably because it's been deleted)
_navigateBack.emit(true)
eventsChannel.send(MovieEvent.NavigateBack)
} catch (e: Exception) {
_uiState.emit(UiState.Error(e))
}
@ -330,7 +327,7 @@ constructor(
_downloadStatus.emit(Pair(10, Random.nextInt()))
if (result.second != null) {
_downloadError.emit(result.second!!)
eventsChannel.send(MovieEvent.DownloadError(result.second!!))
}
loadData(item.id)
@ -385,3 +382,8 @@ constructor(
handler.removeCallbacksAndMessages(null)
}
}
sealed interface MovieEvent {
data object NavigateBack : MovieEvent
data class DownloadError(val uiText: UiText) : MovieEvent
}

View file

@ -6,10 +6,10 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import dev.jdtech.jellyfin.models.EpisodeItem
import dev.jdtech.jellyfin.models.FindroidSeason
import dev.jdtech.jellyfin.repository.JellyfinRepository
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.ItemFields
import java.util.UUID
@ -24,8 +24,8 @@ constructor(
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState = _uiState.asStateFlow()
private val _navigateBack = MutableSharedFlow<Boolean>()
val navigateBack = _navigateBack.asSharedFlow()
private val eventsChannel = Channel<SeasonEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
sealed class UiState {
data class Normal(val episodes: List<EpisodeItem>) : UiState()
@ -44,7 +44,7 @@ constructor(
_uiState.emit(UiState.Normal(episodes))
} catch (_: NullPointerException) {
// Navigate back because item does not exist (probably because it's been deleted)
_navigateBack.emit(true)
eventsChannel.send(SeasonEvent.NavigateBack)
} catch (e: Exception) {
_uiState.emit(UiState.Error(e))
}
@ -63,3 +63,7 @@ constructor(
return listOf(header) + episodes.map { EpisodeItem.Episode(it) }
}
}
sealed interface SeasonEvent {
data object NavigateBack : SeasonEvent
}

View file

@ -7,10 +7,10 @@ import dev.jdtech.jellyfin.api.JellyfinApi
import dev.jdtech.jellyfin.database.ServerDatabaseDao
import dev.jdtech.jellyfin.models.ServerAddress
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.UUID
@ -32,8 +32,8 @@ constructor(
data class Error(val error: Exception) : UiState()
}
private val _navigateToMain = MutableSharedFlow<Boolean>()
val navigateToMain = _navigateToMain.asSharedFlow()
private val eventsChannel = Channel<ServerAddressesEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
private var currentServerId: String = ""
@ -75,7 +75,7 @@ constructor(
jellyfinApi.api.baseUrl = address.address
_navigateToMain.emit(true)
eventsChannel.send(ServerAddressesEvent.NavigateToHome)
}
}
@ -87,3 +87,7 @@ constructor(
}
}
}
sealed interface ServerAddressesEvent {
data object NavigateToHome : ServerAddressesEvent
}

View file

@ -8,10 +8,10 @@ import dev.jdtech.jellyfin.api.JellyfinApi
import dev.jdtech.jellyfin.database.ServerDatabaseDao
import dev.jdtech.jellyfin.models.Server
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -26,11 +26,8 @@ constructor(
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState = _uiState.asStateFlow()
private val _navigateToMain = MutableSharedFlow<Boolean>()
val navigateToMain = _navigateToMain.asSharedFlow()
private val _navigateToLogin = MutableSharedFlow<Boolean>()
val navigateToLogin = _navigateToLogin.asSharedFlow()
private val eventsChannel = Channel<ServerSelectEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
sealed class UiState {
data class Normal(val servers: List<Server>) : UiState()
@ -75,7 +72,7 @@ constructor(
userId = null
}
appPreferences.currentServer = server.id
_navigateToLogin.emit(true)
eventsChannel.send(ServerSelectEvent.NavigateToLogin)
return@launch
}
@ -87,7 +84,12 @@ constructor(
appPreferences.currentServer = server.id
_navigateToMain.emit(true)
eventsChannel.send(ServerSelectEvent.NavigateToHome)
}
}
}
sealed interface ServerSelectEvent {
data object NavigateToHome : ServerSelectEvent
data object NavigateToLogin : ServerSelectEvent
}

View file

@ -8,10 +8,10 @@ import dev.jdtech.jellyfin.models.FindroidSeason
import dev.jdtech.jellyfin.models.FindroidShow
import dev.jdtech.jellyfin.repository.JellyfinRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.model.api.BaseItemPerson
@ -27,8 +27,8 @@ constructor(
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState = _uiState.asStateFlow()
private val _navigateBack = MutableSharedFlow<Boolean>()
val navigateBack = _navigateBack.asSharedFlow()
private val eventsChannel = Channel<ShowEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
sealed class UiState {
data class Normal(
@ -93,7 +93,7 @@ constructor(
)
} catch (_: NullPointerException) {
// Navigate back because item does not exist (probably because it's been deleted)
_navigateBack.emit(true)
eventsChannel.send(ShowEvent.NavigateBack)
} catch (e: Exception) {
_uiState.emit(UiState.Error(e))
}
@ -189,3 +189,7 @@ constructor(
return dateRange.joinToString(separator = " - ")
}
}
sealed interface ShowEvent {
data object NavigateBack : ShowEvent
}

View file

@ -7,10 +7,10 @@ import dev.jdtech.jellyfin.api.JellyfinApi
import dev.jdtech.jellyfin.database.ServerDatabaseDao
import dev.jdtech.jellyfin.models.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@ -31,8 +31,8 @@ constructor(
data class Error(val error: Exception) : UiState()
}
private val _navigateToMain = MutableSharedFlow<Boolean>()
val navigateToMain = _navigateToMain.asSharedFlow()
private val eventsChannel = Channel<UsersEvent>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
private var currentServerId: String = ""
@ -77,7 +77,11 @@ constructor(
userId = user.id
}
_navigateToMain.emit(true)
eventsChannel.send(UsersEvent.NavigateToHome)
}
}
}
sealed interface UsersEvent {
data object NavigateToHome : UsersEvent
}

View file

@ -27,11 +27,11 @@ import dev.jdtech.jellyfin.utils.bif.BifUtil
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -60,8 +60,8 @@ constructor(
)
val uiState = _uiState.asStateFlow()
private val _navigateBack = MutableSharedFlow<Boolean>()
val navigateBack = _navigateBack.asSharedFlow()
private val eventsChannel = Channel<PlayerEvents>()
val eventsChannelFlow = eventsChannel.receiveAsFlow()
private val intros: MutableMap<UUID, Intro> = mutableMapOf()
@ -317,7 +317,7 @@ constructor(
}
ExoPlayer.STATE_ENDED -> {
stateString = "ExoPlayer.STATE_ENDED -"
_navigateBack.tryEmit(true)
eventsChannel.trySend(PlayerEvents.NavigateBack)
}
}
Timber.d("Changed player state to $stateString")
@ -366,3 +366,7 @@ constructor(
}
}
}
sealed interface PlayerEvents {
data object NavigateBack : PlayerEvents
}