Skip to content

Commit

Permalink
Merge pull request #19 from jhg3410/feature/video-youtube,mute
Browse files Browse the repository at this point in the history
video player 유튜브에서 시청, 음소거 기능 추가
  • Loading branch information
jhg3410 authored Sep 2, 2024
2 parents daa9408 + 21581bd commit 3238023
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 46 deletions.
3 changes: 2 additions & 1 deletion app/src/main/java/com/jik/movie/ui/MovieApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.jik.core.designsystem.component.MovieNavigationBar
import com.jik.core.designsystem.component.MovieNavigationBarItem
Expand Down Expand Up @@ -65,7 +66,7 @@ fun MovieBottomBar(
onClick = { onNavigateToDestination(destination) },
iconImageVector = destination.icon,
selectedIconImageVector = destination.icon,
labelTextId = destination.iconTextId,
labelText = stringResource(id = destination.iconTextId),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
Expand All @@ -36,6 +35,7 @@ import com.jik.core.designsystem.component.MovieNavigationBarItemDefaults.select
import com.jik.core.designsystem.component.MovieNavigationBarItemDefaults.selectedTextColor
import com.jik.core.designsystem.component.MovieNavigationBarItemDefaults.unselectedIconColor
import com.jik.core.designsystem.component.MovieNavigationBarItemDefaults.unselectedTextColor
import com.jik.core.designsystem.icon.MovieIcons


val NavigationBarCornerSize = 24.dp
Expand Down Expand Up @@ -72,7 +72,7 @@ fun RowScope.MovieNavigationBarItem(
iconImageVector: ImageVector,
selectedIconImageVector: ImageVector,
modifier: Modifier = Modifier,
labelTextId: Int? = null,
labelText: String,
enabled: Boolean = true,
onClick: () -> Unit,
) {
Expand All @@ -95,20 +95,12 @@ fun RowScope.MovieNavigationBarItem(
.padding(vertical = 4.dp),
contentAlignment = Alignment.Center
) {
if (labelTextId == null) {
MovieNavigationBarItemIcon(
selected = selected,
iconImageVector = iconImageVector,
selectedIconImageVector = selectedIconImageVector
)
} else {
MovieNavigationBarItemLabelAndIcon(
selected = selected,
iconImageVector = iconImageVector,
selectedIconImageVector = selectedIconImageVector,
labelTextId = labelTextId
)
}
MovieNavigationBarItemLabelAndIcon(
selected = selected,
iconImageVector = iconImageVector,
selectedIconImageVector = selectedIconImageVector,
labelText = labelText
)
}
}

Expand All @@ -127,12 +119,14 @@ private fun MovieNavigationBarItemIcon(

@Composable
private fun MovieNavigationBarItemLabelAndIcon(
modifier: Modifier = Modifier,
selected: Boolean,
iconImageVector: ImageVector,
selectedIconImageVector: ImageVector,
labelTextId: Int,
labelText: String,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Expand All @@ -142,14 +136,27 @@ private fun MovieNavigationBarItemLabelAndIcon(
selectedIconImageVector = selectedIconImageVector
)
Text(
text = stringResource(id = labelTextId),
text = labelText,
color = if (selected) selectedTextColor() else unselectedTextColor(),
fontWeight = FontWeight.SemiBold,
fontSize = 12.sp
)
}
}

@Composable
fun FakeNavigationBarItemLabelAndIcon(
modifier: Modifier = Modifier,
) {
MovieNavigationBarItemLabelAndIcon(
modifier = modifier,
selected = false,
iconImageVector = MovieIcons.HomeRounded,
selectedIconImageVector = MovieIcons.HomeRounded,
labelText = ""
)
}

private object MovieNavigationBarItemDefaults {
@Composable
fun selectedIconColor() = MaterialTheme.colorScheme.onSurface
Expand Down
14 changes: 10 additions & 4 deletions feature/home/src/main/java/com/jik/feature/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ package com.jik.feature.home

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.jik.core.designsystem.component.FakeNavigationBarItemLabelAndIcon
import com.jik.core.designsystem.component.LoadingWheel
import com.jik.core.designsystem.component.NavigationBarCornerSize
import com.jik.core.designsystem.component.Refresh
import com.jik.core.model.Movie
import com.jik.core.ui.state.UiState
Expand All @@ -31,7 +33,7 @@ fun HomeScreen(
val uiState by homeViewModel.uiState.collectAsStateWithLifecycle()
val mainMovie by homeViewModel.mainMovie.collectAsStateWithLifecycle()

Box(modifier = modifier) {
Box(modifier = modifier.navigationBarsPadding()) {
Content(
modifier = Modifier
.fillMaxSize()
Expand Down Expand Up @@ -67,7 +69,11 @@ private fun Content(
onLoadMore = onLoadMore,
onPosterClick = onPosterClick
)
Spacer(modifier = Modifier.padding(bottom = NavigationBarCornerSize))
FakeNavigationBarItemLabelAndIcon(
modifier = Modifier
.alpha(0f)
.padding(vertical = 4.dp)
)
}

if (uiState is UiState.Loading && mainMovie == Movie.EMPTY) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -29,7 +30,10 @@ import com.jik.lib.videoplayer.ui.VideoPlayerScreen
import com.jik.lib.videoplayer.util.VideoPlayerControllerUtil.AUTO_HIDE_DELAY
import com.jik.lib.videoplayer.util.VideoPlayerListener.stateChangedListener
import com.jik.lib.videoplayer.util.VideoPlayerUtil.toStreamUrlOfYouTube
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlin.time.Duration.Companion.seconds

Expand All @@ -43,11 +47,16 @@ fun VideoPlayer(
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
var streamUrl: String? = remember { null }
val nonNullVideoId: String by rememberUpdatedState(newValue = videoId ?: "")

var player: ExoPlayer? by remember { mutableStateOf(null) }
var controllerVisible by remember { mutableStateOf(true) }
var isPlaying by remember { mutableStateOf(false) }
var currentPosition by remember { mutableLongStateOf(0L) }
val controllerEventChannel = remember { Channel<Unit>() }
val controllerEventChannelFlow =
remember(key1 = controllerEventChannel) { controllerEventChannel.receiveAsFlow() }
var onControllerEvent: Long by remember { mutableLongStateOf(0) }

var videoPlayerState: VideoPlayerState by remember { mutableStateOf(VideoPlayerState.Initial) }
var controllerState: VideoPlayerControllerState by remember {
Expand All @@ -63,19 +72,24 @@ fun VideoPlayer(
)
}

LaunchedEffect(key1 = controllerState, key2 = controllerVisible) {
LaunchedEffect(key1 = controllerEventChannelFlow) {
controllerEventChannelFlow.collectLatest {
onControllerEvent += 1
}
}

LaunchedEffect(key1 = controllerState, key2 = controllerVisible, key3 = onControllerEvent) {
if (controllerState == VideoPlayerControllerState.PLAYING && controllerVisible) {
delay(AUTO_HIDE_DELAY)
controllerVisible = false
}
}

if (isPlaying) {
LaunchedEffect(key1 = Unit) {
while (player != null) {
currentPosition = player?.currentPosition ?: 0L
delay(1.seconds / 30)
}

LaunchedEffect(key1 = isPlaying) {
while (isPlaying && player != null) {
currentPosition = player?.currentPosition ?: 0L
delay(1.seconds / 30)
}
}

Expand All @@ -91,7 +105,7 @@ fun VideoPlayer(
try {
player = ExoPlayer.Builder(context).build().apply {
setMediaItem(
MediaItem.fromUri(streamUrl ?: videoId.toStreamUrlOfYouTube(context)
MediaItem.fromUri(streamUrl ?: nonNullVideoId.toStreamUrlOfYouTube(context)
.also { streamUrl = it }
),
currentPosition
Expand Down Expand Up @@ -140,6 +154,7 @@ fun VideoPlayer(
PlayerLoadingWheel()
player?.let {
videoPlayerState = VideoPlayerState.CanPlay
it.volume = 0f
it.play()
}
}
Expand All @@ -159,7 +174,9 @@ fun VideoPlayer(
setErrorMessageIfError(errorCode = moviePlayer.playerError?.errorCode)
},
player = moviePlayer,
currentPosition = currentPosition
videoId = nonNullVideoId,
currentPosition = currentPosition,
visibleEventChannel = controllerEventChannel
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.jik.lib.videoplayer.component

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.VolumeOff
import androidx.compose.material.icons.automirrored.rounded.VolumeUp
import androidx.compose.material.icons.filled.Forward5
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Replay5
Expand All @@ -17,6 +19,9 @@ internal object VideoPlayerIcons {

val Forward5 = Icons.Filled.Forward5
val Backward5 = Icons.Filled.Replay5

val VolumeUp = Icons.AutoMirrored.Rounded.VolumeUp
val VolumeOFF = Icons.AutoMirrored.Rounded.VolumeOff
}

internal val iconSize = 40.dp
Loading

0 comments on commit 3238023

Please sign in to comment.