Use Wholphin-specific dispatchers (#1583)

## Description
Switches all usages of `kotlinx.coroutines.Dispatchers` to
`WholphinDispatchers`.

`WholphinDispatchers` provides an easier and more reliable mechanism to
use a test dispatcher in unit tests. For regular app usage,
`WholphinDispatchers` just delegates to `Dispatchers`.

There are no user facing changes

### Related issues
None

### Testing
Basic emulator testing & unit tests

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-06-18 11:17:19 -04:00 • committed by GitHub
parent ddbec0da73
commit e17ae3eb8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
68 changed files with 252 additions and 226 deletions

View file

@ -33,9 +33,9 @@ import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.ui.data.RowColumn
import com.github.damontecres.wholphin.ui.data.RowColumnSaver
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
@ -359,34 +359,34 @@ suspend fun showToast(
context: Context,
text: CharSequence,
duration: Int,
) = withContext(Dispatchers.Main) {
) = withContext(WholphinDispatchers.Main) {
Toast.makeText(context, text, duration).show()
}
suspend fun showToast(
context: Context,
text: CharSequence,
) = withContext(Dispatchers.Main) {
) = withContext(WholphinDispatchers.Main) {
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
}
/**
* Launches a coroutine with [Dispatchers.IO] plus the provided [CoroutineContext] defaulting to using [ExceptionHandler]
* Launches a coroutine with [WholphinDispatchers.IO] plus the provided [CoroutineContext] defaulting to using [ExceptionHandler]
*/
fun CoroutineScope.launchIO(
context: CoroutineContext = ExceptionHandler(),
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit,
): Job = launch(context = Dispatchers.IO + context, start = start, block = block)
): Job = launch(context = WholphinDispatchers.IO + context, start = start, block = block)
/**
* Launches a coroutine with [Dispatchers.Default] plus the provided [CoroutineContext] defaulting to using [ExceptionHandler]
* Launches a coroutine with [WholphinDispatchers.Default] plus the provided [CoroutineContext] defaulting to using [ExceptionHandler]
*/
fun CoroutineScope.launchDefault(
context: CoroutineContext = ExceptionHandler(),
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit,
): Job = launch(context = Dispatchers.Default + context, start = start, block = block)
): Job = launch(context = WholphinDispatchers.Default + context, start = start, block = block)
/**
* Converts a UUID to the format used server-side (ie without hyphens).
@ -410,7 +410,7 @@ fun logTab(
ACRA.errorReporter.putCustomData("tabInfo", info)
}
suspend fun <T> onMain(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.Main, block)
suspend fun <T> onMain(block: suspend CoroutineScope.() -> T) = withContext(WholphinDispatchers.Main, block)
fun Modifier.dimAndBlur(enabled: Boolean) =
this.ifElse(

View file

@ -30,7 +30,6 @@ import coil3.request.crossfade
import com.github.damontecres.wholphin.ui.AspectRatios
import com.github.damontecres.wholphin.ui.PreviewTvSpec
import com.github.damontecres.wholphin.ui.components.Genre
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import com.github.damontecres.wholphin.ui.setup.rememberIdColor
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import java.util.UUID

View file

@ -32,9 +32,7 @@ import coil3.request.ImageRequest
import coil3.request.crossfade
import com.github.damontecres.wholphin.ui.AspectRatios
import com.github.damontecres.wholphin.ui.PreviewTvSpec
import com.github.damontecres.wholphin.ui.components.Genre
import com.github.damontecres.wholphin.ui.components.Studio
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import com.github.damontecres.wholphin.ui.setup.rememberIdColor
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import java.util.UUID

View file

@ -70,13 +70,13 @@ import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.GetPersonsHandler
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import com.github.damontecres.wholphin.util.successValue
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
@ -251,7 +251,7 @@ class CollectionFolderViewModel
fun saveViewOptions(viewOptions: ViewOptions) {
_state.update { it.copy(viewOptions = viewOptions) }
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
saveLibraryDisplayInfo(viewOptions = viewOptions)
if (!viewOptions.showBackdrop) {
backdropService.clearBackdrop()
@ -295,7 +295,7 @@ class CollectionFolderViewModel
recursive: Boolean,
filter: GetItemsFilter,
useSeriesForPrimary: Boolean,
) = viewModelScope.launch(Dispatchers.IO) {
) = viewModelScope.launch(WholphinDispatchers.IO) {
_state.update {
it.copy(
items = DataLoadingState.Loading,
@ -437,7 +437,7 @@ class CollectionFolderViewModel
)
suspend fun positionOfLetter(letter: Char): Int? =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
val sort = state.value.sortAndDirection
val filter = state.value.filter
val request =
@ -461,7 +461,7 @@ class CollectionFolderViewModel
itemId: UUID,
played: Boolean,
) {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setWatched(itemId, played)
(state.value.items as? DataLoadingState.Success)?.let {
(it.data as? ApiRequestPager<*>)?.refreshItem(position, itemId)
@ -474,7 +474,7 @@ class CollectionFolderViewModel
itemId: UUID,
favorite: Boolean,
) {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
(state.value.items as? DataLoadingState.Success)?.let {
(it.data as? ApiRequestPager<*>)?.refreshItem(position, itemId)

View file

@ -33,13 +33,13 @@ import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.GetGenresRequestHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import com.mayakapps.kache.InMemoryKache
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.MutableStateFlow
@ -142,7 +142,7 @@ class GenreViewModel
}
suspend fun positionOfLetter(letter: Char): Int =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
val request =
GetGenresRequest(
parentId = itemId,
@ -197,7 +197,7 @@ suspend fun getGenreImageMap(
val semaphore = Semaphore(4)
genres
.map { genreId ->
scope.async(Dispatchers.IO) {
scope.async(WholphinDispatchers.IO) {
semaphore.withPermit {
val item =
GetItemsRequestHandler

View file

@ -38,13 +38,13 @@ import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.RequestHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
@ -150,7 +150,7 @@ class ItemGridViewModel
itemId: UUID,
played: Boolean,
) {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setWatched(itemId, played)
(state.value.items as? DataLoadingState.Success)?.let {
(it.data as? ApiRequestPager<*>)?.refreshItem(position, itemId)
@ -163,7 +163,7 @@ class ItemGridViewModel
itemId: UUID,
favorite: Boolean,
) {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
(state.value.items as? DataLoadingState.Success)?.let {
(it.data as? ApiRequestPager<*>)?.refreshItem(position, itemId)

View file

@ -48,13 +48,13 @@ import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.RequestHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
@ -173,7 +173,7 @@ class RecommendedViewModel
}
private fun fetchSuggestions() {
viewModelScope.launch(Dispatchers.IO) {
viewModelScope.launch(WholphinDispatchers.IO) {
val limit =
userPreferencesService
.getCurrent()

View file

@ -32,11 +32,11 @@ import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.GetStudiosRequestHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
@ -113,7 +113,7 @@ class StudioViewModel
}
suspend fun positionOfLetter(letter: Char): Int =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
val request =
GetStudiosRequest(
userId = serverRepository.currentUser?.id,

View file

@ -17,10 +17,10 @@ import android.speech.RecognizerIntent
import android.speech.SpeechRecognizer
import androidx.core.content.ContextCompat
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.android.asCoroutineDispatcher
@ -175,7 +175,7 @@ class VoiceInputManager
private fun provideMainDispatcher(): CoroutineDispatcher =
try {
Dispatchers.Main.immediate
WholphinDispatchers.Main.immediate
} catch (_: IllegalStateException) {
// Fallback for unit tests where Main dispatcher is not installed
handler.asCoroutineDispatcher()

View file

@ -73,7 +73,7 @@ import com.github.damontecres.wholphin.ui.playback.isForwardButton
import com.github.damontecres.wholphin.ui.playback.isPlayKeyUp
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.ExceptionHandler
import kotlinx.coroutines.Dispatchers
import com.github.damontecres.wholphin.util.WholphinDispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
@ -217,7 +217,7 @@ fun <T : CardGridItem> CardGrid(
{ letter: Char ->
scope.launch(ExceptionHandler()) {
val jumpPosition =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
letterPosition.invoke(letter)
}
Timber.d("Alphabet jump to $jumpPosition")

View file

@ -53,12 +53,12 @@ import com.github.damontecres.wholphin.ui.util.StringStringProvider
import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
@ -166,7 +166,7 @@ class HomeRowGridViewModel
itemId: UUID,
played: Boolean,
) {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setWatched(itemId, played)
(state.value.loading as? HomeRowLoadingState.Success)?.let {
(it.items as? ApiRequestPager<*>)?.refreshItem(position, itemId)
@ -179,7 +179,7 @@ class HomeRowGridViewModel
itemId: UUID,
favorite: Boolean,
) {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
(state.value.loading as? HomeRowLoadingState.Success)?.let {
(it.items as? ApiRequestPager<*>)?.refreshItem(position, itemId)

View file

@ -107,12 +107,12 @@ import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@ -316,14 +316,14 @@ class PlaylistViewModel
fun setWatched(
itemId: UUID,
played: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setWatched(itemId, played)
}
fun setFavorite(
itemId: UUID,
favorite: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
}

View file

@ -40,12 +40,12 @@ import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
@ -210,7 +210,7 @@ class CollectionViewModel
supervisorScope {
val jobs =
typesInCollection.map { type ->
async(Dispatchers.IO) {
async(WholphinDispatchers.IO) {
val title = ResStringProvider(formatTypeName(type))
val result =
try {
@ -359,7 +359,7 @@ class CollectionViewModel
)
suspend fun letterPosition(letter: Char): Int =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
val sort = state.value.sortAndDirection
val filter = state.value.itemFilter
val request =
@ -387,7 +387,7 @@ class CollectionViewModel
itemId: UUID,
played: Boolean,
position: RowColumn?,
) = viewModelScope.launch(Dispatchers.IO + ExceptionHandler()) {
) = viewModelScope.launch(WholphinDispatchers.IO + ExceptionHandler()) {
favoriteWatchManager.setWatched(itemId, played)
if (itemId == state.value.collection?.id) {
refreshCollection()
@ -400,7 +400,7 @@ class CollectionViewModel
itemId: UUID,
favorite: Boolean,
position: RowColumn?,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
if (itemId == state.value.collection?.id) {
refreshCollection()

View file

@ -24,6 +24,7 @@ import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.showToast
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import com.github.damontecres.wholphin.util.successValue
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -31,7 +32,6 @@ import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
@ -73,7 +73,7 @@ class DiscoverMovieViewModel
}
private fun fetchAndSetItem(): Deferred<MovieDetails?> =
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
try {
val movie = seerrService.api.moviesApi.movieMovieIdGet(movieId = item.id)
_state.update { it.copy(movie = DataLoadingState.Success(movie)) }

View file

@ -22,6 +22,7 @@ import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.showToast
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import com.github.damontecres.wholphin.util.successValue
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -30,7 +31,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
@ -71,7 +71,7 @@ class DiscoverSeriesViewModel
}
private fun fetchAndSetItem(): Deferred<TvDetails?> =
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
try {
val tv = seerrService.api.tvApi.tvTvIdGet(tvId = item.id)
_state.update { it.copy(tvSeries = DataLoadingState.Success(tv)) }

View file

@ -23,13 +23,13 @@ import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.showToast
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -126,7 +126,7 @@ class EpisodeViewModel
fun setWatched(
itemId: UUID,
played: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setWatched(itemId, played)
fetchAndSetItem()
}
@ -134,7 +134,7 @@ class EpisodeViewModel
fun setFavorite(
itemId: UUID,
favorite: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
fetchAndSetItem()
}

View file

@ -59,11 +59,11 @@ import com.github.damontecres.wholphin.ui.rememberInt
import com.github.damontecres.wholphin.ui.rememberPosition
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import eu.wewox.programguide.ProgramGuide
import eu.wewox.programguide.ProgramGuideDimensions
import eu.wewox.programguide.ProgramGuideItem
import eu.wewox.programguide.rememberSaveableProgramGuideState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
@ -319,7 +319,7 @@ fun TvGuideGridContent(
var focusedProgramIndex by rememberInt(0)
LaunchedEffect(onFocus, focusedProgramIndex) {
withContext(Dispatchers.Default) {
withContext(WholphinDispatchers.Default) {
val program = programs.programs.getOrNull(focusedProgramIndex)
if (program != null) {
val channelIndex = channels.indexOfFirst { it.id == program.channelId }

View file

@ -86,12 +86,12 @@ import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -242,7 +242,7 @@ class AlbumViewModel
fun setFavorite(
itemId: UUID,
favorite: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
val album =
api.userLibraryApi

View file

@ -81,12 +81,12 @@ import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -254,7 +254,7 @@ class ArtistViewModel
fun setFavorite(
itemId: UUID,
favorite: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
val artist =
api.userLibraryApi

View file

@ -44,7 +44,6 @@ import com.github.damontecres.wholphin.ui.playback.ControllerViewState
import com.github.damontecres.wholphin.ui.playback.overlay.PlaybackAction
import com.github.damontecres.wholphin.ui.playback.overlay.PlaybackButton
import com.github.damontecres.wholphin.ui.playback.overlay.PlaybackButtons
import com.github.damontecres.wholphin.ui.playback.overlay.PlaybackFaButton
import com.github.damontecres.wholphin.ui.playback.overlay.buttonSpacing
import com.github.damontecres.wholphin.ui.theme.PreviewInteractionSource
import com.github.damontecres.wholphin.ui.theme.WholphinTheme

View file

@ -27,13 +27,13 @@ import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.main.settings.MoveDirection
import com.github.damontecres.wholphin.ui.onMain
import com.github.damontecres.wholphin.ui.playback.ControllerViewState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import com.mayakapps.kache.InMemoryKache
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
@ -95,7 +95,7 @@ class NowPlayingViewModel
private val lyricCache =
InMemoryKache<UUID, LyricDto>(20) {
creationScope = CoroutineScope(Dispatchers.IO)
creationScope = CoroutineScope(WholphinDispatchers.IO)
}
init {

View file

@ -24,7 +24,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.tv.material3.DenseListItem
import androidx.tv.material3.Icon
import androidx.tv.material3.ListItem
import androidx.tv.material3.ListItemDefaults
import androidx.tv.material3.LocalContentColor
import androidx.tv.material3.Text

View file

@ -41,6 +41,7 @@ import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import com.github.damontecres.wholphin.util.successValue
import com.google.common.cache.CacheBuilder
import dagger.assisted.Assisted
@ -50,7 +51,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
@ -137,7 +137,7 @@ class SeriesViewModel
val episodeListDeferred =
if (seriesPageType == SeriesPageType.OVERVIEW) {
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
if (seasonEpisodeIds != null) {
loadEpisodesInternal(
seasonEpisodeIds.seasonId,
@ -292,7 +292,7 @@ class SeriesViewModel
series: BaseItem,
seasonNum: Int?,
): Deferred<List<BaseItem?>> =
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
Timber.v("getSeasons for %s", series.id)
val request =
GetItemsRequest(
@ -405,7 +405,7 @@ class SeriesViewModel
itemId: UUID,
played: Boolean,
listIndex: Int?,
) = viewModelScope.launch(Dispatchers.IO + ExceptionHandler()) {
) = viewModelScope.launch(WholphinDispatchers.IO + ExceptionHandler()) {
favoriteWatchManager.setWatched(itemId, played)
listIndex?.let {
refreshEpisode(itemId, listIndex)
@ -440,7 +440,7 @@ class SeriesViewModel
itemId: UUID,
favorite: Boolean,
listIndex: Int?,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
if (listIndex != null) {
refreshEpisode(itemId, listIndex)
@ -452,13 +452,13 @@ class SeriesViewModel
fun setSeasonWatched(
seasonId: UUID,
played: Boolean,
) = viewModelScope.launch(Dispatchers.IO + ExceptionHandler()) {
) = viewModelScope.launch(WholphinDispatchers.IO + ExceptionHandler()) {
setWatched(seasonId, played, null)
updateSeries()
}
fun setWatchedSeries(played: Boolean) =
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setWatched(seriesId, played)
updateSeries()
}
@ -466,7 +466,7 @@ class SeriesViewModel
fun refreshEpisode(
itemId: UUID,
listIndex: Int,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
val eps = state.value.episodes
if (eps is EpisodeList.Success) {
eps.episodes.refreshItem(listIndex, itemId)
@ -481,7 +481,7 @@ class SeriesViewModel
* Play whichever episode is next up for series or else the first episode
*/
fun playNextUp() {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
val result by api.tvShowsApi.getNextUp(seriesId = seriesId)
val nextUp =
result.items.firstOrNull() ?: api.tvShowsApi
@ -491,7 +491,7 @@ class SeriesViewModel
).content.items
.firstOrNull()
if (nextUp != null) {
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
navigateTo(Destination.Playback(BaseItem(nextUp)))
}
} else {
@ -582,7 +582,7 @@ class SeriesViewModel
val result =
peopleInEpisodeCache
.get(item.id) {
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
val list =
api.userLibraryApi
.getItem(item.id)

View file

@ -35,8 +35,8 @@ import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.MutableStateFlow
@ -77,7 +77,7 @@ class SeerrRequestsViewModel
val requests =
mediaRequests.mapNotNull { request ->
if (request.media?.tmdbId != null) {
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
semaphore.withPermit {
val type = SeerrItemType.fromString(request.type)
when (type) {

View file

@ -28,9 +28,9 @@ import com.github.damontecres.wholphin.ui.util.EmptyStringProvider
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.MutableStateFlow
@ -117,7 +117,7 @@ class HomeViewModel
val deferred =
settings.rows
.map { row ->
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
semaphore.withPermit {
Timber.v("Fetching row: %s", row)
try {
@ -220,9 +220,9 @@ class HomeViewModel
fun setWatched(
itemId: UUID,
played: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setWatched(itemId, played)
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
init()
}
}
@ -230,9 +230,9 @@ class HomeViewModel
fun setFavorite(
itemId: UUID,
favorite: Boolean,
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
) = viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
favoriteWatchManager.setFavorite(itemId, favorite)
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
init()
}
}

View file

@ -103,9 +103,9 @@ import com.github.damontecres.wholphin.ui.rememberPosition
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.SearchRelevance
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -253,7 +253,7 @@ class SearchViewModel
}
private fun searchCombined(query: String) {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
try {
val request =
GetItemsRequest(
@ -477,7 +477,7 @@ fun SearchPage(
) {
if (!searchClicked) return@LaunchedEffect
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
// Want to focus on the first successful row after all of the ones before it are finished searching
val results =
if (isLibraryTab) {

View file

@ -43,10 +43,10 @@ import com.github.damontecres.wholphin.ui.util.ResStringProvider
import com.github.damontecres.wholphin.ui.util.StringStringProvider
import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@ -129,7 +129,7 @@ class HomeSettingsViewModel
.let { state ->
state.rows
.map { row ->
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
semaphore.withPermit {
try {
homeSettingsService.fetchDataForRow(

View file

@ -67,6 +67,7 @@ import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.PlaybackItemState
import com.github.damontecres.wholphin.util.TrackActivityPlaybackListener
import com.github.damontecres.wholphin.util.WholphinDispatchers
import com.github.damontecres.wholphin.util.checkForSupport
import com.github.damontecres.wholphin.util.mpv.MpvPlayer
import com.github.damontecres.wholphin.util.mpv.mpvDeviceProfile
@ -79,7 +80,6 @@ import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
@ -242,7 +242,7 @@ class PlaybackViewModel
Timber.d("Selected backend: %s", playerBackend)
if (currentPlayer.value?.backend != playerBackend) {
Timber.i("Switching player backend to %s", playerBackend)
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
disconnectPlayer()
}
@ -421,7 +421,7 @@ class PlaybackViewModel
positionMs: Long,
forceTranscoding: Boolean = this.forceTranscoding,
): Boolean =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
val item =
when (playlistItem) {
is PlaylistItem.Intro -> playlistItem.item
@ -581,7 +581,7 @@ class PlaybackViewModel
trickPlayInfo = trickPlayInfo,
)
}
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
changeStreams(
item,
itemPlaybackToUse,
@ -612,7 +612,7 @@ class PlaybackViewModel
userInitiated: Boolean,
enableDirectPlay: Boolean = !this.forceTranscoding,
enableDirectStream: Boolean = !this.forceTranscoding,
) = withContext(Dispatchers.IO) {
) = withContext(WholphinDispatchers.IO) {
val itemId = item.id
val currentPlayback = state.value.currentPlayback
@ -779,7 +779,7 @@ class PlaybackViewModel
)
}
}
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
// TODO, don't need to release & recreate when switching streams
this@PlaybackViewModel.activityListener?.let {
it.release()
@ -850,7 +850,7 @@ class PlaybackViewModel
subtitleIndex: Int?,
userInitiated: Boolean,
): Boolean =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
// TODO there's probably no reason why we can't add external subtitles?
Timber.v("changeStreams direct play")
@ -859,7 +859,7 @@ class PlaybackViewModel
if (externalSubtitle == null) {
val result =
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
TrackSelectionUtils.createTrackSelections(
onMain { player.trackSelectionParameters },
onMain { player.currentTracks },
@ -1124,7 +1124,7 @@ class PlaybackViewModel
MediaSegmentType.INTRO -> prefs.skipIntros
MediaSegmentType.UNKNOWN -> SkipSegmentBehavior.IGNORE
}
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
val newSegment =
when (behavior) {
SkipSegmentBehavior.AUTO_SKIP -> {
@ -1318,7 +1318,7 @@ class PlaybackViewModel
override fun onPlayerError(error: PlaybackException) {
Timber.e(error, "Playback error")
viewModelScope.launch(Dispatchers.Main + ExceptionHandler()) {
viewModelScope.launch(WholphinDispatchers.Main + ExceptionHandler()) {
state.value.currentPlayback?.let {
when (it.playMethod) {
PlayMethod.TRANSCODE -> {
@ -1346,7 +1346,7 @@ class PlaybackViewModel
enableDirectPlay = false,
enableDirectStream = false,
)
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
player.prepare()
player.play()
}
@ -1367,7 +1367,7 @@ class PlaybackViewModel
.subscribe<PlaystateMessage>()
.onEach { message ->
message.data?.let {
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
when (it.command) {
PlaystateCommand.STOP -> {
release()
@ -1422,7 +1422,7 @@ class PlaybackViewModel
* Atomically update [currentMediaInfo]
*/
internal suspend fun updateCurrentMedia(block: (CurrentMediaInfo) -> CurrentMediaInfo) =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
_state.update {
it.copy(currentMediaInfo = block.invoke(it.currentMediaInfo))
}

View file

@ -10,7 +10,7 @@ import com.github.damontecres.wholphin.data.model.TrackIndex
import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.onMain
import com.github.damontecres.wholphin.ui.showToast
import kotlinx.coroutines.Dispatchers
import com.github.damontecres.wholphin.util.WholphinDispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.withContext
@ -183,7 +183,7 @@ fun PlaybackViewModel.downloadAndSwitchSubtitles(
}
}
subtitleSearchState.update { it.copy(status = SubtitleSearchStatus.Inactive) }
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
if (wasPlaying) {
player.play()
}

View file

@ -36,7 +36,7 @@ import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import com.github.damontecres.wholphin.util.TrackSupport
import com.github.damontecres.wholphin.util.TrackSupportReason
import com.github.damontecres.wholphin.util.TrackType
import kotlinx.coroutines.Dispatchers
import com.github.damontecres.wholphin.util.WholphinDispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@ -90,7 +90,7 @@ fun PlaybackDebugOverlay(
)
val memoryUsed by produceState("") {
withContext(Dispatchers.Default) {
withContext(WholphinDispatchers.Default) {
while (isActive) {
val runtime = Runtime.getRuntime()
val total = runtime.totalMemory()

View file

@ -16,7 +16,6 @@ import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asFlow
import androidx.lifecycle.viewModelScope
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R

View file

@ -57,9 +57,9 @@ import com.github.damontecres.wholphin.ui.main.settings.MoveDirection
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.update
@ -317,7 +317,7 @@ class NavDrawerPreferencesViewModel
return@launchDefault
}
val navDrawerPins =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
serverPreferencesDao
.getNavDrawerPinnedItems(user)
.associateBy { it.itemId }

View file

@ -34,7 +34,6 @@ import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.ui.FontAwesome
import com.github.damontecres.wholphin.ui.PreviewTvSpec
import com.github.damontecres.wholphin.ui.components.BasicDialog
import com.github.damontecres.wholphin.ui.components.Button
import com.github.damontecres.wholphin.ui.components.TextButton
import com.github.damontecres.wholphin.ui.playback.isEnterKey
import com.github.damontecres.wholphin.ui.theme.WholphinTheme

View file

@ -13,13 +13,13 @@ import com.github.damontecres.wholphin.services.SetupNavigationManager
import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
@ -119,7 +119,7 @@ class SwitchUserViewModel
}
fun trySwitchUser(user: JellyfinUser): Deferred<String?> =
viewModelScope.async(Dispatchers.IO) {
viewModelScope.async(WholphinDispatchers.IO) {
try {
val current = serverRepository.changeUser(server, user)
setupNavigationManager.navigateTo(SetupDestination.AppContent(current))
@ -234,7 +234,7 @@ class SwitchUserViewModel
}
private suspend fun getUsers(): List<JellyfinUserAndImage> =
withContext(Dispatchers.IO) {
withContext(WholphinDispatchers.IO) {
val api = jellyfin.createApi(server.url)
val knownUsers =
serverDao

View file

@ -27,13 +27,13 @@ import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.WholphinDispatchers
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
@ -377,7 +377,7 @@ class SlideshowViewModel
),
)
Timber.d("Saved VideoFilter for image %s", it.image.id)
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
showToast(
context,
"Saved",
@ -406,7 +406,7 @@ class SlideshowViewModel
),
)
Timber.d("Saved VideoFilter for album %s", slideshowSettings.parentId)
withContext(Dispatchers.Main) {
withContext(WholphinDispatchers.Main) {
showToast(
context,
"Saved",

View file

@ -8,7 +8,7 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import com.github.damontecres.wholphin.ui.getTimeFormatter
import kotlinx.coroutines.Dispatchers
import com.github.damontecres.wholphin.util.WholphinDispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@ -34,7 +34,7 @@ data class Clock(
fun ProvideLocalClock(content: @Composable () -> Unit) {
val clock = remember { Clock() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
withContext(WholphinDispatchers.Default) {
while (isActive) {
val now = LocalDateTime.now()
val time = getTimeFormatter().format(now)