Skip to content

Commit

Permalink
Merge pull request #166 from junhyeongleeee/develop
Browse files Browse the repository at this point in the history
재생 화면 컴포즈 구현
  • Loading branch information
junhyeongleeee authored Jul 24, 2023
2 parents 4450d1b + a92c6f6 commit 63ebe2c
Show file tree
Hide file tree
Showing 16 changed files with 717 additions and 51 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ dependencies {
implementation "androidx.paging:paging-compose:$pagingComposeVersion"

// Exoplayer
implementation 'androidx.media3:media3-exoplayer:1.1.0-alpha01'
implementation "androidx.media3:media3-ui:1.1.0-alpha01"
implementation 'com.google.android.exoplayer:exoplayer:2.18.7'
// Coordinator-layout
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@ import androidx.fragment.app.viewModels
import com.boostcamp.dailyfilm.R
import com.boostcamp.dailyfilm.databinding.FragmentPlayFilmBinding
import com.boostcamp.dailyfilm.presentation.BaseFragment
import com.boostcamp.dailyfilm.presentation.calendar.CalendarActivity
import com.boostcamp.dailyfilm.presentation.calendar.DateFragment.Companion.KEY_CALENDAR_INDEX
import com.boostcamp.dailyfilm.presentation.calendar.model.DateModel
import com.boostcamp.dailyfilm.presentation.util.network.NetworkManager
import com.boostcamp.dailyfilm.presentation.util.network.NetworkState
import com.boostcamp.dailyfilm.presentation.util.PlayState
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand Down Expand Up @@ -97,7 +93,7 @@ class PlayFilmFragment : BaseFragment<FragmentPlayFilmBinding>(R.layout.fragment
}
}*/

viewModel.playState.observe(viewLifecycleOwner) {
/*viewModel.playState.observe(viewLifecycleOwner) {
when(it) {
is PlayState.Uninitialized -> {}
is PlayState.Loading -> {}
Expand All @@ -121,7 +117,7 @@ class PlayFilmFragment : BaseFragment<FragmentPlayFilmBinding>(R.layout.fragment
}
}
}
}
}*/
}

private fun initListener() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@ package com.boostcamp.dailyfilm.presentation.playfilm

import android.net.Uri
import android.util.Log
import androidx.lifecycle.*
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.boostcamp.dailyfilm.data.delete.DeleteFilmRepository
import com.boostcamp.dailyfilm.data.model.Result
import com.boostcamp.dailyfilm.data.playfilm.PlayFilmRepository
import com.boostcamp.dailyfilm.presentation.calendar.model.DateModel
import com.boostcamp.dailyfilm.presentation.util.network.NetworkManager
import com.boostcamp.dailyfilm.presentation.util.network.NetworkState
import com.boostcamp.dailyfilm.presentation.playfilm.base.ContentShowState
import com.boostcamp.dailyfilm.presentation.playfilm.base.MuteState
import com.boostcamp.dailyfilm.presentation.util.PlayState
import com.boostcamp.dailyfilm.presentation.util.UiState
import com.boostcamp.dailyfilm.presentation.util.network.NetworkManager
import com.boostcamp.dailyfilm.presentation.util.network.NetworkState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
Expand All @@ -31,27 +39,33 @@ class PlayFilmViewModel @Inject constructor(
private val _videoUri = MutableLiveData<Uri?>()
val videoUri: LiveData<Uri?> get() = _videoUri

private val _isContentShowed = MutableLiveData(true)
val isContentShowed: LiveData<Boolean> get() = _isContentShowed
private val _contentShowState = MutableStateFlow(ContentShowState(true))
val contentShowState: StateFlow<ContentShowState> get() = _contentShowState

private val _isMuted = MutableLiveData(false)
val isMuted: LiveData<Boolean> get() = _isMuted
private val _muteState = MutableStateFlow(MuteState(false))
val muteState: StateFlow<MuteState> get() = _muteState

private val _playState = MutableLiveData<PlayState>(PlayState.Uninitialized)
val playState: LiveData<PlayState> get() = _playState
private val _playState = MutableStateFlow<PlayState>(PlayState.Uninitialized)
val playState: StateFlow<PlayState> get() = _playState

private val _networkState = MutableLiveData(NetworkManager.checkNetwork())
val networkState: LiveData<NetworkState> get() = _networkState

private val _isNetworkConnectShowed = MutableLiveData(true)
val isNetworkConnectShowed: LiveData<Boolean> get() = _isNetworkConnectShowed

private val _isProgressed = MutableLiveData(false)
val isProgressed: LiveData<Boolean> get() = _isProgressed
private val _isProgressed = MutableStateFlow(false)
val isProgressed: StateFlow<Boolean> get() = _isProgressed

private val _openDialog = MutableStateFlow(false)
val openDialog : StateFlow<Boolean> get() = _openDialog

init {
loadVideo()
}
fun setDialog(value: Boolean) {
_openDialog.value = value
}

private fun checkNetwork() {
_networkState.value = NetworkManager.checkNetwork()
Expand All @@ -62,14 +76,6 @@ class PlayFilmViewModel @Inject constructor(
_text.value = text
}

fun changeShowState() {
_isContentShowed.value = _isContentShowed.value?.not()
}

fun changeMuteState() {
_isMuted.value = _isMuted.value?.not()
}

fun setNetworkState(state: NetworkState) {
viewModelScope.launch {
// isNetworkConnected 는 연결 여부를 떠나 Playing 중이면 보여 주지 않는다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.boostcamp.dailyfilm.presentation.calendar.model.DateModel
import com.boostcamp.dailyfilm.presentation.playfilm.PlayFilmFragment
import com.boostcamp.dailyfilm.presentation.playfilm.compose.PlayFilmComposeFragment

class PlayFilmPageAdapter(
private val dateList: ArrayList<DateModel>,
Expand All @@ -13,7 +14,7 @@ class PlayFilmPageAdapter(

override fun getItemCount(): Int = dateList.size

override fun createFragment(position: Int): PlayFilmFragment {
return PlayFilmFragment.newInstance(dateList[position])
override fun createFragment(position: Int): PlayFilmComposeFragment {
return PlayFilmComposeFragment.newInstance(dateList[position])
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.boostcamp.dailyfilm.presentation.playfilm.base

import com.airbnb.lottie.compose.LottieClipSpec

class ContentShowState(init: Boolean): LottieState(init) {
override val clipSpec: LottieClipSpec
get() = if (state) {
LottieClipSpec.Progress(START, MID)
} else {
LottieClipSpec.Progress(MID, FINISH)
}

companion object {
const val START = 0.67f
const val MID = 0.25f
const val FINISH = 0.67f
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.boostcamp.dailyfilm.presentation.playfilm.base

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.airbnb.lottie.compose.LottieClipSpec

abstract class LottieState(initial: Boolean) {
var state by mutableStateOf(initial)

abstract val clipSpec: LottieClipSpec

fun updateState() {
state = !state
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.boostcamp.dailyfilm.presentation.playfilm.base

import com.airbnb.lottie.compose.LottieClipSpec

class MuteState(init: Boolean): LottieState(init) {

override val clipSpec: LottieClipSpec
get() = if (state) {
LottieClipSpec.Progress(START, MID)
} else {
LottieClipSpec.Progress(MID, FINISH)
}

companion object {
const val START = 0.0f
const val MID = 0.5f
const val FINISH = 1.0f
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package com.boostcamp.dailyfilm.presentation.playfilm.compose

import android.annotation.SuppressLint
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.os.Bundle
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import com.boostcamp.dailyfilm.R
import com.boostcamp.dailyfilm.databinding.FragmentPlayFilmComposeBinding
import com.boostcamp.dailyfilm.presentation.BaseFragment
import com.boostcamp.dailyfilm.presentation.calendar.CalendarActivity
import com.boostcamp.dailyfilm.presentation.calendar.CalendarActivity.Companion.KEY_EDIT_STATE
import com.boostcamp.dailyfilm.presentation.calendar.DateFragment.Companion.KEY_CALENDAR_INDEX
import com.boostcamp.dailyfilm.presentation.calendar.model.DateModel
import com.boostcamp.dailyfilm.presentation.playfilm.PlayFilmActivityViewModel
import com.boostcamp.dailyfilm.presentation.playfilm.PlayFilmBottomSheetDialog
import com.boostcamp.dailyfilm.presentation.playfilm.PlayFilmViewModel
import com.boostcamp.dailyfilm.presentation.playfilm.model.EditState
import com.boostcamp.dailyfilm.presentation.selectvideo.SelectVideoActivity
import com.boostcamp.dailyfilm.presentation.selectvideo.SelectVideoActivity.Companion.DATE_VIDEO_ITEM
import com.boostcamp.dailyfilm.presentation.ui.theme.DailyFilmTheme
import com.boostcamp.dailyfilm.presentation.uploadfilm.UploadFilmActivity
import com.boostcamp.dailyfilm.presentation.uploadfilm.model.DateAndVideoModel
import com.boostcamp.dailyfilm.presentation.util.network.NetworkManager
import com.boostcamp.dailyfilm.presentation.util.network.NetworkState
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class PlayFilmComposeFragment :
BaseFragment<FragmentPlayFilmComposeBinding>(R.layout.fragment_play_film_compose) {

private val viewModel: PlayFilmViewModel by viewModels()
private val activityViewModel: PlayFilmActivityViewModel by activityViewModels()
private lateinit var playFilmBottomSheetDialog: PlayFilmBottomSheetDialog

private val startForResult: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == RESULT_OK && result.data != null) {
val text = result.data?.getStringExtra(KET_EDIT_TEXT) ?: ""
viewModel.setDateModel(text)
}
}

private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
viewModel.setNetworkState(NetworkState.AVAILABLE)
}

override fun onLost(network: Network) {
super.onLost(network)
viewModel.setNetworkState(NetworkState.LOST)
}
}

@SuppressLint("ShowToast")
override fun initView() {
binding.playFilmCompose.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
DailyFilmTheme(requireActivity()) {
PlayFilmUI(
requireActivity(),
viewModel = viewModel,
setResultCalendar = { state ->
activity?.let {
it.setResult(
RESULT_OK, Intent(
it, CalendarActivity::class.java
).apply {
putExtra(
KEY_CALENDAR_INDEX,
activityViewModel.calendarIndex
)
putExtra(KEY_DATE_MODEL, state.dateModel)
})
it.finish()
}
},
dialogEvent = { resId ->
when(resId) {
R.string.delete -> {
viewModel.setDialog(true)
}
R.string.re_upload -> {
activity?.let {
it.startActivity(
Intent(
it.applicationContext, SelectVideoActivity::class.java
).apply {
putExtra(
KEY_CALENDAR_INDEX,
activityViewModel.calendarIndex
)
putExtra(KEY_DATE_MODEL, viewModel.dateModel)
putExtra(KEY_EDIT_STATE, EditState.RE_UPLOAD)
putExtra(
DATE_VIDEO_ITEM,
DateAndVideoModel(
viewModel.videoUri.value ?: return@PlayFilmUI,
viewModel.dateModel.getDate()
)
)
}
)
it.finish()
}
}
R.string.edit_text -> {
startForResult.launch(
Intent(activity?.applicationContext, UploadFilmActivity::class.java).apply {
putExtra(KEY_CALENDAR_INDEX, activityViewModel.calendarIndex)
putExtra(
DATE_VIDEO_ITEM,
DateAndVideoModel(
viewModel.videoUri.value ?: return@PlayFilmUI,
viewModel.dateModel.getDate()
)
)
putExtra(KEY_EDIT_STATE, EditState.EDIT_CONTENT)
putExtra(KEY_DATE_MODEL, viewModel.dateModel)
}
)
}
}
}
)
}
}
}
initBinding()
initDialog()
}

private fun initBinding() {
binding.viewModel = viewModel
}

private fun initDialog() {
playFilmBottomSheetDialog =
PlayFilmBottomSheetDialog(viewModel, activityViewModel, startForResult)
}

override fun onStart() {
super.onStart()
NetworkManager.registerNetworkCallback(networkCallback)
}

override fun onResume() {
super.onResume()
binding.backgroundPlayer.player?.play()
}

override fun onPause() {
binding.backgroundPlayer.player?.let { player ->
if (player.isPlaying) {
player.seekTo(0L)
player.pause()
}
}
super.onPause()
}

override fun onStop() {
super.onStop()
NetworkManager.terminateNetworkCallback(networkCallback)
}

override fun onDestroyView() {
binding.backgroundPlayer.player?.release()
binding.backgroundPlayer.player = null
super.onDestroyView()
}

companion object {
const val KEY_DATE_MODEL = "dateModel"
const val KET_EDIT_TEXT = "editText"
fun newInstance(dateModel: DateModel) =
PlayFilmComposeFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_DATE_MODEL, dateModel)
}
}
}
}
Loading

0 comments on commit 63ebe2c

Please sign in to comment.