diff --git a/app/android/src/androidMain/kotlin/dev/datlag/burningseries/MainActivity.kt b/app/android/src/androidMain/kotlin/dev/datlag/burningseries/MainActivity.kt index cd74b7e6..78932d81 100644 --- a/app/android/src/androidMain/kotlin/dev/datlag/burningseries/MainActivity.kt +++ b/app/android/src/androidMain/kotlin/dev/datlag/burningseries/MainActivity.kt @@ -20,6 +20,7 @@ import com.arkivanov.essenty.lifecycle.LifecycleOwner import com.arkivanov.essenty.lifecycle.essentyLifecycle import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.shouldShowRationale +import dev.datlag.burningseries.model.common.safeCast import dev.datlag.burningseries.shared.App import dev.datlag.burningseries.shared.SharedRes import dev.datlag.burningseries.shared.common.lifecycle.LocalLifecycleOwner @@ -43,7 +44,7 @@ class MainActivity : AppCompatActivity() { WindowCompat.setDecorFitsSystemWindows(window, false) enableEdgeToEdge() - val di = ((applicationContext as? App) ?: (application as App)).di + val di = applicationContext.safeCast()?.di ?: (application as App).di val lifecycleOwner = object : LifecycleOwner { override val lifecycle: Lifecycle = essentyLifecycle() diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbar.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbar.kt index f2ee86e2..fa059e75 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbar.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbar.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.layout.* import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntSize +import dev.datlag.burningseries.model.common.safeCast import kotlin.math.absoluteValue import kotlin.math.max import kotlin.math.min @@ -289,7 +290,7 @@ internal class RoadModifier( override fun Density.modifyParentData(parentData: Any?): Any { return CollapsingToolbarRoadData( this@RoadModifier.whenCollapsed, this@RoadModifier.whenExpanded, - (parentData as? CollapsingToolbarData)?.progressListener + parentData.safeCast()?.progressListener ) } } @@ -298,13 +299,13 @@ internal class ParallaxModifier( private val ratio: Float ): ParentDataModifier { override fun Density.modifyParentData(parentData: Any?): Any { - return CollapsingToolbarParallaxData(ratio, (parentData as? CollapsingToolbarData)?.progressListener) + return CollapsingToolbarParallaxData(ratio, parentData.safeCast()?.progressListener) } } internal class PinModifier: ParentDataModifier { override fun Density.modifyParentData(parentData: Any?): Any { - return CollapsingToolbarPinData((parentData as? CollapsingToolbarData)?.progressListener) + return CollapsingToolbarPinData(parentData.safeCast()?.progressListener) } } diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbarScaffold.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbarScaffold.kt index 4ea0b280..ab448dd9 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbarScaffold.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/toolbar/CollapsingToolbarScaffold.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntSize +import dev.datlag.burningseries.model.common.safeCast import kotlin.math.max @Stable @@ -145,7 +146,7 @@ fun CollapsingToolbarScaffold( val bodyMeasurables = measurables.subList(1, measurables.size) val childrenAlignments = bodyMeasurables.map { - (it.parentData as? ScaffoldParentData)?.alignment + it.parentData.safeCast()?.alignment } val bodyPlaceables = bodyMeasurables.map { it.measure(bodyConstraints) @@ -210,7 +211,7 @@ private class ScaffoldChildAlignmentModifier( private val alignment: Alignment ) : ParentDataModifier { override fun Density.modifyParentData(parentData: Any?): Any { - return (parentData as? ScaffoldParentData) ?: ScaffoldParentData(alignment) + return parentData.safeCast()?.alignment ?: ScaffoldParentData(alignment) } } diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/search/SearchScreenComponent.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/search/SearchScreenComponent.kt index 540e8eba..46cb4043 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/search/SearchScreenComponent.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/search/SearchScreenComponent.kt @@ -8,6 +8,7 @@ import com.arkivanov.decompose.value.Value import dev.datlag.burningseries.model.Genre import dev.datlag.burningseries.model.Series import dev.datlag.burningseries.model.algorithm.JaroWinkler +import dev.datlag.burningseries.model.common.safeCast import dev.datlag.burningseries.model.common.safeSubList import dev.datlag.burningseries.model.state.SearchAction import dev.datlag.burningseries.model.state.SearchState @@ -36,7 +37,7 @@ class SearchScreenComponent( private val searchStateMachine: SearchStateMachine by di.instance() override val searchState: StateFlow = searchStateMachine.state.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), SearchState.Loading) - private val allGenres = searchState.mapNotNull { it as SearchState.Success }.map { it.genres }.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), emptyList()) + private val allGenres = searchState.mapNotNull { it.safeCast() }.map { it.genres }.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), emptyList()) private val allItems = allGenres.map { it.flatMap { g -> g.items } }.flowOn(ioDispatcher()) private val maxGenres = allGenres.map { it.size }.flowOn(ioDispatcher()) private val loadedGenres = MutableStateFlow(1) diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreenComponent.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreenComponent.kt index fff8023d..15dffc38 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreenComponent.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreenComponent.kt @@ -12,6 +12,7 @@ import com.arkivanov.essenty.backhandler.BackCallback import dev.datlag.burningseries.database.BurningSeries import dev.datlag.burningseries.model.BSUtil import dev.datlag.burningseries.model.Series +import dev.datlag.burningseries.model.common.safeCast import dev.datlag.burningseries.model.state.EpisodeAction import dev.datlag.burningseries.model.state.EpisodeState import dev.datlag.burningseries.model.state.SeriesAction @@ -68,7 +69,7 @@ class SeriesScreenComponent( ) override val seriesState: StateFlow = seriesStateMachine.state.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), SeriesState.Loading(initialHref)) - private val successState = seriesState.mapNotNull { it as? SeriesState.Success }.flowOn(ioDispatcher()) + private val successState = seriesState.mapNotNull { it.safeCast() }.flowOn(ioDispatcher()) private val currentSeries = successState.map { it.series }.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), null) private val onDeviceReachable = successState.map { it.onDeviceReachable }.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.Eagerly, true) override val title: StateFlow = currentSeries.mapNotNull { it?.bestTitle }.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), initialTitle) @@ -97,7 +98,7 @@ class SeriesScreenComponent( private val episodeStateMachine by di.instance() private val episodeState: StateFlow = episodeStateMachine.state.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), EpisodeState.Waiting) override val loadingEpisodeHref: StateFlow = episodeState.map { - (it as? EpisodeState.Loading)?.episode?.href ?: (it as? EpisodeState.SuccessHoster)?.episode?.href + it.safeCast()?.episode?.href ?: it.safeCast()?.episode?.href }.flowOn(ioDispatcher()).stateIn(ioScope(), SharingStarted.WhileSubscribed(), null) override val dbEpisodes = commonHref.transform { @@ -196,7 +197,7 @@ class SeriesScreenComponent( } } is EpisodeState.ErrorHoster, is EpisodeState.ErrorStream -> { - val episode = (state as? EpisodeState.EpisodeHolder)?.episode + val episode = state.safeCast()?.episode val series = currentSeries.value ?: currentSeries.first() ?: currentSeries.value!! if (episode != null) { diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/video/VideoScreenComponent.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/video/VideoScreenComponent.kt index 35638479..bbeb0f95 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/video/VideoScreenComponent.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/video/VideoScreenComponent.kt @@ -10,6 +10,7 @@ import com.arkivanov.essenty.backhandler.BackCallback import dev.datlag.burningseries.database.BurningSeries import dev.datlag.burningseries.model.BSUtil import dev.datlag.burningseries.model.Series +import dev.datlag.burningseries.model.common.safeCast import dev.datlag.burningseries.model.state.EpisodeState import dev.datlag.burningseries.network.state.EpisodeStateMachine import dev.datlag.burningseries.shared.common.ioDispatcher @@ -38,7 +39,7 @@ class VideoScreenComponent( override val streams: List = initialStreams.sortedBy { it.headers.size } private val episodeStateMachine by di.instance() - override val episode: StateFlow = episodeStateMachine.state.mapNotNull { it as? EpisodeState.EpisodeHolder }.map { it.episode }.flowOn( + override val episode: StateFlow = episodeStateMachine.state.mapNotNull { it.safeCast() }.map { it.episode }.flowOn( ioDispatcher() ).stateIn(ioScope(), SharingStarted.WhileSubscribed(), initialEpisode) diff --git a/model/src/commonMain/kotlin/dev/datlag/burningseries/model/common/ExtendCoroutine.kt b/model/src/commonMain/kotlin/dev/datlag/burningseries/model/common/ExtendCoroutine.kt index 14cb51d5..2b03907d 100644 --- a/model/src/commonMain/kotlin/dev/datlag/burningseries/model/common/ExtendCoroutine.kt +++ b/model/src/commonMain/kotlin/dev/datlag/burningseries/model/common/ExtendCoroutine.kt @@ -24,4 +24,26 @@ suspend fun suspendCatching(block: suspend CoroutineScope.() -> T): Result safeCast(block: () -> T?): T? { + return scopeCatching { + block() + }.getOrNull() +} + +suspend fun suspendSafeCast(block: () -> T?): T? { + return suspendCatching { + block() + }.getOrNull() +} + +inline fun Any?.safeCast(): T? { + return safeCast { + if (this is T) { + this + } else { + this as? T? + } + } } \ No newline at end of file