Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QA에서 발견한 버그 개선 및 MyPage -> Player 이동 #339

Merged
merged 14 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
android:usesCleartextTraffic="true">
<activity
android:name=".feature.login.LoginActivity"
android:exported="true">
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand All @@ -25,7 +26,8 @@

<activity
android:name=".MainActivity"
android:exported="true" />
android:exported="true"
android:screenOrientation="portrait" />

<service
android:name=".mediasession.PlaybackService"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.ohdodok.catchytape.core.domain.utils

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

fun <T> Flow<T>.throttleFirst(windowDuration: Long): Flow<T> = flow {
var lastEmissionTime = 0L
collect { upstream ->
val currentTime = System.currentTimeMillis()
if (currentTime - lastEmissionTime > windowDuration) {
lastEmissionTime = currentTime
emit(upstream)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract class BaseFragment<VB : ViewDataBinding>(
_binding = null
}

protected fun setupBackStack(toolbar: MaterialToolbar){
protected fun setupBackStack(toolbar: MaterialToolbar) {
toolbar.setNavigationOnClickListener {
findNavController().popBackStack()
}
Expand All @@ -56,5 +56,4 @@ abstract class BaseFragment<VB : ViewDataBinding>(
protected fun showMessage(@StringRes messageId: Int) {
Snackbar.make(this.requireView(), messageId, Snackbar.LENGTH_LONG).show()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.ohdodok.catchytape.core.ui

import android.view.View
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow

fun View.clicksFlow(): Flow<Unit> = callbackFlow {
setOnClickListener { trySend(Unit) }
awaitClose { setOnClickListener(null) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
xmlns:tools="http://schemas.android.com/tools">

<data>

<variable
name="viewModel"
type="com.ohdodok.catchytape.core.ui.PlaylistBottomSheetViewModel" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:background="@color/surface_bright">

<TextView
Expand Down Expand Up @@ -43,11 +44,9 @@
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:maxHeight="400dp"
android:orientation="vertical"
android:paddingHorizontal="@dimen/margin_horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ private fun NavController.navigateToPlayerScreen() {
NavDeepLinkRequest.Builder.fromUri("android-app://com.ohdodok.catchytape/player_fragment".toUri())
.build()

this.navigate(request)
navigate(request)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package com.ohdodok.catchytape.feature.mypage

import android.os.Bundle
import android.view.View
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
import androidx.fragment.app.viewModels
import androidx.navigation.NavController
import androidx.navigation.NavDeepLinkRequest
import androidx.navigation.fragment.findNavController
import com.ohdodok.catchytape.core.ui.BaseFragment
import com.ohdodok.catchytape.core.ui.MusicAdapter
import com.ohdodok.catchytape.core.ui.Orientation
Expand All @@ -28,7 +32,10 @@ class MyMusicsFragment : BaseFragment<FragmentMyMusicsBinding>(R.layout.fragment
}

private fun setupRecyclerView() {
binding.rvMyMusics.adapter = MusicAdapter(Orientation.VERTICAL)
binding.rvMyMusics.adapter = MusicAdapter(
musicItemOrientation = Orientation.VERTICAL,
listener = viewModel
)
}

private fun observeEvents() {
Expand All @@ -38,8 +45,17 @@ class MyMusicsFragment : BaseFragment<FragmentMyMusicsBinding>(R.layout.fragment
is MyMusicsEvent.ShowMessage -> {
showMessage(event.error.toMessageId())
}
is MyMusicsEvent.NavigateToPlayerScreen -> {
findNavController().navigateToPlayerScreen()
}
}
}
}
}
}

private fun NavController.navigateToPlayerScreen() {
val request =
NavDeepLinkRequest.Builder.fromUri("android-app://com.ohdodok.catchytape/player_fragment".toUri()).build()
navigate(request)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.ohdodok.catchytape.core.domain.model.CtErrorType
import com.ohdodok.catchytape.core.domain.model.CtException
import com.ohdodok.catchytape.core.domain.model.Music
import com.ohdodok.catchytape.core.domain.repository.MusicRepository
import com.ohdodok.catchytape.core.domain.usecase.player.CurrentPlaylistUseCase
import com.ohdodok.catchytape.core.ui.MusicAdapter
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -29,12 +31,14 @@ sealed interface MyMusicsEvent {
data class ShowMessage(
val error: CtErrorType
) : MyMusicsEvent
data object NavigateToPlayerScreen : MyMusicsEvent
}

@HiltViewModel
class MyMusicsViewModel @Inject constructor(
private val musicRepository: MusicRepository,
) : ViewModel() {
private val currentPlaylistUseCase: CurrentPlaylistUseCase,
) : ViewModel(), MusicAdapter.Listener {

private val _uiState = MutableStateFlow(MyMusicsUiState())
val uiState: StateFlow<MyMusicsUiState> = _uiState.asStateFlow()
Expand Down Expand Up @@ -67,4 +71,11 @@ class MyMusicsViewModel @Inject constructor(
}
.launchIn(viewModelScopeWithExceptionHandler)
}

override fun onClick(music: Music) {
currentPlaylistUseCase.playMusic(music)
viewModelScope.launch {
_events.emit(MyMusicsEvent.NavigateToPlayerScreen)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.view.View
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
import androidx.fragment.app.viewModels
import androidx.navigation.NavController
import androidx.navigation.NavDeepLinkRequest
import androidx.navigation.fragment.findNavController
import com.ohdodok.catchytape.core.ui.BaseFragment
Expand Down Expand Up @@ -37,6 +38,9 @@ class MyPageFragment : BaseFragment<FragmentMyPageBinding>(R.layout.fragment_my_
is MyPageEvent.ShowMessage -> {
showMessage(event.error.toMessageId())
}
is MyPageEvent.NavigateToPlayerScreen -> {
findNavController().navigateToPlayerScreen()
}
}
}
}
Expand All @@ -56,11 +60,20 @@ class MyPageFragment : BaseFragment<FragmentMyPageBinding>(R.layout.fragment_my_
}

private fun setupRecyclerView() {
binding.rvMusics.adapter = MusicAdapter(Orientation.VERTICAL)
binding.rvMusics.adapter = MusicAdapter(
musicItemOrientation = Orientation.VERTICAL,
listener = viewModel
)
}

override fun onStart() {
super.onStart()
viewModel.fetchMyMusics(count = 3)
}
}

private fun NavController.navigateToPlayerScreen() {
val request =
NavDeepLinkRequest.Builder.fromUri("android-app://com.ohdodok.catchytape/player_fragment".toUri()).build()
navigate(request)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.ohdodok.catchytape.core.domain.model.CtErrorType
import com.ohdodok.catchytape.core.domain.model.CtException
import com.ohdodok.catchytape.core.domain.model.Music
import com.ohdodok.catchytape.core.domain.repository.MusicRepository
import com.ohdodok.catchytape.core.domain.usecase.player.CurrentPlaylistUseCase
import com.ohdodok.catchytape.core.ui.MusicAdapter
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -28,7 +30,8 @@ data class MyPageUiState(
@HiltViewModel
class MyPageViewModel @Inject constructor(
private val musicRepository: MusicRepository,
) : ViewModel() {
private val currentPlaylistUseCase: CurrentPlaylistUseCase,
) : ViewModel(), MusicAdapter.Listener {

private val _uiState = MutableStateFlow(MyPageUiState())
val uiState: StateFlow<MyPageUiState> = _uiState.asStateFlow()
Expand All @@ -55,8 +58,16 @@ class MyPageViewModel @Inject constructor(
}
.launchIn(viewModelScopeWithExceptionHandler)
}

override fun onClick(music: Music) {
currentPlaylistUseCase.playMusic(music)
viewModelScope.launch {
_events.emit(MyPageEvent.NavigateToPlayerScreen)
}
}
}

sealed interface MyPageEvent {
data class ShowMessage(val error: CtErrorType) : MyPageEvent
data object NavigateToPlayerScreen : MyPageEvent
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import android.view.View
import android.widget.SeekBar
import androidx.core.view.ViewCompat
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.media3.exoplayer.ExoPlayer
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import com.ohdodok.catchytape.core.domain.utils.throttleFirst
import com.ohdodok.catchytape.core.ui.BaseFragment
import com.ohdodok.catchytape.core.ui.RootViewInsetsCallback
import com.ohdodok.catchytape.core.ui.clicksFlow
import com.ohdodok.catchytape.feature.player.databinding.FragmentPlayerBinding
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject

const val millisecondsPerSecond = 1000
Expand Down Expand Up @@ -67,19 +72,20 @@ class PlayerFragment : BaseFragment<FragmentPlayerBinding>(R.layout.fragment_pla
player.onPreviousBtnClick()
}

binding.btnAddToPlaylist.setOnClickListener {
findNavController().showPlaylistBottomSheet()
}
binding.btnAddToPlaylist.clicksFlow()
.throttleFirst(500)
.onEach { findNavController().showPlaylistBottomSheet() }
.launchIn(viewLifecycleOwner.lifecycleScope)
}

private fun NavController.showPlaylistBottomSheet() {
val musicId = viewModel.uiState.value.currentMusic?.id ?: return

val action = PlayerFragmentDirections.actionPlayerFragmentToPlaylistBottomSheet(musicId = musicId)
this.navigate(action)
navigate(action)
}
}

fun NavController.navigateToPlayer() {
this.navigate(R.id.player_nav_graph)
navigate(R.id.player_nav_graph)
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ohdodok.catchytape.feature.player

import androidx.lifecycle.ViewModel

import androidx.lifecycle.viewModelScope
import com.ohdodok.catchytape.core.domain.model.CtErrorType
import com.ohdodok.catchytape.core.domain.model.CtException
Expand Down Expand Up @@ -28,7 +29,6 @@ data class PlayerState(
val duration: Int = 0,
val isNextEnable: Boolean = false,
val isPreviousEnable: Boolean = false

) {
val isPlayEnable: Boolean
get() = currentMusic != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ private fun NavController.navigateToPlayerScreen() {
val targetUri = "android-app://com.ohdodok.catchytape/player_fragment".toUri()
val request = NavDeepLinkRequest.Builder.fromUri(targetUri).build()

this.navigate(request)
navigate(request)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ import android.view.View
import androidx.core.view.ViewCompat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import com.ohdodok.catchytape.core.domain.utils.throttleFirst
import com.ohdodok.catchytape.core.ui.BaseFragment
import com.ohdodok.catchytape.core.ui.PlaylistAdapter
import com.ohdodok.catchytape.core.ui.RootViewInsetsCallback
import com.ohdodok.catchytape.core.ui.clicksFlow
import com.ohdodok.catchytape.core.ui.cterror.toMessageId
import com.ohdodok.catchytape.feature.playlist.databinding.FragmentPlaylistsBinding
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

@AndroidEntryPoint
class PlaylistsFragment : BaseFragment<FragmentPlaylistsBinding>(R.layout.fragment_playlists),
Expand All @@ -28,11 +33,15 @@ class PlaylistsFragment : BaseFragment<FragmentPlaylistsBinding>(R.layout.fragme
viewModel.fetchPlaylists()

observeEvents()
val newPlaylistDialog = NewPlaylistDialog()
binding.fabNewPlaylist.setOnClickListener {
newPlaylistDialog.show(childFragmentManager, NewPlaylistDialog.TAG)
}
setupButton()
}

private fun setupButton() {
val newPlaylistDialog = NewPlaylistDialog()
binding.fabNewPlaylist.clicksFlow()
.throttleFirst(500)
.onEach { newPlaylistDialog.show(childFragmentManager, NewPlaylistDialog.TAG) }
.launchIn(viewLifecycleOwner.lifecycleScope)
}

private fun observeEvents() {
Expand Down
Loading