Skip to content

Commit

Permalink
feat: Implement functionality of the VideoLibraryScreen
Browse files Browse the repository at this point in the history
  • Loading branch information
azrael8576 committed Dec 5, 2023
1 parent 42f57ac commit 2af7897
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,11 @@ class PqAppStateTest {
)
}

assertThat(state.topLevelDestinations).hasSize(3)
assertThat(state.topLevelDestinations).hasSize(4)
assertThat(state.topLevelDestinations[0].name).ignoringCase().contains("home")
assertThat(state.topLevelDestinations[1].name).ignoringCase().contains("photo")
assertThat(state.topLevelDestinations[2].name).ignoringCase().contains("contact_me")
assertThat(state.topLevelDestinations[2].name).ignoringCase().contains("video")
assertThat(state.topLevelDestinations[3].name).ignoringCase().contains("contact_me")
}

@Test
Expand Down Expand Up @@ -280,6 +281,7 @@ private fun rememberTestNavController(): TestNavHostController {
composable("a") { }
composable("b") { }
composable("c") { }
composable("d") { }
}
}
}
Expand Down
3 changes: 0 additions & 3 deletions app/src/main/java/com/wei/picquest/ui/PqApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ import com.wei.picquest.core.manager.SnackbarState
import com.wei.picquest.core.utils.UiText
import com.wei.picquest.navigation.PqNavHost
import com.wei.picquest.navigation.TopLevelDestination
import timber.log.Timber

@OptIn(
ExperimentalMaterial3Api::class,
Expand Down Expand Up @@ -295,8 +294,6 @@ private fun PqBottomBar(

private fun NavDestination?.isTopLevelDestinationInHierarchy(destination: TopLevelDestination) =
this?.hierarchy?.any {
Timber.e("PQ isTopLevelDestinationInHierarchy " + it.route.toString())
Timber.e("PQ destination " + destination.name.toString())
it.route?.contains(destination.name, true) ?: false
} ?: false

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.wei.picquest.core.data.di

import com.wei.picquest.core.data.repository.DefaultSearchImagesRepository
import com.wei.picquest.core.data.repository.DefaultSearchVideosRepository
import com.wei.picquest.core.data.repository.DefaultUserDataRepository
import com.wei.picquest.core.data.repository.SearchImagesRepository
import com.wei.picquest.core.data.repository.SearchVideosRepository
import com.wei.picquest.core.data.repository.UserDataRepository
import com.wei.picquest.core.data.utils.ConnectivityManagerNetworkMonitor
import com.wei.picquest.core.data.utils.NetworkMonitor
Expand All @@ -20,6 +22,11 @@ interface DataModule {
searchImagesRepository: DefaultSearchImagesRepository,
): SearchImagesRepository

@Binds
fun bindsSearchVideosRepository(
searchVideosRepository: DefaultSearchVideosRepository,
): SearchVideosRepository

@Binds
fun bindsNetworkMonitor(
networkMonitor: ConnectivityManagerNetworkMonitor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class DefaultSearchVideoRepository @Inject constructor(
class DefaultSearchVideosRepository @Inject constructor(
private val pqNetworkDataSource: PqNetworkDataSource,
) : SearchVideoRepository {
) : SearchVideosRepository {

override suspend fun getSearchVideo(query: String): Flow<PagingData<VideoDetail>> {
return Pager(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import androidx.paging.PagingData
import com.wei.picquest.core.data.model.VideoDetail
import kotlinx.coroutines.flow.Flow

interface SearchVideoRepository {
interface SearchVideosRepository {

suspend fun getSearchVideo(query: String): Flow<PagingData<VideoDetail>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ interface RetrofitPixabayApi {
/**
* https://pixabay.com/api/videos/?key=${api key}&q=yellow+flowers
*/
@GET("/videos/")
@GET("./videos/")
suspend fun searchVideos(
@Query("key") apiKey: String = API_KEY,
@Query("q") query: String,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,26 +1,48 @@
package com.wei.picquest.feature.video.videolibrary

import android.net.Uri
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.windowInsetsBottomHeight
import androidx.compose.foundation.layout.windowInsetsTopHeight
import androidx.compose.foundation.pager.VerticalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.net.toUri
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DefaultDataSource
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.ProgressiveMediaSource
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import androidx.navigation.NavController
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import com.wei.picquest.core.data.model.VideoDetail
import com.wei.picquest.core.designsystem.component.FunctionalityNotAvailablePopup
import com.wei.picquest.core.designsystem.component.ThemePreviews
import com.wei.picquest.core.designsystem.theme.PqTheme

/**
*
Expand Down Expand Up @@ -54,12 +76,17 @@ import com.wei.picquest.core.designsystem.theme.PqTheme
@Composable
internal fun VideoLibraryRoute(
navController: NavController,
viewModel: VideoLibraryViewModel = hiltViewModel(),
) {
VideoLibraryScreen()
val lazyPagingItems = viewModel.videosState.collectAsLazyPagingItems()

VideoLibraryScreen(lazyPagingItems)
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun VideoLibraryScreen(
lazyPagingItems: LazyPagingItems<VideoDetail>,
withTopSpacer: Boolean = true,
withBottomSpacer: Boolean = true,
) {
Expand All @@ -84,16 +111,20 @@ internal fun VideoLibraryScreen(
Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing))
}

Column {
Spacer(modifier = Modifier.weight(1f))
Text(
text = "Screen not available \uD83D\uDE48",
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier
.semantics { contentDescription = "" },
)
Spacer(modifier = Modifier.weight(1f))
val pagerState = rememberPagerState(
initialPage = 0,
initialPageOffsetFraction = 0f,
pageCount = { lazyPagingItems.itemCount },
)

VerticalPager(
state = pagerState,
modifier = Modifier.fillMaxSize(),
) { page ->
val videoDetail = lazyPagingItems[page]
videoDetail?.let {
VideoPlayer(uri = it.videos.tiny.url.toUri())
}
}

if (withBottomSpacer) {
Expand All @@ -103,10 +134,66 @@ internal fun VideoLibraryScreen(
}
}

@ThemePreviews
@androidx.annotation.OptIn(UnstableApi::class)
@Composable
fun VideoLibraryScreenPreview() {
PqTheme {
VideoLibraryScreen()
fun VideoPlayer(uri: Uri) {
val context = LocalContext.current
val isPlayerReady = remember { mutableStateOf(false) }

val exoPlayer = remember(uri) {
ExoPlayer.Builder(context).build().apply {
playWhenReady = true
videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT
repeatMode = Player.REPEAT_MODE_ONE

addListener(object : Player.Listener {
override fun onPlaybackStateChanged(state: Int) {
isPlayerReady.value = (state == Player.STATE_READY)
}
})

val dataSourceFactory: DataSource.Factory = DefaultDataSource.Factory(context)
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(uri))

setMediaSource(mediaSource)
prepare()
}
}

DisposableEffect(uri) {
onDispose {
exoPlayer.release()
}
}

Box {
AndroidView(
factory = {
PlayerView(it).apply {
useController = false
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
player = exoPlayer
alpha = if (isPlayerReady.value) 0f else 1f
}
},
modifier = Modifier.fillMaxSize(),
)

if (!isPlayerReady.value) {
LoadingView()
}
}
}

@Composable
private fun LoadingView() {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
) {
CircularProgressIndicator(modifier = Modifier.size(30.dp))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.wei.picquest.feature.video.videolibrary

import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.wei.picquest.core.base.BaseViewModel
import com.wei.picquest.core.data.model.VideoDetail
import com.wei.picquest.core.data.repository.SearchVideosRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class VideoLibraryViewModel @Inject constructor(
private val searchVideoRepository: SearchVideosRepository,
) : BaseViewModel<
VideoLibraryViewAction,
VideoLibraryViewState,
>(VideoLibraryViewState) {

private val _videosState: MutableStateFlow<PagingData<VideoDetail>> =
MutableStateFlow(value = PagingData.empty())
val videosState: MutableStateFlow<PagingData<VideoDetail>> get() = _videosState

init {
searchVideos("cat")
}

private fun searchVideos(query: String) {
viewModelScope.launch {
searchVideoRepository.getSearchVideo(query)
.distinctUntilChanged()
.cachedIn(viewModelScope)
.collect { pagingData ->
_videosState.value = pagingData
}
}
}

override fun dispatch(action: VideoLibraryViewAction) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.wei.picquest.feature.video.videolibrary

import com.wei.picquest.core.base.Action
import com.wei.picquest.core.base.State

sealed class VideoLibraryViewAction : Action

object VideoLibraryViewState : State

0 comments on commit 2af7897

Please sign in to comment.