Skip to content

Commit

Permalink
add: Providers WebView support
Browse files Browse the repository at this point in the history
  • Loading branch information
rhenwinch committed Apr 10, 2024
1 parent 9be4a53 commit fab12a1
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 44 deletions.
53 changes: 42 additions & 11 deletions app/src/main/kotlin/com/flixclusive/mobile/MobileApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHostState
Expand All @@ -18,9 +20,11 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.rememberNavController
import com.flixclusive.core.ui.mobile.InternetMonitorSnackbar
Expand All @@ -36,6 +40,7 @@ import com.flixclusive.mobile.component.BottomBar
import com.flixclusive.mobile.component.FilmCoverPreview
import com.flixclusive.mobile.component.FilmPreviewBottomSheet
import com.flixclusive.model.provider.SourceDataState
import com.flixclusive.provider.util.FlixclusiveWebView
import com.flixclusive.util.AppNavHost
import com.flixclusive.util.currentScreenAsState
import com.flixclusive.util.navigateIfResumed
Expand Down Expand Up @@ -63,6 +68,8 @@ internal fun MobileActivity.MobileApp(
var hasBeenDisconnected by remember { mutableStateOf(false) }
var fullScreenImageToShow: String? by remember { mutableStateOf(null) }

var webView: FlixclusiveWebView? by remember { mutableStateOf(null) }

val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
val skipPartiallyExpanded by remember { mutableStateOf(true) }
Expand Down Expand Up @@ -166,7 +173,13 @@ internal fun MobileActivity.MobileApp(
AppNavHost(
navController = navController,
previewFilm = viewModel::previewFilm,
play = viewModel::onPlayClick,
play = { film, episode ->
viewModel.onPlayClick(
film = film,
episode = episode,
runWebView = { webView = it }
)
},
closeApp = {
finish()
exitProcess(0)
Expand Down Expand Up @@ -207,7 +220,7 @@ internal fun MobileActivity.MobileApp(
},
onDismissRequest = viewModel::onBottomSheetClose,
onPlayClick = {
viewModel.onPlayClick()
viewModel.onPlayClick(runWebView = { webView = it })
navigateToFilmScreen()
},
onImageClick = {
Expand All @@ -216,19 +229,37 @@ internal fun MobileActivity.MobileApp(
)
}

if (uiState.sourceDataState !is SourceDataState.Idle) {
if (uiState.sourceDataState !is SourceDataState.Idle || webView != null) {
window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
SourceDataDialog(
state = uiState.sourceDataState,
canSkipExtractingPhase = sourceData?.cachedLinks?.isNotEmpty() == true,
onSkipExtractingPhase = onStartPlayer,
onConsumeDialog = {
viewModel.onConsumeSourceDataDialog(isForceClosing = true)
viewModel.onBottomSheetClose() // In case, the bottom sheet is opened
Box(
contentAlignment = Alignment.Center
) {
SourceDataDialog(
state = uiState.sourceDataState,
canSkipExtractingPhase = sourceData?.cachedLinks?.isNotEmpty() == true,
onSkipExtractingPhase = onStartPlayer,
onConsumeDialog = {
viewModel.onConsumeSourceDataDialog(isForceClosing = true)
webView?.destroy()
webView = null
viewModel.onBottomSheetClose() // In case, the bottom sheet is opened
}
)

if(webView != null) {
AndroidView(
factory = { _ -> webView!! },
update = { it.startScraping() },
modifier = Modifier
.height(0.5.dp)
.width(0.5.dp)
)
}
)
}
} else {
window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
webView?.destroy()
webView = null
}

AnimatedVisibility(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.flixclusive.model.tmdb.Movie
import com.flixclusive.model.tmdb.TMDBEpisode
import com.flixclusive.model.tmdb.TvShow
import com.flixclusive.model.tmdb.toFilmInstance
import com.flixclusive.provider.util.FlixclusiveWebView
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -152,7 +153,11 @@ internal class MobileAppViewModel @Inject constructor(
}
}

fun onPlayClick(film: Film? = null, episode: TMDBEpisode? = null) {
fun onPlayClick(
film: Film? = null,
episode: TMDBEpisode? = null,
runWebView: (FlixclusiveWebView) -> Unit,
) {
if(onPlayClickJob?.isActive == true)
return

Expand Down Expand Up @@ -190,6 +195,7 @@ internal class MobileAppViewModel @Inject constructor(
film = filmToShow,
watchHistoryItem = watchHistoryItem,
episode = episode,
runWebView = runWebView,
onSuccess = { episodeToPlay ->
_episodeToPlay.value = episodeToPlay
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.flixclusive.model.provider.SourceDataState
import com.flixclusive.model.tmdb.Season
import com.flixclusive.model.tmdb.TMDBEpisode
import com.flixclusive.model.tmdb.TvShow
import com.flixclusive.provider.util.FlixclusiveWebView
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
Expand Down Expand Up @@ -177,7 +178,10 @@ abstract class BasePlayerViewModel(
}
}

fun onProviderChange(newProvider: String) {
fun onProviderChange(
newProvider: String,
runWebView: (FlixclusiveWebView) -> Unit
) {
if (loadLinksFromNewProviderJob?.isActive == true)
return

Expand Down Expand Up @@ -206,6 +210,7 @@ abstract class BasePlayerViewModel(
resetUiState()
resetNextEpisodeQueue()
},
runWebView = runWebView,
onError = {
updateProviderSelected(oldSelectedSource)
showErrorOnUiCallback(UiText.StringResource(UtilR.string.failed_to_retrieve_provider_message_format))
Expand Down Expand Up @@ -381,7 +386,10 @@ abstract class BasePlayerViewModel(
*
* @param episodeToWatch The next episode to be played, or null if not available.
*/
fun onEpisodeClick(episodeToWatch: TMDBEpisode? = null) {
fun onEpisodeClick(
episodeToWatch: TMDBEpisode? = null,
runWebView: (FlixclusiveWebView) -> Unit
) {
if (loadLinksFromNewProviderJob?.isActive == true || loadLinksJob?.isActive == true) {
showErrorOnUiCallback(UiText.StringResource(UtilR.string.load_link_job_active_error_message))
return
Expand Down Expand Up @@ -413,7 +421,7 @@ abstract class BasePlayerViewModel(
}
}

loadSourceData(episode)
loadSourceData(episode, runWebView)
}
}

Expand All @@ -424,6 +432,7 @@ abstract class BasePlayerViewModel(
*/
fun loadSourceData(
episodeToWatch: TMDBEpisode? = null,
runWebView: (FlixclusiveWebView) -> Unit
) {
if (loadLinksFromNewProviderJob?.isActive == true || loadLinksJob?.isActive == true) {
showErrorOnUiCallback(UiText.StringResource(UtilR.string.load_link_job_active_error_message))
Expand All @@ -443,6 +452,7 @@ abstract class BasePlayerViewModel(
preferredProviderName = _uiState.value.selectedProvider,
watchHistoryItem = watchHistoryItem.value,
episode = episodeToWatch,
runWebView = runWebView,
onSuccess = { newEpisode ->
_currentSelectedEpisode.value = newEpisode

Expand Down Expand Up @@ -490,7 +500,9 @@ abstract class BasePlayerViewModel(
*
* Callback function to silently queue up the next episode
*/
fun onQueueNextEpisode() {
fun onQueueNextEpisode(
runWebView: (FlixclusiveWebView) -> Unit
) {
if (loadNextLinksJob?.isActive == true || isNextEpisodeLoaded || loadLinksJob?.isActive == true || loadLinksFromNewProviderJob?.isActive == true)
return

Expand All @@ -504,6 +516,7 @@ abstract class BasePlayerViewModel(
preferredProviderName = _uiState.value.selectedProvider,
watchHistoryItem = watchHistoryItem.value,
episode = episode,
runWebView = runWebView,
onSuccess = { newEpisode ->
nextEpisodeToUse = newEpisode
isNextEpisodeLoaded = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ object CryptographyUtil {
while (generatedLength < keyLength + ivLength) {

// Digest data (last digest if available, password data, salt if available)
if (generatedLength > 0) md.update(generatedData, generatedLength - digestLength, digestLength)
if (generatedLength > 0)
md.update(generatedData, generatedLength - digestLength, digestLength)
md.update(password)
md.update(salt, 0, 8)
md.digest(generatedData, generatedLength, digestLength)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.flixclusive.domain.provider

import android.content.Context
import com.flixclusive.core.util.common.resource.Resource
import com.flixclusive.core.util.common.ui.UiText
import com.flixclusive.data.provider.ProviderManager
Expand All @@ -11,10 +12,15 @@ import com.flixclusive.model.database.WatchHistoryItem
import com.flixclusive.model.database.util.getNextEpisodeToWatch
import com.flixclusive.model.provider.SourceData
import com.flixclusive.model.provider.SourceDataState
import com.flixclusive.model.provider.SourceLink
import com.flixclusive.model.provider.Subtitle
import com.flixclusive.model.tmdb.Film
import com.flixclusive.model.tmdb.TMDBEpisode
import com.flixclusive.model.tmdb.TvShow
import com.flixclusive.provider.ProviderApi
import com.flixclusive.provider.util.FlixclusiveWebView
import com.flixclusive.provider.util.WebViewCallback
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import javax.inject.Inject
Expand All @@ -34,6 +40,7 @@ typealias FilmKey = String

@Singleton
class SourceLinksProviderUseCase @Inject constructor(
@ApplicationContext private val context: Context,
private val sourceLinksRepository: SourceLinksRepository,
private val providersManager: ProviderManager,
private val providersRepository: ProviderRepository,
Expand Down Expand Up @@ -78,6 +85,7 @@ class SourceLinksProviderUseCase @Inject constructor(
isChangingProvider: Boolean = false,
mediaId: String? = null,
episode: TMDBEpisode? = null,
runWebView: (FlixclusiveWebView) -> Unit,
onSuccess: (TMDBEpisode?) -> Unit,
onError: (() -> Unit)? = null,
): Flow<SourceDataState> = flow {
Expand Down Expand Up @@ -143,6 +151,55 @@ class SourceLinksProviderUseCase @Inject constructor(

emit(SourceDataState.Fetching(UiText.StringResource(UtilR.string.fetching_from_provider_format, provider.name)))

if (provider.useWebView) {
runWebView(
provider.getWebView(
context = context,
callback = object : WebViewCallback {
val sourceData = getLinks(
filmId = film.id,
episode = episodeToUse
)

override suspend fun onError() {
emit(SourceDataState.Error(UiText.StringResource(UtilR.string.default_error)))
onError?.invoke()
}

override suspend fun onSuccess(episode: TMDBEpisode?) {
emit(SourceDataState.Success)
onSuccess.invoke(episode)
}

override fun onSubtitleLoaded(subtitle: Subtitle) {
sourceData.run {
if (!cachedSubtitles.contains(subtitle)) {
if (cachedSourceData != null) {
cachedSubtitles.add(0, subtitle)
} else cachedSubtitles.add(subtitle)
}
}
}

override fun onLinkLoaded(link: SourceLink) {
sourceData.run {
if (!cachedLinks.contains(link)) {
if (cachedSourceData != null) {
cachedLinks.add(0, link)
} else cachedLinks.add(link)
}
}
}

override suspend fun updateDialogState(state: SourceDataState) {
emit(state)
}
},
)!!
)
return@flow
}

val canStopLooping = i == providersList.lastIndex
val needsNewMediaId = mediaId != null && provider.name != preferredProviderName

Expand Down
Loading

0 comments on commit fab12a1

Please sign in to comment.