From 615373d7e492d5050eb7b7a3edd4343f91cffc23 Mon Sep 17 00:00:00 2001 From: algosketch Date: Thu, 30 Nov 2023 21:57:49 +0900 Subject: [PATCH 001/205] =?UTF-8?q?feat=20:=20MusicAdapter=EC=97=90=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EB=A6=AC=EC=8A=A4=EB=84=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ohdodok/catchytape/core/ui/MusicAdapter.kt | 10 ++++++++-- .../ui/src/main/res/layout/item_music_horizontal.xml | 5 +++++ .../ui/src/main/res/layout/item_music_vertical.xml | 5 +++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt index 34cb5c5..eb62c24 100644 --- a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt +++ b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt @@ -10,8 +10,10 @@ import com.ohdodok.catchytape.core.ui.databinding.ItemMusicHorizontalBinding import com.ohdodok.catchytape.core.ui.databinding.ItemMusicVerticalBinding -class MusicAdapter(private val musicItemOrientation: Orientation) : - ListAdapter(MusicDiffUtil) { +class MusicAdapter( + private val musicItemOrientation: Orientation, + private val listener: Listener = Listener { }, // todo : 클릭 이벤트 구현이 완료되면 디폴트 값을 지워주세요. +) : ListAdapter(MusicDiffUtil) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (musicItemOrientation) { @@ -63,6 +65,10 @@ class MusicAdapter(private val musicItemOrientation: Orientation) : ) } } + + fun interface Listener { + fun onClick(music: Music) + } } object MusicDiffUtil : DiffUtil.ItemCallback() { diff --git a/android/core/ui/src/main/res/layout/item_music_horizontal.xml b/android/core/ui/src/main/res/layout/item_music_horizontal.xml index 0c1edcb..6a5d5f9 100644 --- a/android/core/ui/src/main/res/layout/item_music_horizontal.xml +++ b/android/core/ui/src/main/res/layout/item_music_horizontal.xml @@ -8,11 +8,16 @@ + + + + Date: Thu, 30 Nov 2023 21:58:52 +0900 Subject: [PATCH 002/205] =?UTF-8?q?refactor=20:=20HomeFragment=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=84=A4=EC=A0=95=20=ED=95=A8=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/feature/home/HomeFragment.kt | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt b/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt index 1836d49..de61724 100644 --- a/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt +++ b/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt @@ -21,10 +21,26 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.viewModel = viewModel + binding.rvRecentlyAddedSong.adapter = MusicAdapter(musicItemOrientation = Orientation.HORIZONTAL) observeEvents() viewModel.fetchUploadedMusics() + setupButtons() + } + + private fun observeEvents() { + repeatOnStarted { + viewModel.events.collect { event -> + when (event) { + is HomeEvent.ShowMessage -> { + showMessage(event.error.toMessageId()) + } + } + } + } + } + private fun setupButtons() { binding.ibUpload.setOnClickListener { val request = NavDeepLinkRequest.Builder .fromUri("android-app://com.ohdodok.catchytape/upload_fragment".toUri()) @@ -39,16 +55,4 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { findNavController().navigate(request) } } - - private fun observeEvents() { - repeatOnStarted { - viewModel.events.collect { event -> - when (event) { - is HomeEvent.ShowMessage -> { - showMessage(event.error.toMessageId()) - } - } - } - } - } } \ No newline at end of file From 9b0b89487793d1069b722221346a52f78881045e Mon Sep 17 00:00:00 2001 From: youlalala Date: Thu, 30 Nov 2023 22:09:33 +0900 Subject: [PATCH 003/205] =?UTF-8?q?feat=20:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EC=9E=AC=EC=83=9D=20=EB=AA=A9=EB=A1=9D=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/core/data/api/UserApi.kt | 4 +++ .../data/repository/PlaylistRepositoryImpl.kt | 15 +++++++--- .../domain/repository/PlaylistRepository.kt | 3 ++ .../feature/player/PlayerFragment.kt | 4 +-- .../feature/player/PlayerViewModel.kt | 30 +++++++++++++++++-- 5 files changed, 48 insertions(+), 8 deletions(-) diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UserApi.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UserApi.kt index a9b3d37..1238e9d 100644 --- a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UserApi.kt +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UserApi.kt @@ -2,6 +2,7 @@ package com.ohdodok.catchytape.core.data.api import com.ohdodok.catchytape.core.data.model.LoginRequest import com.ohdodok.catchytape.core.data.model.LoginResponse +import com.ohdodok.catchytape.core.data.model.MusicResponse import com.ohdodok.catchytape.core.data.model.NicknameResponse import com.ohdodok.catchytape.core.data.model.SignUpRequest import retrofit2.Response @@ -32,4 +33,7 @@ interface UserApi { suspend fun verify( @Header("Authorization") accessToken: String, ): Response + + @GET("users/recent-played") + suspend fun getRecentPlayed(): List } \ No newline at end of file diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/PlaylistRepositoryImpl.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/PlaylistRepositoryImpl.kt index defecec..7dcc49c 100644 --- a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/PlaylistRepositoryImpl.kt +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/PlaylistRepositoryImpl.kt @@ -1,7 +1,10 @@ package com.ohdodok.catchytape.core.data.repository import com.ohdodok.catchytape.core.data.api.PlaylistApi +import com.ohdodok.catchytape.core.data.api.UserApi import com.ohdodok.catchytape.core.data.model.PlaylistRequest +import com.ohdodok.catchytape.core.data.model.toDomains +import com.ohdodok.catchytape.core.domain.model.Music import com.ohdodok.catchytape.core.domain.model.Playlist import com.ohdodok.catchytape.core.domain.repository.PlaylistRepository import kotlinx.coroutines.flow.Flow @@ -10,19 +13,23 @@ import javax.inject.Inject class PlaylistRepositoryImpl @Inject constructor( - private val playlistApi: PlaylistApi + private val playlistApi: PlaylistApi, + private val userApi: UserApi, ) : PlaylistRepository { - override fun getPlaylists(): Flow> = flow { val playlistResponse = playlistApi.getPlaylists() - emit( playlistResponse.map { it.toDomain() }) + emit(playlistResponse.map { it.toDomain() }) } - override suspend fun postPlaylist(title: String) { playlistApi.postPlaylist(PlaylistRequest(title = title)) } + + override fun getRecentPlaylist(): Flow> = flow { + val response = userApi.getRecentPlayed() + emit(response.toDomains()) + } } diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/PlaylistRepository.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/PlaylistRepository.kt index bb2b7eb..591e867 100644 --- a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/PlaylistRepository.kt +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/PlaylistRepository.kt @@ -1,5 +1,6 @@ package com.ohdodok.catchytape.core.domain.repository +import com.ohdodok.catchytape.core.domain.model.Music import com.ohdodok.catchytape.core.domain.model.Playlist import kotlinx.coroutines.flow.Flow @@ -8,4 +9,6 @@ interface PlaylistRepository { fun getPlaylists(): Flow> suspend fun postPlaylist(title: String) + + fun getRecentPlaylist(): Flow> } \ No newline at end of file diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt index b29608a..deee0dc 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt @@ -9,9 +9,9 @@ import androidx.media3.exoplayer.ExoPlayer import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import com.ohdodok.catchytape.core.ui.BaseFragment +import com.ohdodok.catchytape.core.ui.toMessageId import com.ohdodok.catchytape.feature.player.databinding.FragmentPlayerBinding import dagger.hilt.android.AndroidEntryPoint -import timber.log.Timber import javax.inject.Inject const val millisecondsPerSecond = 1000 @@ -72,7 +72,7 @@ class PlayerFragment : BaseFragment(R.layout.fragment_pla repeatOnStarted { viewModel.events.collect { event -> when (event) { - is PlayerEvent.ShowError -> Timber.d(event.error.message ?: "") + is PlayerEvent.ShowError -> showMessage(event.error.toMessageId()) } } } diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt index 9a336e1..2aa8539 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt @@ -2,30 +2,39 @@ 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 +import com.ohdodok.catchytape.core.domain.model.Music +import com.ohdodok.catchytape.core.domain.repository.PlaylistRepository import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.coroutines.plus import javax.inject.Inject data class PlayerState( + val playlist: List = emptyList(), val isPlaying: Boolean = false, val currentPositionSecond: Int = 0, val duration: Int = 0, ) sealed interface PlayerEvent { - data class ShowError(val error: Exception) : PlayerEvent + data class ShowError(val error: CtErrorType) : PlayerEvent } @HiltViewModel class PlayerViewModel @Inject constructor( - + private val playlistRepository: PlaylistRepository, ) : ViewModel(), PlayerEventListener { private val _uiState = MutableStateFlow(PlayerState()) @@ -34,6 +43,23 @@ class PlayerViewModel @Inject constructor( private val _events = MutableSharedFlow() val events: SharedFlow = _events.asSharedFlow() + private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> + val errorType = if (throwable is CtException) throwable.ctError else CtErrorType.UN_KNOWN + viewModelScope.launch { _events.emit(PlayerEvent.ShowError(errorType)) } + } + + private val viewModelScopeWithExceptionHandler = viewModelScope + exceptionHandler + + init { + getRecentPlaylist() + } + + private fun getRecentPlaylist() { + playlistRepository.getRecentPlaylist().onEach { recentPlaylist -> + _uiState.update { it.copy(playlist = recentPlaylist) } + }.launchIn(viewModelScopeWithExceptionHandler) + } + private fun sendEvent(event: PlayerEvent) { viewModelScope.launch { _events.emit(event) From b1edae80bdc6339c1e6c294f4324da96b59c5e1d Mon Sep 17 00:00:00 2001 From: youlalala Date: Thu, 30 Nov 2023 22:34:07 +0900 Subject: [PATCH 004/205] =?UTF-8?q?feat=20:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EC=9E=AC=EC=83=9D=20=EB=AA=A9=EB=A1=9D=EC=9D=B4=20=EB=B9=84?= =?UTF-8?q?=EC=96=B4=EC=9E=88=EC=9C=BC=EB=A9=B4=20bottom=20player=20?= =?UTF-8?q?=EC=88=A8=EA=B9=80=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle.kts | 1 + .../src/main/java/com/ohdodok/catchytape/MainActivity.kt | 8 -------- android/app/src/main/res/layout/activity_main.xml | 8 ++++++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index dc7608e..29bbb8e 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -67,6 +67,7 @@ dependencies { implementation(project(":feature:playlist")) implementation(project(":feature:mypage")) implementation(project(":core:data")) + implementation(project(":core:domain")) implementation(libs.core.ktx) implementation(libs.appcompat) diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index e324875..6464eb3 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -39,7 +39,6 @@ class MainActivity : AppCompatActivity() { private lateinit var connectivityManager: ConnectivityManager private val playViewModel: PlayerViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) @@ -93,7 +92,6 @@ class MainActivity : AppCompatActivity() { else -> { showBottomNav() - showPlayerController() } } } @@ -117,11 +115,6 @@ class MainActivity : AppCompatActivity() { binding.pcvController.visibility = View.GONE } - private fun showPlayerController() { - binding.pcvController.visibility = View.VISIBLE - } - - private fun setupPlayer() { player.addListener(PlayerListener(playViewModel)) player.prepare() @@ -142,7 +135,6 @@ class MainActivity : AppCompatActivity() { } } - private fun setupPlayButton() { binding.pcvController.setOnPlayButtonClick { if (playViewModel.uiState.value.isPlaying) player.pause() diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml index 7d4c4e6..0439fe4 100644 --- a/android/app/src/main/res/layout/activity_main.xml +++ b/android/app/src/main/res/layout/activity_main.xml @@ -5,6 +5,10 @@ + + @@ -31,17 +35,17 @@ android:id="@+id/pcv_controller" android:layout_width="0dp" android:layout_height="65dp" + android:visibility="@{viewModel.uiState.playlist.empty ? view.GONE : view.VISIBLE}" app:artist="@string/artist" app:duration="@{viewModel.uiState.duration}" - app:playing="@{viewModel.uiState.isPlaying}" app:layout_constraintBottom_toTopOf="@id/bottom_nav" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" + app:playing="@{viewModel.uiState.isPlaying}" app:progress="@{viewModel.uiState.currentPositionSecond}" app:thumbnailUrl="https://picsum.photos/200" app:title="@string/title" /> - Date: Fri, 1 Dec 2023 00:30:36 +0900 Subject: [PATCH 005/205] =?UTF-8?q?feat=20:=20=ED=98=84=EC=9E=AC=20?= =?UTF-8?q?=EC=9E=AC=EC=83=9D=20=EB=AA=A9=EB=A1=9D=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20UseCase=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/model/CurrentPlaylist.kt | 12 +++++++++ .../usecase/player/CurrentPlayListUseCase.kt | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/model/CurrentPlaylist.kt create mode 100644 android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/model/CurrentPlaylist.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/model/CurrentPlaylist.kt new file mode 100644 index 0000000..2de32c5 --- /dev/null +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/model/CurrentPlaylist.kt @@ -0,0 +1,12 @@ +package com.ohdodok.catchytape.core.domain.model + +data class CurrentPlaylist( + val startMusic: Music, + val musics: List, +) { + init { + require(musics.contains(startMusic)) { + "재생할 노래가 재생할 노래 목록에 포함되어 있어야 합니다." + } + } +} \ No newline at end of file diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt new file mode 100644 index 0000000..c99973e --- /dev/null +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt @@ -0,0 +1,26 @@ +package com.ohdodok.catchytape.core.domain.usecase.player + +import com.ohdodok.catchytape.core.domain.model.CurrentPlaylist +import com.ohdodok.catchytape.core.domain.model.Music +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch +import javax.inject.Inject + +class CurrentPlaylistUseCase @Inject constructor() { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) + val currentPlaylist = Channel() + + fun playMusics(startMusic: Music, musics: List) { + val newPlaylist = CurrentPlaylist( + startMusic = startMusic, + musics = musics, + ) + + scope.launch { + currentPlaylist.send(newPlaylist) + } + } +} \ No newline at end of file From 2e02a036b6e1a4e629c0b547ecdc85bd3c3ce823 Mon Sep 17 00:00:00 2001 From: algosketch Date: Fri, 1 Dec 2023 00:41:01 +0900 Subject: [PATCH 006/205] =?UTF-8?q?feat=20:=20MusicAdpater=EC=99=80=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=EB=84=88=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/core/ui/MusicAdapter.kt | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt index eb62c24..dea8cae 100644 --- a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt +++ b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/MusicAdapter.kt @@ -6,19 +6,20 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.ohdodok.catchytape.core.domain.model.Music +import com.ohdodok.catchytape.core.ui.MusicAdapter.Listener import com.ohdodok.catchytape.core.ui.databinding.ItemMusicHorizontalBinding import com.ohdodok.catchytape.core.ui.databinding.ItemMusicVerticalBinding class MusicAdapter( private val musicItemOrientation: Orientation, - private val listener: Listener = Listener { }, // todo : 클릭 이벤트 구현이 완료되면 디폴트 값을 지워주세요. + private val listener: Listener = Listener { }, // todo : 클릭 이벤트 구현이 완료되면 디폴트 값을 지워주세요. ) : ListAdapter(MusicDiffUtil) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (musicItemOrientation) { - Orientation.HORIZONTAL -> HorizontalViewHolder.from(parent) - Orientation.VERTICAL -> VerticalViewHolder.from(parent) + Orientation.HORIZONTAL -> HorizontalViewHolder.from(parent, listener) + Orientation.VERTICAL -> VerticalViewHolder.from(parent, listener) } } @@ -30,25 +31,33 @@ class MusicAdapter( } - class HorizontalViewHolder private constructor(private val binding: ItemMusicHorizontalBinding) : + class HorizontalViewHolder private constructor( + private val binding: ItemMusicHorizontalBinding, + private val listener: Listener, + ) : RecyclerView.ViewHolder(binding.root) { fun bind(item: Music) { binding.music = item + binding.listener = listener } companion object { - fun from(parent: ViewGroup) = HorizontalViewHolder( + fun from(parent: ViewGroup, listener: Listener) = HorizontalViewHolder( ItemMusicHorizontalBinding.inflate( LayoutInflater.from(parent.context), parent, false - ) + ), + listener ) } } - class VerticalViewHolder private constructor(private val binding: ItemMusicVerticalBinding) : + class VerticalViewHolder private constructor( + private val binding: ItemMusicVerticalBinding, + private val listener: Listener, + ) : RecyclerView.ViewHolder(binding.root) { fun bind(item: Music) { @@ -56,12 +65,13 @@ class MusicAdapter( } companion object { - fun from(parent: ViewGroup) = VerticalViewHolder( + fun from(parent: ViewGroup, listener: Listener) = VerticalViewHolder( ItemMusicVerticalBinding.inflate( LayoutInflater.from(parent.context), parent, false - ) + ), + listener ) } } From 75c4f39ead2861a767c92f88387723175ff5ad66 Mon Sep 17 00:00:00 2001 From: algosketch Date: Fri, 1 Dec 2023 00:41:46 +0900 Subject: [PATCH 007/205] =?UTF-8?q?feat=20:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=EB=90=9C=20=EB=85=B8=EB=9E=98=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=ED=94=8C?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=20=ED=99=94=EB=A9=B4=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/feature/home/HomeFragment.kt | 29 ++++++++++++++----- .../catchytape/feature/home/HomeViewModel.kt | 15 ++++++++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt b/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt index de61724..42fe9a5 100644 --- a/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt +++ b/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.View import androidx.core.net.toUri 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 @@ -22,7 +23,10 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { super.onViewCreated(view, savedInstanceState) binding.viewModel = viewModel - binding.rvRecentlyAddedSong.adapter = MusicAdapter(musicItemOrientation = Orientation.HORIZONTAL) + binding.rvRecentlyAddedSong.adapter = MusicAdapter( + musicItemOrientation = Orientation.HORIZONTAL, + listener = viewModel, + ) observeEvents() viewModel.fetchUploadedMusics() setupButtons() @@ -35,6 +39,10 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { is HomeEvent.ShowMessage -> { showMessage(event.error.toMessageId()) } + + is HomeEvent.NavigateToPlayerScreen -> { + findNavController().navigateToPlayerScreen() + } } } } @@ -42,17 +50,22 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { private fun setupButtons() { binding.ibUpload.setOnClickListener { - val request = NavDeepLinkRequest.Builder - .fromUri("android-app://com.ohdodok.catchytape/upload_fragment".toUri()) - .build() + val request = + NavDeepLinkRequest.Builder.fromUri("android-app://com.ohdodok.catchytape/upload_fragment".toUri()) + .build() findNavController().navigate(request) } binding.ivRecentlyPlayedSong.setOnClickListener { - val request = NavDeepLinkRequest.Builder - .fromUri("android-app://com.ohdodok.catchytape/player_fragment".toUri()) - .build() - findNavController().navigate(request) + findNavController().navigateToPlayerScreen() } } +} + +private fun NavController.navigateToPlayerScreen() { + val request = + NavDeepLinkRequest.Builder.fromUri("android-app://com.ohdodok.catchytape/player_fragment".toUri()) + .build() + + this.navigate(request) } \ No newline at end of file diff --git a/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeViewModel.kt b/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeViewModel.kt index 8442230..75b8d61 100644 --- a/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeViewModel.kt +++ b/android/feature/home/src/main/java/com/ohdodok/catchytape/feature/home/HomeViewModel.kt @@ -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 @@ -26,8 +28,9 @@ data class HomeUiState( @HiltViewModel class HomeViewModel @Inject constructor( - private val musicRepository: MusicRepository -) : ViewModel() { + private val musicRepository: MusicRepository, + private val currentPlaylistUseCase: CurrentPlaylistUseCase, +) : ViewModel(), MusicAdapter.Listener { private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> viewModelScope.launch { @@ -55,8 +58,16 @@ class HomeViewModel @Inject constructor( } }.launchIn(viewModelScopeWithExceptionHandler) } + + override fun onClick(music: Music) { + currentPlaylistUseCase.playMusics(music, uiState.value.recentlyUploadedMusics) + viewModelScope.launch { + _events.emit(HomeEvent.NavigateToPlayerScreen) + } + } } sealed interface HomeEvent { data class ShowMessage(val error: CtErrorType) : HomeEvent + data object NavigateToPlayerScreen : HomeEvent } \ No newline at end of file From 0421802052b7878c30c4c8a8c42907dce5d8090d Mon Sep 17 00:00:00 2001 From: algosketch Date: Fri, 1 Dec 2023 00:49:52 +0900 Subject: [PATCH 008/205] =?UTF-8?q?feat=20:=20CurrentPlaylistUseCase=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=20Channel=20=EC=BA=A1=EC=8A=90=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/usecase/player/CurrentPlayListUseCase.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt index c99973e..d0f5e11 100644 --- a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt @@ -6,12 +6,14 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.launch import javax.inject.Inject class CurrentPlaylistUseCase @Inject constructor() { private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) - val currentPlaylist = Channel() + private val _currentPlaylist = Channel() + val currentPlaylist: ReceiveChannel = _currentPlaylist fun playMusics(startMusic: Music, musics: List) { val newPlaylist = CurrentPlaylist( @@ -20,7 +22,7 @@ class CurrentPlaylistUseCase @Inject constructor() { ) scope.launch { - currentPlaylist.send(newPlaylist) + _currentPlaylist.send(newPlaylist) } } } \ No newline at end of file From df4d7b50a239874920345e59be771293781ab848 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Fri, 1 Dec 2023 14:26:48 +0900 Subject: [PATCH 009/205] =?UTF-8?q?refactor=20:=20playlist=5Fnavigation.xm?= =?UTF-8?q?l=20=EC=86=8D=EC=84=B1=20=EC=9D=B4=EB=A6=84=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/navigation/playlist_navigation.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/feature/playlist/src/main/res/navigation/playlist_navigation.xml b/android/feature/playlist/src/main/res/navigation/playlist_navigation.xml index 0b0f0f5..ab63bc2 100644 --- a/android/feature/playlist/src/main/res/navigation/playlist_navigation.xml +++ b/android/feature/playlist/src/main/res/navigation/playlist_navigation.xml @@ -3,12 +3,12 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/playlist_nav_graph" - app:startDestination="@id/playlist_fragment"> + app:startDestination="@id/playlists_fragment"> \ No newline at end of file From 945ce0139ec4a9a63a46482e3bfde7bcf3694f52 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Fri, 1 Dec 2023 14:28:03 +0900 Subject: [PATCH 010/205] =?UTF-8?q?refactor=20:=20PlayerControlView=20?= =?UTF-8?q?=EB=B6=88=20=ED=95=84=EC=9A=94=ED=95=9C=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=ED=95=A0=EB=8B=B9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ohdodok/catchytape/feature/player/PlayerControlView.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt index b3e846b..998f90e 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt @@ -52,9 +52,6 @@ class PlayerControlView(context: Context, attrs: AttributeSet) : ConstraintLayou thumbnailUrl = getString(R.styleable.PlayerBarView_thumbnailUrl) ?: "" title = getString(R.styleable.PlayerBarView_title) ?: "" artist = getString(R.styleable.PlayerBarView_artist) ?: "" - isPlaying = getBoolean(R.styleable.PlayerBarView_isPlaying, false) - progress = getInt(R.styleable.PlayerBarView_progress, 0) - duration = getInt(R.styleable.PlayerBarView_duration, 0) } finally { recycle() } From 73180f01a8232ab3dca07953ec32afd613e658fb Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Fri, 1 Dec 2023 17:35:20 +0900 Subject: [PATCH 011/205] =?UTF-8?q?fix=20:=20NewPlaylistDialog()=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=EA=B0=80=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20?= =?UTF-8?q?=EC=83=88=EB=A1=9C=20=EC=83=9D=EC=84=B1=EB=90=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EA=B2=8C=20=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt index 65c2c41..0a2508c 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt @@ -22,8 +22,9 @@ class PlaylistsFragment : BaseFragment(R.layout.fragme viewModel.fetchPlaylists() observeEvents() + val newPlaylistDialog = NewPlaylistDialog() binding.fabNewPlaylist.setOnClickListener { - NewPlaylistDialog().show(childFragmentManager, NewPlaylistDialog.TAG) + newPlaylistDialog.show(childFragmentManager, NewPlaylistDialog.TAG) } } From 6663a550e0258f0030c132deea930a01cc5f10dc Mon Sep 17 00:00:00 2001 From: Yura Park <62279741+youlalala@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:04:03 +0900 Subject: [PATCH 012/205] =?UTF-8?q?docs=20:=20server=20tech=20stack=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d7c3755..b460f76 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,14 @@ ### 📡 Server | Category | TechStack | | ------------- | ------------- | -| | | +| Framework, Language | NestJS, TypeScript | +| DB | MySQL | +| ORM | TypeORM | +| Test | Jest | +| API Docs | SwaggerHub | +| CI/CD | Github Actions | +| NCP | Server, Container Registry, VPC, Object Storage| +
그 외 기록 From e58f664a8c250a77a6d6ace453bbf3cae1f84f10 Mon Sep 17 00:00:00 2001 From: youlalala Date: Sun, 3 Dec 2023 00:32:02 +0900 Subject: [PATCH 013/205] =?UTF-8?q?refactor=20:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=ED=94=8C=EB=A0=88=EC=9D=B4=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=20=EC=98=A4=EB=8A=94=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ohdodok/catchytape/feature/player/PlayerViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt index 2aa8539..4a274ef 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt @@ -51,10 +51,10 @@ class PlayerViewModel @Inject constructor( private val viewModelScopeWithExceptionHandler = viewModelScope + exceptionHandler init { - getRecentPlaylist() + fetchRecentPlaylist() } - private fun getRecentPlaylist() { + private fun fetchRecentPlaylist() { playlistRepository.getRecentPlaylist().onEach { recentPlaylist -> _uiState.update { it.copy(playlist = recentPlaylist) } }.launchIn(viewModelScopeWithExceptionHandler) From 58ffad7f7ec0dc3cdc7d2cc5774901aff2f5d16f Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Mon, 4 Dec 2023 13:56:42 +0900 Subject: [PATCH 014/205] =?UTF-8?q?feat=20:=20media=EA=B0=80=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=90=A0=EC=8B=9C(=EC=9D=B4=EC=A0=84=20=EA=B3=A1,?= =?UTF-8?q?=20=EB=8B=A4=EC=9D=8C=20=EA=B3=A1)=20playing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/player/PlayerFragment.kt | 27 ++++++++++++++++++- .../feature/player/PlayerListener.kt | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt index b29608a..2959970 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt @@ -29,7 +29,9 @@ class PlayerFragment : BaseFragment(R.layout.fragment_pla setUpSeekBar() // todo : 실제 데이터로 변경 - setMedia("https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8") + //setMedia("https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8") + setMedias() + setupButtons() collectEvents() } @@ -57,6 +59,19 @@ class PlayerFragment : BaseFragment(R.layout.fragment_pla player.play() } + private fun setMedias() { + val dummys = listOf( + "https://catchy-tape-bucket2.kr.object.ncloudstorage.com/music/379c98d8-df30-4df1-90a8-e9d45d80789a/music.m3u8", + "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8", + "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8" + ) // TODO : dummys 삭제 필요 + + val mediaItems = dummys.map { MediaItem.fromUri(it) } + player.setMediaItems(mediaItems) + player.play() + } + + private fun setupButtons() { binding.btnPlay.setOnClickListener { if (viewModel.uiState.value.isPlaying) player.pause() @@ -66,6 +81,16 @@ class PlayerFragment : BaseFragment(R.layout.fragment_pla binding.ibDown.setOnClickListener { findNavController().popBackStack() } + + binding.btnNext.setOnClickListener { + player.seekToNextMediaItem() + player.play() + } + + binding.btnPrevious.setOnClickListener { + player.seekToPreviousMediaItem() + player.play() + } } private fun collectEvents() { diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerListener.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerListener.kt index e186770..a3eb33f 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerListener.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerListener.kt @@ -13,7 +13,7 @@ class PlayerListener( listener.onPlayingChanged(player.isPlaying) } - events.contains(Player.EVENT_TIMELINE_CHANGED) -> { + events.containsAny(Player.EVENT_TIMELINE_CHANGED, Player.EVENT_MEDIA_ITEM_TRANSITION) -> { val durationMs = player.duration.toInt() listener.onMediaItemChanged(durationMs / millisecondsPerSecond) } From 1e540d22eed8f4738f2e8a5b69a94f4353858b1d Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Mon, 4 Dec 2023 14:13:23 +0900 Subject: [PATCH 015/205] =?UTF-8?q?feat=20:=20Bottom=20Player=20=EC=9D=B4?= =?UTF-8?q?=EC=A0=84,=20=EB=8B=A4=EC=9D=8C=20=EA=B3=A1=20UI=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/res/layout/view_player_control.xml | 26 ++++++++++++++++--- .../player/src/main/res/values/strings.xml | 2 ++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/android/feature/player/src/main/res/layout/view_player_control.xml b/android/feature/player/src/main/res/layout/view_player_control.xml index 64b5bb3..83e65ea 100644 --- a/android/feature/player/src/main/res/layout/view_player_control.xml +++ b/android/feature/player/src/main/res/layout/view_player_control.xml @@ -28,7 +28,7 @@ android:ellipsize="end" android:maxLines="1" app:layout_constraintBottom_toTopOf="@id/tv_artist" - app:layout_constraintEnd_toStartOf="@id/ib_play" + app:layout_constraintEnd_toStartOf="@id/ib_previous" app:layout_constraintStart_toEndOf="@id/iv_thumbnail" app:layout_constraintTop_toTopOf="@id/iv_thumbnail" app:layout_constraintVertical_chainStyle="packed" @@ -47,15 +47,35 @@ app:layout_constraintTop_toBottomOf="@id/tv_title" tools:text="데이먼스 이어" /> + + + + diff --git a/android/feature/player/src/main/res/values/strings.xml b/android/feature/player/src/main/res/values/strings.xml index 02d0582..12a5bfe 100644 --- a/android/feature/player/src/main/res/values/strings.xml +++ b/android/feature/player/src/main/res/values/strings.xml @@ -2,4 +2,6 @@ %d:%02d 재생하기 + 이전 곡 + 다음 곡 \ No newline at end of file From 93ce65a5dc72c372a33f2af09a4753de6c8b7e08 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Mon, 4 Dec 2023 14:13:43 +0900 Subject: [PATCH 016/205] =?UTF-8?q?feat=20:=20Bottom=20Player=20=EC=9D=B4?= =?UTF-8?q?=EC=A0=84,=20=EB=8B=A4=EC=9D=8C=20=EA=B3=A1=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ohdodok/catchytape/MainActivity.kt | 32 ++++++++++++++++++- .../feature/player/PlayerControlView.kt | 7 ++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index e324875..7f9a283 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -11,6 +11,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.media3.common.MediaItem import androidx.media3.exoplayer.ExoPlayer import androidx.media3.session.MediaController import androidx.media3.session.SessionToken @@ -21,9 +22,9 @@ import androidx.navigation.ui.setupWithNavController import com.ohdodok.catchytape.databinding.ActivityMainBinding import com.ohdodok.catchytape.feature.player.PlayerListener import com.ohdodok.catchytape.feature.player.PlayerViewModel -import com.ohdodok.catchytape.mediacontrol.PlaybackService import com.ohdodok.catchytape.feature.player.millisecondsPerSecond import com.ohdodok.catchytape.feature.player.navigateToPlayer +import com.ohdodok.catchytape.mediacontrol.PlaybackService import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -55,8 +56,11 @@ class MainActivity : AppCompatActivity() { val networkStateObserver = NetworkStateObserver(connectivityManager, ::checkNetworkState) lifecycle.addObserver(networkStateObserver) + setMedias() setupPlayer() setupPlayButton() + setupBeforeButton() + setupNextButton() } override fun onStart() { @@ -149,4 +153,30 @@ class MainActivity : AppCompatActivity() { else player.play() } } + + private fun setupBeforeButton() { + binding.pcvController.setOnPreviousButtonClick { + player.seekToPreviousMediaItem() + player.play() + } + } + + private fun setupNextButton() { + binding.pcvController.setOnNextButtonClick { + player.seekToNextMediaItem() + player.play() + } + } + + private fun setMedias() { + val dummys = listOf( + "https://catchy-tape-bucket2.kr.object.ncloudstorage.com/music/379c98d8-df30-4df1-90a8-e9d45d80789a/music.m3u8", + "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8", + "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8" + ) // TODO : dummys 삭제 필요 + + val mediaItems = dummys.map { MediaItem.fromUri(it) } + player.setMediaItems(mediaItems) + player.play() + } } \ No newline at end of file diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt index 998f90e..30e505a 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerControlView.kt @@ -74,4 +74,11 @@ class PlayerControlView(context: Context, attrs: AttributeSet) : ConstraintLayou else AppCompatResources.getDrawable(context, drawable.ic_play) } + fun setOnPreviousButtonClick(onPreviousButtonClick: () -> Unit) { + binding.ibPrevious.setOnClickListener { onPreviousButtonClick() } + } + + fun setOnNextButtonClick(onNextButtonClick: () -> Unit) { + binding.ibNext.setOnClickListener { onNextButtonClick() } + } } \ No newline at end of file From 7262f0c21a679415dc33d355825bacc1cff1bd13 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Mon, 4 Dec 2023 16:19:34 +0900 Subject: [PATCH 017/205] =?UTF-8?q?feat=20:=20dummyUrls=20viewmodel=20?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/ohdodok/catchytape/MainActivity.kt | 8 +------- .../ohdodok/catchytape/feature/player/PlayerFragment.kt | 8 +------- .../ohdodok/catchytape/feature/player/PlayerViewModel.kt | 6 ++++++ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index 7f9a283..22cbfb8 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -169,13 +169,7 @@ class MainActivity : AppCompatActivity() { } private fun setMedias() { - val dummys = listOf( - "https://catchy-tape-bucket2.kr.object.ncloudstorage.com/music/379c98d8-df30-4df1-90a8-e9d45d80789a/music.m3u8", - "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8", - "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8" - ) // TODO : dummys 삭제 필요 - - val mediaItems = dummys.map { MediaItem.fromUri(it) } + val mediaItems = playViewModel.dummyUris.map { MediaItem.fromUri(it) } player.setMediaItems(mediaItems) player.play() } diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt index 2959970..49cb752 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt @@ -60,13 +60,7 @@ class PlayerFragment : BaseFragment(R.layout.fragment_pla } private fun setMedias() { - val dummys = listOf( - "https://catchy-tape-bucket2.kr.object.ncloudstorage.com/music/379c98d8-df30-4df1-90a8-e9d45d80789a/music.m3u8", - "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8", - "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8" - ) // TODO : dummys 삭제 필요 - - val mediaItems = dummys.map { MediaItem.fromUri(it) } + val mediaItems = viewModel.dummyUris.map { MediaItem.fromUri(it) } player.setMediaItems(mediaItems) player.play() } diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt index 9a336e1..3575040 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt @@ -28,6 +28,12 @@ class PlayerViewModel @Inject constructor( ) : ViewModel(), PlayerEventListener { + val dummyUris = listOf( + "https://catchy-tape-bucket2.kr.object.ncloudstorage.com/music/379c98d8-df30-4df1-90a8-e9d45d80789a/music.m3u8", + "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8", + "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8" + ) // TODO : dummys 삭제 필요 + private val _uiState = MutableStateFlow(PlayerState()) val uiState: StateFlow = _uiState.asStateFlow() From ec603daaae6cf571f74809813a47d70b9b0a71a7 Mon Sep 17 00:00:00 2001 From: hyungun Date: Mon, 4 Dec 2023 17:32:00 +0900 Subject: [PATCH 018/205] =?UTF-8?q?chore=20:=20winston=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * winston, winston daily, nest-winston 패키지 설치 Co-authored-by: Cutiepazzipozzi --- server/package-lock.json | 276 ++++++++++++++++++++++++++++++++++++++- server/package.json | 5 +- 2 files changed, 278 insertions(+), 3 deletions(-) diff --git a/server/package-lock.json b/server/package-lock.json index 3bd2b28..5371e29 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -26,13 +26,16 @@ "cross-env": "^7.0.3", "fluent-ffmpeg": "^2.1.2", "mysql2": "^3.6.3", + "nest-winston": "^1.9.4", "passport": "^0.6.0", "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "typeorm": "^0.3.17", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^4.7.1" }, "devDependencies": { "@nestjs/cli": "^10.0.0", @@ -885,6 +888,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2366,6 +2379,11 @@ "@types/superagent": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "9.0.7", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", @@ -3746,6 +3764,15 @@ "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3762,6 +3789,37 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4375,6 +4433,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -4919,6 +4982,11 @@ "bser": "2.1.1" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -4955,6 +5023,14 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-stream-rotator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz", + "integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==", + "dependencies": { + "moment": "^2.29.1" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5091,6 +5167,11 @@ "which": "bin/which" } }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/follow-redirects": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", @@ -5874,7 +5955,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -6810,6 +6890,11 @@ "node": ">=6" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -6935,6 +7020,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/logform": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", @@ -7143,6 +7252,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7257,6 +7374,18 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/nest-winston": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/nest-winston/-/nest-winston-1.9.4.tgz", + "integrity": "sha512-ilEmHuuYSAI6aMNR120fLBl42EdY13QI9WRggHdEizt9M7qZlmXJwpbemVWKW/tqRmULjSx/otKNQ3GMQbfoUQ==", + "dependencies": { + "fast-safe-stringify": "^2.1.1" + }, + "peerDependencies": { + "@nestjs/common": "^5.0.0 || ^6.6.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", + "winston": "^3.0.0" + } + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -7337,6 +7466,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -7364,6 +7501,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -8316,6 +8461,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -8586,6 +8739,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8643,6 +8809,14 @@ "node": ">= 0.6" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -9012,6 +9186,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -9116,6 +9295,14 @@ "tree-kill": "cli.js" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -9923,6 +10110,91 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/winston": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-daily-rotate-file": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.7.1.tgz", + "integrity": "sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==", + "dependencies": { + "file-stream-rotator": "^0.6.1", + "object-hash": "^2.0.1", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "winston": "^3" + } + }, + "node_modules/winston-transport": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", diff --git a/server/package.json b/server/package.json index 0970803..2fbc0cf 100644 --- a/server/package.json +++ b/server/package.json @@ -37,13 +37,16 @@ "cross-env": "^7.0.3", "fluent-ffmpeg": "^2.1.2", "mysql2": "^3.6.3", + "nest-winston": "^1.9.4", "passport": "^0.6.0", "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "typeorm": "^0.3.17", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^4.7.1" }, "devDependencies": { "@nestjs/cli": "^10.0.0", From 0cb028aafca7f285e9f4843a36a8680dcaf254c7 Mon Sep 17 00:00:00 2001 From: hyungun Date: Mon, 4 Dec 2023 17:33:12 +0900 Subject: [PATCH 019/205] =?UTF-8?q?feat=20:=20winston=20=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20logger=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 전역 logger를 winston 으로 교체 --- server/src/app.module.ts | 14 +++++++++++++- server/src/auth/auth.controller.ts | 11 +++++++++-- server/src/auth/auth.module.ts | 4 ++-- server/src/main.ts | 2 ++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/server/src/app.module.ts b/server/src/app.module.ts index d6b78c8..f39a53d 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -7,11 +7,23 @@ import { TypeOrmConfigService } from 'src/config/typeorm.config'; import { ConfigModule } from '@nestjs/config'; import { UploadModule } from './upload/upload.module'; import { MusicModule } from './music/music.module'; -import { PlaylistController } from './playlist/playlist.controller'; import { PlaylistModule } from './playlist/playlist.module'; +import { utilities, WinstonModule } from 'nest-winston'; +import * as winston from 'winston'; @Module({ imports: [ + WinstonModule.forRoot({ + transports: [ + new winston.transports.Console({ + level: process.env.NODE_ENV === 'prod' ? 'info' : 'silly', + format: winston.format.combine( + winston.format.timestamp(), + utilities.format.nestLike('CatchyTape', { prettyPrint: true }), + ), + }), + ], + }), ConfigModule.forRoot({ isGlobal: true, envFilePath: __dirname + `/../${process.env.NODE_ENV}.env`, diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts index a8a3519..5a2a6e1 100644 --- a/server/src/auth/auth.controller.ts +++ b/server/src/auth/auth.controller.ts @@ -4,6 +4,9 @@ import { Delete, Get, HttpCode, + Inject, + Logger, + LoggerService, Post, Req, UseGuards, @@ -18,7 +21,10 @@ import { User } from 'src/entity/user.entity'; @Controller('users') export class AuthController { - constructor(private authService: AuthService) {} + constructor( + private authService: AuthService, + @Inject(Logger) private readonly logger: LoggerService, + ) {} @Post('login') @HttpCode(HTTP_STATUS_CODE.SUCCESS) @@ -42,6 +48,7 @@ export class AuthController { @UseGuards(AuthGuard()) @HttpCode(HTTP_STATUS_CODE.SUCCESS) verifyToken(@Req() req): { userId: string } { + this.logger.log('log: 테스트 로그'); const user: User = req.user; return { userId: user.user_id }; } @@ -49,7 +56,7 @@ export class AuthController { @Delete() @UseGuards(AuthGuard()) @HttpCode(HTTP_STATUS_CODE.SUCCESS) - async deleteUser(@Req() req): Promise<{userId: string}> { + async deleteUser(@Req() req): Promise<{ userId: string }> { const user: User = req.user; return await this.authService.deleteUser(user); } diff --git a/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts index 4095a88..73dbe8c 100644 --- a/server/src/auth/auth.module.ts +++ b/server/src/auth/auth.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common'; +import { Logger, Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; import { ConfigModule, ConfigService } from '@nestjs/config'; @@ -25,7 +25,7 @@ import { Music_Playlist } from 'src/entity/music_playlist.entity'; }), TypeOrmModule.forFeature([User, Playlist, Music, Music_Playlist]), ], - providers: [JwtStrategy, AuthService, PlaylistService], + providers: [JwtStrategy, AuthService, PlaylistService, Logger], exports: [JwtStrategy, PassportModule], controllers: [AuthController], }) diff --git a/server/src/main.ts b/server/src/main.ts index 13cad38..40a4af3 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -1,8 +1,10 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; +import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; async function bootstrap() { const app = await NestFactory.create(AppModule); + app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER)); await app.listen(3000); } bootstrap(); From 0cdb3f24b7a20a12f94edb5fa9a5eaab8aa6e13a Mon Sep 17 00:00:00 2001 From: hyungun Date: Mon, 4 Dec 2023 17:40:19 +0900 Subject: [PATCH 020/205] =?UTF-8?q?chore=20:=20test=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EC=97=90=EC=84=9C=20logger=20=EB=AA=A8=EB=93=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * auth controller.test 에서 설정 Co-authored-by: Cutiepazzipozzi --- server/src/auth/auth.controller.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/auth/auth.controller.spec.ts b/server/src/auth/auth.controller.spec.ts index 0c0504e..5c3541d 100644 --- a/server/src/auth/auth.controller.spec.ts +++ b/server/src/auth/auth.controller.spec.ts @@ -9,6 +9,7 @@ import { PlaylistService } from 'src/playlist/playlist.service'; import { Playlist } from 'src/entity/playlist.entity'; import { Music } from 'src/entity/music.entity'; import { Music_Playlist } from 'src/entity/music_playlist.entity'; +import { Logger, LoggerService } from '@nestjs/common'; describe('AuthController', () => { let controller: AuthController; @@ -21,6 +22,7 @@ describe('AuthController', () => { imports: [JwtModule], controllers: [AuthController], providers: [ + Logger, AuthService, { provide: getRepositoryToken(User), From 9951c3d385b9148491868b1d3ba7227a5b9c6ac8 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Mon, 4 Dec 2023 17:48:33 +0900 Subject: [PATCH 021/205] =?UTF-8?q?refactor=20:=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/java/com/ohdodok/catchytape/MainActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index 22cbfb8..34fd76c 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -59,7 +59,7 @@ class MainActivity : AppCompatActivity() { setMedias() setupPlayer() setupPlayButton() - setupBeforeButton() + setupPreviousButton() setupNextButton() } @@ -154,7 +154,7 @@ class MainActivity : AppCompatActivity() { } } - private fun setupBeforeButton() { + private fun setupPreviousButton() { binding.pcvController.setOnPreviousButtonClick { player.seekToPreviousMediaItem() player.play() From 39f2585e73ab6bd27768b7147d6ab83e68149c6b Mon Sep 17 00:00:00 2001 From: youlalala Date: Mon, 4 Dec 2023 17:57:32 +0900 Subject: [PATCH 022/205] =?UTF-8?q?feat=20:=20PlaylistDetailFragment=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/playlist/PlaylistDetailFragment.kt | 9 +++++++++ .../main/res/layout/fragment_playlist_detail.xml | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt create mode 100644 android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt new file mode 100644 index 0000000..ce8d93a --- /dev/null +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt @@ -0,0 +1,9 @@ +package com.ohdodok.catchytape.feature.playlist + +import com.ohdodok.catchytape.core.ui.BaseFragment +import com.ohdodok.catchytape.feature.playlist.databinding.FragmentPlaylistDetailBinding + +class PlaylistDetailFragment : BaseFragment(R.layout.fragment_playlist_detail) { + + +} \ No newline at end of file diff --git a/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml b/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml new file mode 100644 index 0000000..67ed5d4 --- /dev/null +++ b/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file From 52f8e0cf458044a268aff79b828119cd8ccbfbcb Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Mon, 4 Dec 2023 18:12:14 +0900 Subject: [PATCH 023/205] =?UTF-8?q?refactor=20:=20package=20=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20mediacontrol=20->=20mediasession?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 2 +- .../app/src/main/java/com/ohdodok/catchytape/MainActivity.kt | 2 +- .../{mediacontrol => mediasession}/PlaybackService.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename android/app/src/main/java/com/ohdodok/catchytape/{mediacontrol => mediasession}/PlaybackService.kt (94%) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5ac85f4..c26ecfc 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -28,7 +28,7 @@ android:exported="true" /> diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index cafc33a..5f54916 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -24,7 +24,7 @@ import com.ohdodok.catchytape.feature.player.PlayerListener import com.ohdodok.catchytape.feature.player.PlayerViewModel import com.ohdodok.catchytape.feature.player.millisecondsPerSecond import com.ohdodok.catchytape.feature.player.navigateToPlayer -import com.ohdodok.catchytape.mediacontrol.PlaybackService +import com.ohdodok.catchytape.mediasession.PlaybackService import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/android/app/src/main/java/com/ohdodok/catchytape/mediacontrol/PlaybackService.kt b/android/app/src/main/java/com/ohdodok/catchytape/mediasession/PlaybackService.kt similarity index 94% rename from android/app/src/main/java/com/ohdodok/catchytape/mediacontrol/PlaybackService.kt rename to android/app/src/main/java/com/ohdodok/catchytape/mediasession/PlaybackService.kt index d84e832..4e9a851 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/mediacontrol/PlaybackService.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/mediasession/PlaybackService.kt @@ -1,4 +1,4 @@ -package com.ohdodok.catchytape.mediacontrol +package com.ohdodok.catchytape.mediasession import androidx.media3.exoplayer.ExoPlayer import androidx.media3.session.MediaSession From ba665131d1444cec935b47779e4da550da663b3f Mon Sep 17 00:00:00 2001 From: hyungun Date: Mon, 4 Dec 2023 18:15:54 +0900 Subject: [PATCH 024/205] =?UTF-8?q?chore=20:=20logger=20config=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * logger 설정을 위한 config 파일 추가 Co-authored-by: Cutiepazzipozzi --- server/src/config/logger.config.ts | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 server/src/config/logger.config.ts diff --git a/server/src/config/logger.config.ts b/server/src/config/logger.config.ts new file mode 100644 index 0000000..7a0df9b --- /dev/null +++ b/server/src/config/logger.config.ts @@ -0,0 +1,43 @@ +import { WinstonModule, utilities } from 'nest-winston'; +import * as winston from 'winston'; +import * as winstonDaily from 'winston-daily-rotate-file'; + +const colors = { + error: 'red', + warn: 'yellow', + info: 'green', + http: 'magenta', + silly: 'blue', +}; +winston.addColors(colors); + +const dailyOption = () => { + return { + datePattern: 'YYYY-MM-DD', + dirname: `logs/`, + filename: `%DATE%.log`, + maxFiles: 7, + zippedArchive: true, + format: winston.format.combine( + winston.format.timestamp(), + utilities.format.nestLike(process.env.NODE_ENV, { + colors: false, + prettyPrint: true, + }), + ), + }; +}; + +export const winstonLogger = WinstonModule.createLogger({ + transports: [ + new winston.transports.Console({ + level: process.env.NODE_ENV === 'prod' ? 'info' : 'silly', + format: winston.format.combine( + winston.format.colorize({ all: true }), + winston.format.timestamp(), + utilities.format.nestLike('CatchyTape', { prettyPrint: true }), + ), + }), + new winstonDaily(dailyOption()), + ], +}); From b48f688ab20da1c044c4c486c171bfb1fde97642 Mon Sep 17 00:00:00 2001 From: hyungun Date: Mon, 4 Dec 2023 18:17:00 +0900 Subject: [PATCH 025/205] =?UTF-8?q?feat=20:=20winston=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * winston daily 를 이용해서 log 파일 저장 설정 Co-authored-by: Cutiepazzipozzi --- server/src/app.module.ts | 13 ------------- server/src/auth/auth.controller.ts | 2 +- server/src/main.ts | 5 ++--- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/server/src/app.module.ts b/server/src/app.module.ts index f39a53d..737d876 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -8,22 +8,9 @@ import { ConfigModule } from '@nestjs/config'; import { UploadModule } from './upload/upload.module'; import { MusicModule } from './music/music.module'; import { PlaylistModule } from './playlist/playlist.module'; -import { utilities, WinstonModule } from 'nest-winston'; -import * as winston from 'winston'; @Module({ imports: [ - WinstonModule.forRoot({ - transports: [ - new winston.transports.Console({ - level: process.env.NODE_ENV === 'prod' ? 'info' : 'silly', - format: winston.format.combine( - winston.format.timestamp(), - utilities.format.nestLike('CatchyTape', { prettyPrint: true }), - ), - }), - ], - }), ConfigModule.forRoot({ isGlobal: true, envFilePath: __dirname + `/../${process.env.NODE_ENV}.env`, diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts index 5a2a6e1..89731bc 100644 --- a/server/src/auth/auth.controller.ts +++ b/server/src/auth/auth.controller.ts @@ -48,8 +48,8 @@ export class AuthController { @UseGuards(AuthGuard()) @HttpCode(HTTP_STATUS_CODE.SUCCESS) verifyToken(@Req() req): { userId: string } { - this.logger.log('log: 테스트 로그'); const user: User = req.user; + this.logger.log(`GET /users/verify - ${user.nickname}: verified`); return { userId: user.user_id }; } diff --git a/server/src/main.ts b/server/src/main.ts index 40a4af3..c52769d 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -1,10 +1,9 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; -import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; +import { winstonLogger } from './config/logger.config'; async function bootstrap() { - const app = await NestFactory.create(AppModule); - app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER)); + const app = await NestFactory.create(AppModule, { logger: winstonLogger }); await app.listen(3000); } bootstrap(); From f300ef6f74a9c50ab78062bda017b046e6f499d2 Mon Sep 17 00:00:00 2001 From: HamBP Date: Mon, 4 Dec 2023 18:25:38 +0900 Subject: [PATCH 026/205] =?UTF-8?q?chore=20:=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle.kts | 1 + android/feature/search/.gitignore | 1 + android/feature/search/build.gradle.kts | 30 +++++++++++++++++++ android/feature/search/consumer-rules.pro | 0 android/feature/search/proguard-rules.pro | 21 +++++++++++++ .../search/src/main/AndroidManifest.xml | 4 +++ android/settings.gradle.kts | 1 + 7 files changed, 58 insertions(+) create mode 100644 android/feature/search/.gitignore create mode 100644 android/feature/search/build.gradle.kts create mode 100644 android/feature/search/consumer-rules.pro create mode 100644 android/feature/search/proguard-rules.pro create mode 100644 android/feature/search/src/main/AndroidManifest.xml diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 30ba985..c3136de 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -66,6 +66,7 @@ dependencies { implementation(project(":feature:player")) implementation(project(":feature:playlist")) implementation(project(":feature:mypage")) + implementation(project(":feature:search")) implementation(project(":core:data")) implementation(project(":core:domain")) diff --git a/android/feature/search/.gitignore b/android/feature/search/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/android/feature/search/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/android/feature/search/build.gradle.kts b/android/feature/search/build.gradle.kts new file mode 100644 index 0000000..a93fd1e --- /dev/null +++ b/android/feature/search/build.gradle.kts @@ -0,0 +1,30 @@ +@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed +plugins { + id("catchytape.android.feature") +} + +android { + namespace = "com.ohdodok.catchytape.feature.search" + + defaultConfig { + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + +} \ No newline at end of file diff --git a/android/feature/search/consumer-rules.pro b/android/feature/search/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/android/feature/search/proguard-rules.pro b/android/feature/search/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/android/feature/search/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/android/feature/search/src/main/AndroidManifest.xml b/android/feature/search/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/android/feature/search/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 7c22b98..b1b8a38 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -25,3 +25,4 @@ include(":feature:upload") include(":feature:player") include(":feature:playlist") include(":feature:mypage") +include(":feature:search") From d2eb3ddf6193e658c6b9fa383292e12a4640fe7e Mon Sep 17 00:00:00 2001 From: youlalala Date: Mon, 4 Dec 2023 18:56:51 +0900 Subject: [PATCH 027/205] =?UTF-8?q?feat=20:=20PlaylistsFragment=20->=20Pla?= =?UTF-8?q?ylistDetailFragment=20=ED=99=94=EB=A9=B4=20=EC=A0=84=ED=99=98?= =?UTF-8?q?=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/playlist/PlaylistAdapter.kt | 12 ++++----- .../playlist/PlaylistDetailFragment.kt | 6 +++-- .../feature/playlist/PlaylistsFragment.kt | 16 +++++++++++- .../feature/playlist/PlaylistsViewModel.kt | 26 ++++++++++++++++--- .../feature/playlist/model/PlaylistUiModel.kt | 9 +++++++ .../src/main/res/layout/item_playlist.xml | 3 ++- .../res/navigation/playlist_navigation.xml | 20 +++++++++++++- 7 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/model/PlaylistUiModel.kt diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistAdapter.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistAdapter.kt index 4f6fc19..3b1fbef 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistAdapter.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistAdapter.kt @@ -5,11 +5,11 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.ohdodok.catchytape.core.domain.model.Playlist import com.ohdodok.catchytape.feature.playlist.databinding.ItemPlaylistBinding +import com.ohdodok.catchytape.feature.playlist.model.PlaylistUiModel class PlaylistAdapter : - ListAdapter(PlaylistItemDiffUtil) { + ListAdapter(PlaylistItemDiffUtil) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlaylistViewHolder { return PlaylistViewHolder.from(parent) @@ -22,7 +22,7 @@ class PlaylistAdapter : class PlaylistViewHolder private constructor(private val binding: ItemPlaylistBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(item: Playlist) { + fun bind(item: PlaylistUiModel) { binding.playlist = item } @@ -37,12 +37,12 @@ class PlaylistAdapter : } } - object PlaylistItemDiffUtil : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Playlist, newItem: Playlist): Boolean { + object PlaylistItemDiffUtil : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: PlaylistUiModel, newItem: PlaylistUiModel): Boolean { return oldItem.id == newItem.id } - override fun areContentsTheSame(oldItem: Playlist, newItem: Playlist): Boolean { + override fun areContentsTheSame(oldItem: PlaylistUiModel, newItem: PlaylistUiModel): Boolean { return oldItem == newItem } } diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt index ce8d93a..c1b5889 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt @@ -3,7 +3,9 @@ package com.ohdodok.catchytape.feature.playlist import com.ohdodok.catchytape.core.ui.BaseFragment import com.ohdodok.catchytape.feature.playlist.databinding.FragmentPlaylistDetailBinding -class PlaylistDetailFragment : BaseFragment(R.layout.fragment_playlist_detail) { +class PlaylistDetailFragment : + BaseFragment(R.layout.fragment_playlist_detail) { -} \ No newline at end of file +} + diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt index 65c2c41..1d36456 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsFragment.kt @@ -4,6 +4,8 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.DialogFragment import androidx.fragment.app.viewModels +import androidx.navigation.NavController +import androidx.navigation.fragment.findNavController import com.ohdodok.catchytape.core.ui.BaseFragment import com.ohdodok.catchytape.core.ui.toMessageId import com.ohdodok.catchytape.feature.playlist.databinding.FragmentPlaylistsBinding @@ -28,7 +30,6 @@ class PlaylistsFragment : BaseFragment(R.layout.fragme } - private fun observeEvents() { repeatOnStarted { viewModel.events.collect { event -> @@ -36,6 +37,10 @@ class PlaylistsFragment : BaseFragment(R.layout.fragme is PlaylistsEvent.ShowMessage -> { showMessage(event.error.toMessageId()) } + + is PlaylistsEvent.NavigateToPlaylistDetail -> { + findNavController().navigateToPlaylistDetail(event.playlistId) + } } } } @@ -44,4 +49,13 @@ class PlaylistsFragment : BaseFragment(R.layout.fragme override fun onPositiveButtonClicked(dialog: DialogFragment, title: String) { viewModel.createPlaylist(title) } + +} + +private fun NavController.navigateToPlaylistDetail(playlistId: Int) { + navigate( + PlaylistsFragmentDirections.actionPlaylistsFragmentToPlaylistDetailFragment( + playlistId = playlistId + ) + ) } \ No newline at end of file diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt index 99f3b75..c053a66 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt @@ -4,8 +4,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ohdodok.catchytape.core.domain.model.CtErrorType import com.ohdodok.catchytape.core.domain.model.CtException -import com.ohdodok.catchytape.core.domain.model.Playlist import com.ohdodok.catchytape.core.domain.repository.PlaylistRepository +import com.ohdodok.catchytape.feature.playlist.model.PlaylistUiModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.flow.MutableSharedFlow @@ -21,7 +21,7 @@ import kotlinx.coroutines.plus import javax.inject.Inject data class PlaylistsUiState( - val playlists: List = emptyList() + val playlists: List = emptyList() ) @HiltViewModel @@ -48,7 +48,19 @@ class PlaylistViewModel @Inject constructor( fun fetchPlaylists() { playlistRepository.getPlaylists().onEach { playlists -> - _uiState.update { it.copy(playlists = playlists) } + _uiState.update { + it.copy( + playlists = playlists.map { playlist -> + PlaylistUiModel( + id = playlist.id, + title = playlist.title, + thumbnailUrl = playlist.thumbnailUrl, + trackSize = playlist.trackSize, + onClick = { onPlaylistClick(playlist.id) }, + ) + } + ) + } }.launchIn(viewModelScopeWithExceptionHandler) } @@ -57,9 +69,17 @@ class PlaylistViewModel @Inject constructor( playlistRepository.postPlaylist(playlistTitle) } } + + private fun onPlaylistClick(playlistId: Int) { + viewModelScope.launch { + _events.emit(PlaylistsEvent.NavigateToPlaylistDetail(playlistId)) + } + } } sealed interface PlaylistsEvent { + + data class NavigateToPlaylistDetail(val playlistId: Int) : PlaylistsEvent data class ShowMessage(val error: CtErrorType) : PlaylistsEvent } diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/model/PlaylistUiModel.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/model/PlaylistUiModel.kt new file mode 100644 index 0000000..ce1c89f --- /dev/null +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/model/PlaylistUiModel.kt @@ -0,0 +1,9 @@ +package com.ohdodok.catchytape.feature.playlist.model + +data class PlaylistUiModel( + val id: Int, + val title: String, + val thumbnailUrl: String, + val trackSize: Int, + val onClick: () -> Unit, +) \ No newline at end of file diff --git a/android/feature/playlist/src/main/res/layout/item_playlist.xml b/android/feature/playlist/src/main/res/layout/item_playlist.xml index ac9fe96..3633a0d 100644 --- a/android/feature/playlist/src/main/res/layout/item_playlist.xml +++ b/android/feature/playlist/src/main/res/layout/item_playlist.xml @@ -7,12 +7,13 @@ + type="com.ohdodok.catchytape.feature.playlist.model.PlaylistUiModel" /> + tools:layout="@layout/fragment_playlists"> + + + + + + + + + + \ No newline at end of file From f2e91bbbd4017573bc9b49f72dfb22b1a44e05bc Mon Sep 17 00:00:00 2001 From: youlalala Date: Mon, 4 Dec 2023 22:19:53 +0900 Subject: [PATCH 028/205] =?UTF-8?q?feat=20:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=83=81=EC=84=B8=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/drawable/btn_circle_background.xml | 5 ++ .../core/ui/src/main/res/drawable/ic_play.xml | 6 +-- .../core/ui/src/main/res/values/dimens.xml | 2 - .../core/ui/src/main/res/values/strings.xml | 2 +- .../main/res/layout/fragment_my_musics.xml | 3 +- .../src/main/res/layout/fragment_my_page.xml | 3 +- .../player/src/main/res/values/strings.xml | 1 - .../playlist/PlaylistDetailFragment.kt | 6 +++ .../res/layout/fragment_playlist_detail.xml | 52 ++++++++++++++++++- 9 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 android/core/ui/src/main/res/drawable/btn_circle_background.xml diff --git a/android/core/ui/src/main/res/drawable/btn_circle_background.xml b/android/core/ui/src/main/res/drawable/btn_circle_background.xml new file mode 100644 index 0000000..3c03914 --- /dev/null +++ b/android/core/ui/src/main/res/drawable/btn_circle_background.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/android/core/ui/src/main/res/drawable/ic_play.xml b/android/core/ui/src/main/res/drawable/ic_play.xml index f711f9c..02fb731 100644 --- a/android/core/ui/src/main/res/drawable/ic_play.xml +++ b/android/core/ui/src/main/res/drawable/ic_play.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/android/core/ui/src/main/res/values/dimens.xml b/android/core/ui/src/main/res/values/dimens.xml index 6c531ba..65a0fd7 100644 --- a/android/core/ui/src/main/res/values/dimens.xml +++ b/android/core/ui/src/main/res/values/dimens.xml @@ -17,6 +17,4 @@ 4dp 50dp - - 48dp \ No newline at end of file diff --git a/android/core/ui/src/main/res/values/strings.xml b/android/core/ui/src/main/res/values/strings.xml index 588430c..08c39f6 100644 --- a/android/core/ui/src/main/res/values/strings.xml +++ b/android/core/ui/src/main/res/values/strings.xml @@ -14,7 +14,7 @@ 확인 완료 저장 - 썸네일 이미지 + 재생하기 최근 재생한 노래 최근 추가된 노래 diff --git a/android/feature/mypage/src/main/res/layout/fragment_my_musics.xml b/android/feature/mypage/src/main/res/layout/fragment_my_musics.xml index d041418..6a75642 100644 --- a/android/feature/mypage/src/main/res/layout/fragment_my_musics.xml +++ b/android/feature/mypage/src/main/res/layout/fragment_my_musics.xml @@ -16,8 +16,9 @@ %d:%02d - 재생하기 \ No newline at end of file diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt index c1b5889..a6859ab 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt @@ -1,11 +1,17 @@ package com.ohdodok.catchytape.feature.playlist +import android.os.Bundle +import android.view.View import com.ohdodok.catchytape.core.ui.BaseFragment import com.ohdodok.catchytape.feature.playlist.databinding.FragmentPlaylistDetailBinding class PlaylistDetailFragment : BaseFragment(R.layout.fragment_playlist_detail) { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupBackStack(binding.tbPlaylistDetail) + } } diff --git a/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml b/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml index 67ed5d4..a9857f8 100644 --- a/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml +++ b/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml @@ -1,13 +1,63 @@ - + + + + + + + + + + + + + \ No newline at end of file From fc77651e070cf895ba44cbe175bbb085107a5f83 Mon Sep 17 00:00:00 2001 From: hyungun Date: Mon, 4 Dec 2023 23:57:39 +0900 Subject: [PATCH 029/205] =?UTF-8?q?feat=20:=20music=5Fplaylist=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=EC=97=90=20updated=5Fat=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 날짜를 식별하기 위해 updated_at 컬럼 추가 --- server/src/entity/music_playlist.entity.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/entity/music_playlist.entity.ts b/server/src/entity/music_playlist.entity.ts index fd471ed..fe19290 100644 --- a/server/src/entity/music_playlist.entity.ts +++ b/server/src/entity/music_playlist.entity.ts @@ -1,5 +1,6 @@ import { BaseEntity, + Column, Entity, JoinColumn, ManyToOne, @@ -21,6 +22,9 @@ export class Music_Playlist extends BaseEntity { @JoinColumn({ name: 'playlist_id' }) playlist: Playlist; + @Column() + updated_at: Date; + static async getMusicListByPlaylistId(playlistId: number): Promise { return this.find({ relations: { From d8d953501fa9810575922f6bcc55a8c21f13cc7d Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 00:36:39 +0900 Subject: [PATCH 030/205] =?UTF-8?q?feat=20:=20addMusicToPlaylist=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 플레이리스트에 음악을 추가할 때 추가된 날짜 저장 --- server/src/playlist/playlist.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/playlist/playlist.service.ts b/server/src/playlist/playlist.service.ts index 2907606..f3f87ac 100644 --- a/server/src/playlist/playlist.service.ts +++ b/server/src/playlist/playlist.service.ts @@ -82,6 +82,7 @@ export class PlaylistService { this.music_playlistRepository.create({ music: { music_id: musicId }, playlist: { playlist_id: playlistId }, + updated_at: new Date(), }); const result: Music_Playlist = From 3f46b35cc8958ae37f770a4a114d3d645ae86751 Mon Sep 17 00:00:00 2001 From: HamBP Date: Tue, 5 Dec 2023 00:58:11 +0900 Subject: [PATCH 031/205] =?UTF-8?q?feat=20:=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/res/drawable/ic_search.xml | 13 ++++++++++ .../main/res/menu/bottom_navigation_items.xml | 6 ++++- .../res/navigation/catchytape_navigation.xml | 1 + .../feature/search/SearchFragment.kt | 24 +++++++++++++++++++ .../feature/search/SearchViewModel.kt | 12 ++++++++++ .../src/main/res/layout/fragment_search.xml | 15 ++++++++++++ .../main/res/navigation/search_navigation.xml | 14 +++++++++++ 7 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 android/app/src/main/res/drawable/ic_search.xml create mode 100644 android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt create mode 100644 android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt create mode 100644 android/feature/search/src/main/res/layout/fragment_search.xml create mode 100644 android/feature/search/src/main/res/navigation/search_navigation.xml diff --git a/android/app/src/main/res/drawable/ic_search.xml b/android/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 0000000..82383d4 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,13 @@ + + + diff --git a/android/app/src/main/res/menu/bottom_navigation_items.xml b/android/app/src/main/res/menu/bottom_navigation_items.xml index 7072fc7..31ed6a4 100644 --- a/android/app/src/main/res/menu/bottom_navigation_items.xml +++ b/android/app/src/main/res/menu/bottom_navigation_items.xml @@ -6,12 +6,16 @@ android:icon="@drawable/home_tab_selector" android:title="@string/home" /> + + - + \ No newline at end of file diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt new file mode 100644 index 0000000..8437a80 --- /dev/null +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt @@ -0,0 +1,24 @@ +package com.ohdodok.catchytape.feature.search + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.viewModels +import com.ohdodok.catchytape.core.ui.BaseFragment +import com.ohdodok.catchytape.feature.search.databinding.FragmentSearchBinding +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class SearchFragment : BaseFragment(R.layout.fragment_search) { + init { + println("아니 왜 안 돼!!") + } + + private val viewModel: SearchViewModel by viewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.viewModel = viewModel + } +} \ No newline at end of file diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt new file mode 100644 index 0000000..751ac42 --- /dev/null +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt @@ -0,0 +1,12 @@ +package com.ohdodok.catchytape.feature.search + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class SearchViewModel @Inject constructor( + +) : ViewModel() { + +} \ No newline at end of file diff --git a/android/feature/search/src/main/res/layout/fragment_search.xml b/android/feature/search/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..1eabc1f --- /dev/null +++ b/android/feature/search/src/main/res/layout/fragment_search.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/feature/search/src/main/res/navigation/search_navigation.xml b/android/feature/search/src/main/res/navigation/search_navigation.xml new file mode 100644 index 0000000..b035281 --- /dev/null +++ b/android/feature/search/src/main/res/navigation/search_navigation.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file From b63f5fc822cea2a07ae6e94327c77763e6278211 Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 01:06:40 +0900 Subject: [PATCH 032/205] =?UTF-8?q?feat=20:=20getRecentPlaylist=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 사용자의 최근 재생 목록을 가져오는 getRecentPlaylist 추가 --- server/src/config/errorCode.enum.ts | 1 + server/src/playlist/playlist.service.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/server/src/config/errorCode.enum.ts b/server/src/config/errorCode.enum.ts index f779c42..2b7497b 100644 --- a/server/src/config/errorCode.enum.ts +++ b/server/src/config/errorCode.enum.ts @@ -5,6 +5,7 @@ export enum ERROR_CODE { 'SERVICE_ERROR' = 5001, 'MUSIC_ENCODE_ERROR' = 5002, 'ENCODED_MUSIC_UPLOAD_ERROR' = 5003, + 'QUERY_ERROR' = 5004, 'NOT_EXIST_PLAYLIST_ON_USER' = 4001, 'NOT_EXIST_MUSIC' = 4002, 'ALREADY_ADDED' = 4003, diff --git a/server/src/playlist/playlist.service.ts b/server/src/playlist/playlist.service.ts index f3f87ac..d4134c6 100644 --- a/server/src/playlist/playlist.service.ts +++ b/server/src/playlist/playlist.service.ts @@ -223,4 +223,20 @@ export class PlaylistService { ); } } + + async getRecentPlaylist(user_id: string): Promise { + try { + return await this.playlistRepository.findOne({ + where: { + user: { user_id }, + }, + }); + } catch { + throw new CatchyException( + 'QUERY_ERROR', + HTTP_STATUS_CODE.SERVER_ERROR, + ERROR_CODE.QUERY_ERROR, + ); + } + } } From e00ca15162a6f39b2f376408386509321f4b09b8 Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 01:46:37 +0900 Subject: [PATCH 033/205] =?UTF-8?q?feat=20:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EC=9E=AC=EC=83=9D=20=EB=AA=A9=EB=A1=9D=20update=20API=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 최근 재생 목록의 날짜를 update 하는 함수 구현 * PATCH /playlists/recently-played --- server/src/playlist/playlist.controller.ts | 24 +++++++++++++++++++++- server/src/playlist/playlist.service.ts | 17 +++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/server/src/playlist/playlist.controller.ts b/server/src/playlist/playlist.controller.ts index 1aa7ddd..73bfcbd 100644 --- a/server/src/playlist/playlist.controller.ts +++ b/server/src/playlist/playlist.controller.ts @@ -53,7 +53,7 @@ export class PlaylistController { playlistId, music_id, ); - return { music_playlist_id}; + return { music_playlist_id }; } @Get() @@ -76,4 +76,26 @@ export class PlaylistController { const userId: string = req.user.user_id; return await this.playlistService.getPlaylistMusics(userId, playlistId); } + + @Patch('recently-played') + @UseGuards(AuthGuard()) + @HttpCode(HTTP_STATUS_CODE.SUCCESS) + async updateRecentPlay( + @Req() req, + @Body('musicId') music_id: string, + ): Promise { + const user_id: string = req.user.user_id; + const recentPlaylist: Playlist = + await this.playlistService.getRecentPlaylist(user_id); + const recentPlaylistId: number = recentPlaylist.playlist_id; + if (await this.playlistService.isAlreadyAdded(recentPlaylistId, music_id)) { + return this.playlistService.updateRecentMusic(music_id, recentPlaylistId); + } else { + return this.playlistService.addMusicToPlaylist( + user_id, + recentPlaylistId, + music_id, + ); + } + } } diff --git a/server/src/playlist/playlist.service.ts b/server/src/playlist/playlist.service.ts index d4134c6..4c3a6b9 100644 --- a/server/src/playlist/playlist.service.ts +++ b/server/src/playlist/playlist.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { CatchyException } from 'src/config/catchyException'; import { ERROR_CODE } from 'src/config/errorCode.enum'; +import { RECENT_PLAYLIST_NAME } from 'src/constants'; import { PlaylistCreateDto } from 'src/dto/playlistCreate.dto'; import { Music } from 'src/entity/music.entity'; import { Music_Playlist } from 'src/entity/music_playlist.entity'; @@ -229,6 +230,7 @@ export class PlaylistService { return await this.playlistRepository.findOne({ where: { user: { user_id }, + playlist_title: RECENT_PLAYLIST_NAME, }, }); } catch { @@ -239,4 +241,19 @@ export class PlaylistService { ); } } + + async updateRecentMusic( + music_id: string, + playlist_id: number, + ): Promise { + const music_playlist: Music_Playlist = + await this.music_playlistRepository.findOne({ + where: { music: { music_id }, playlist: { playlist_id } }, + }); + + music_playlist.updated_at = new Date(); + const savedData: Music_Playlist = + await this.music_playlistRepository.save(music_playlist); + return savedData.music_playlist_id; + } } From 668b4896f265f1bc24dc22b1a90c30e4137a5bde Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 01:50:38 +0900 Subject: [PATCH 034/205] =?UTF-8?q?refactor=20:=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EB=AA=A8=EC=96=91=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * { music_playlist_id: number } 로 변경 --- server/src/playlist/playlist.controller.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/server/src/playlist/playlist.controller.ts b/server/src/playlist/playlist.controller.ts index 73bfcbd..0de7907 100644 --- a/server/src/playlist/playlist.controller.ts +++ b/server/src/playlist/playlist.controller.ts @@ -83,19 +83,26 @@ export class PlaylistController { async updateRecentPlay( @Req() req, @Body('musicId') music_id: string, - ): Promise { + ): Promise<{ music_playlist_id: number }> { const user_id: string = req.user.user_id; const recentPlaylist: Playlist = await this.playlistService.getRecentPlaylist(user_id); const recentPlaylistId: number = recentPlaylist.playlist_id; if (await this.playlistService.isAlreadyAdded(recentPlaylistId, music_id)) { - return this.playlistService.updateRecentMusic(music_id, recentPlaylistId); + return { + music_playlist_id: await this.playlistService.updateRecentMusic( + music_id, + recentPlaylistId, + ), + }; } else { - return this.playlistService.addMusicToPlaylist( - user_id, - recentPlaylistId, - music_id, - ); + return { + music_playlist_id: await this.playlistService.addMusicToPlaylist( + user_id, + recentPlaylistId, + music_id, + ), + }; } } } From 06b4d219d525bfbd4be39383d83af2c0749e0035 Mon Sep 17 00:00:00 2001 From: algosketch Date: Tue, 5 Dec 2023 01:52:00 +0900 Subject: [PATCH 035/205] =?UTF-8?q?feat=20:=20=EA=B2=80=EC=83=89=EC=96=B4?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/drawable/search_bar_background.xml | 4 ++++ .../feature/search/SearchFragment.kt | 5 ----- .../feature/search/SearchViewModel.kt | 14 ++++++++++++++ .../src/main/res/layout/fragment_search.xml | 18 +++++++++++++++++- .../search/src/main/res/values/strings.xml | 4 ++++ 5 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 android/core/ui/src/main/res/drawable/search_bar_background.xml create mode 100644 android/feature/search/src/main/res/values/strings.xml diff --git a/android/core/ui/src/main/res/drawable/search_bar_background.xml b/android/core/ui/src/main/res/drawable/search_bar_background.xml new file mode 100644 index 0000000..dcb88e5 --- /dev/null +++ b/android/core/ui/src/main/res/drawable/search_bar_background.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt index 8437a80..33bd928 100644 --- a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt @@ -1,9 +1,7 @@ package com.ohdodok.catchytape.feature.search import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import androidx.fragment.app.viewModels import com.ohdodok.catchytape.core.ui.BaseFragment import com.ohdodok.catchytape.feature.search.databinding.FragmentSearchBinding @@ -11,9 +9,6 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class SearchFragment : BaseFragment(R.layout.fragment_search) { - init { - println("아니 왜 안 돼!!") - } private val viewModel: SearchViewModel by viewModels() diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt index 751ac42..204b250 100644 --- a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt @@ -2,11 +2,25 @@ package com.ohdodok.catchytape.feature.search import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update import javax.inject.Inject +data class SearchUiState( + val keyword: String = "", +) + @HiltViewModel class SearchViewModel @Inject constructor( ) : ViewModel() { + private val _uiState = MutableStateFlow(SearchUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + fun updateKeyword(newKeyword: String) { + _uiState.update { it.copy(keyword = newKeyword) } + } } \ No newline at end of file diff --git a/android/feature/search/src/main/res/layout/fragment_search.xml b/android/feature/search/src/main/res/layout/fragment_search.xml index 1eabc1f..e4e7c65 100644 --- a/android/feature/search/src/main/res/layout/fragment_search.xml +++ b/android/feature/search/src/main/res/layout/fragment_search.xml @@ -1,7 +1,9 @@ - + + @@ -11,5 +13,19 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + \ No newline at end of file diff --git a/android/feature/search/src/main/res/values/strings.xml b/android/feature/search/src/main/res/values/strings.xml new file mode 100644 index 0000000..3ea6048 --- /dev/null +++ b/android/feature/search/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + 검색어를 입력하세요. + \ No newline at end of file From 3d717a4113127a6fb9a3e49c6a2a31eda3217a9d Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 01:52:19 +0900 Subject: [PATCH 036/205] =?UTF-8?q?feat=20:=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * updateRecentMusic 예외 처리 추가 --- server/src/playlist/playlist.service.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/server/src/playlist/playlist.service.ts b/server/src/playlist/playlist.service.ts index 4c3a6b9..9384090 100644 --- a/server/src/playlist/playlist.service.ts +++ b/server/src/playlist/playlist.service.ts @@ -246,14 +246,22 @@ export class PlaylistService { music_id: string, playlist_id: number, ): Promise { - const music_playlist: Music_Playlist = - await this.music_playlistRepository.findOne({ - where: { music: { music_id }, playlist: { playlist_id } }, - }); + try { + const music_playlist: Music_Playlist = + await this.music_playlistRepository.findOne({ + where: { music: { music_id }, playlist: { playlist_id } }, + }); - music_playlist.updated_at = new Date(); - const savedData: Music_Playlist = - await this.music_playlistRepository.save(music_playlist); - return savedData.music_playlist_id; + music_playlist.updated_at = new Date(); + const savedData: Music_Playlist = + await this.music_playlistRepository.save(music_playlist); + return savedData.music_playlist_id; + } catch { + throw new CatchyException( + 'SERVICE_ERROR', + HTTP_STATUS_CODE.SERVER_ERROR, + ERROR_CODE.SERVICE_ERROR, + ); + } } } From 3949c0ef1d54a6ec1824b9bbb4d0d09088e8107c Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 01:57:26 +0900 Subject: [PATCH 037/205] =?UTF-8?q?refactor=20:=20=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=9D=8C=EC=95=85=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EC=88=9C=EC=84=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ID 내림차순 -> updated_at 내림차순 --- server/src/entity/music_playlist.entity.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/src/entity/music_playlist.entity.ts b/server/src/entity/music_playlist.entity.ts index fe19290..0285350 100644 --- a/server/src/entity/music_playlist.entity.ts +++ b/server/src/entity/music_playlist.entity.ts @@ -8,6 +8,7 @@ import { } from 'typeorm'; import { Music } from './music.entity'; import { Playlist } from './playlist.entity'; +import { RECENT_PLAYLIST_NAME } from 'src/constants'; @Entity({ name: 'music_playlist' }) export class Music_Playlist extends BaseEntity { @@ -45,7 +46,7 @@ export class Music_Playlist extends BaseEntity { music_playlist_id: false, }, order: { - music_playlist_id: 'DESC', + updated_at: 'DESC', }, }).then((a: Music_Playlist[]) => a.map((b) => b.music)); } @@ -57,7 +58,7 @@ export class Music_Playlist extends BaseEntity { }, where: { playlist: { - playlist_title: '최근 재생 목록', + playlist_title: RECENT_PLAYLIST_NAME, }, music: { user: { @@ -76,7 +77,7 @@ export class Music_Playlist extends BaseEntity { }, }, order: { - music_playlist_id: 'DESC', + updated_at: 'DESC', }, take: 10, }).then((a: Music_Playlist[]) => a.map((b) => b.music)); @@ -93,7 +94,7 @@ export class Music_Playlist extends BaseEntity { relations: { music: true }, select: { music: { cover: true } }, where: { playlist: { playlist_id } }, - order: { music_playlist_id: 'DESC' }, + order: { updated_at: 'DESC' }, }); } } From 78b869e38d5cdc707774067012ff990ab27736b6 Mon Sep 17 00:00:00 2001 From: youlalala Date: Tue, 5 Dec 2023 04:13:15 +0900 Subject: [PATCH 038/205] =?UTF-8?q?feat=20:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B0=B0=EA=B2=BD=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EA=B7=B8=EB=9D=BC=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/res/drawable/gradient_background.xml | 8 +++++ .../playlist/PlaylistDetailFragment.kt | 9 +++++- .../playlist/PlaylistDetailViewModel.kt | 29 +++++++++++++++++++ .../res/layout/fragment_playlist_detail.xml | 28 ++++++++++++++++-- 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 android/core/ui/src/main/res/drawable/gradient_background.xml create mode 100644 android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailViewModel.kt diff --git a/android/core/ui/src/main/res/drawable/gradient_background.xml b/android/core/ui/src/main/res/drawable/gradient_background.xml new file mode 100644 index 0000000..1ffb949 --- /dev/null +++ b/android/core/ui/src/main/res/drawable/gradient_background.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt index a6859ab..7b1a72d 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailFragment.kt @@ -2,16 +2,23 @@ package com.ohdodok.catchytape.feature.playlist import android.os.Bundle import android.view.View +import androidx.fragment.app.viewModels import com.ohdodok.catchytape.core.ui.BaseFragment +import com.ohdodok.catchytape.core.ui.MusicAdapter +import com.ohdodok.catchytape.core.ui.Orientation import com.ohdodok.catchytape.feature.playlist.databinding.FragmentPlaylistDetailBinding class PlaylistDetailFragment : BaseFragment(R.layout.fragment_playlist_detail) { + private val viewModel: PlaylistDetailViewModel by viewModels() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + binding.viewModel = viewModel setupBackStack(binding.tbPlaylistDetail) + binding.rvPlaylist.adapter = MusicAdapter(Orientation.VERTICAL) } - } diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailViewModel.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailViewModel.kt new file mode 100644 index 0000000..bf771a4 --- /dev/null +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistDetailViewModel.kt @@ -0,0 +1,29 @@ +package com.ohdodok.catchytape.feature.playlist + +import androidx.lifecycle.ViewModel +import com.ohdodok.catchytape.core.domain.model.Music +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +data class PlaylistDetailUiState( + val musics: List = listOf( + Music( + id = "1", + title = "title", + artist = "artist", + imageUrl = "https://i.pinimg.com/736x/6a/be/29/6abe2929274d6459c815ac752fb0c057.jpg" + ) + ) +) + +@HiltViewModel +class PlaylistDetailViewModel @Inject constructor( + +) : ViewModel() { + + private val _uiState = MutableStateFlow(PlaylistDetailUiState()) + val uiState: StateFlow = _uiState.asStateFlow() +} \ No newline at end of file diff --git a/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml b/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml index a9857f8..275b568 100644 --- a/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml +++ b/android/feature/playlist/src/main/res/layout/fragment_playlist_detail.xml @@ -6,8 +6,8 @@ + name="viewModel" + type="com.ohdodok.catchytape.feature.playlist.PlaylistDetailViewModel" /> @@ -15,6 +15,28 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + + @@ -57,6 +80,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/ctl_playlist_detail" + app:list="@{viewModel.uiState.musics}" tools:listitem="@layout/item_music_vertical" /> From ae0f655044fa2741cf3f604b45fdea74017fcb19 Mon Sep 17 00:00:00 2001 From: youlalala Date: Tue, 5 Dec 2023 04:59:09 +0900 Subject: [PATCH 039/205] =?UTF-8?q?feat=20:=20status=20bar=20=ED=88=AC?= =?UTF-8?q?=EB=AA=85=ED=95=98=EA=B2=8C=20=ED=95=98=EA=B3=A0,=20=EC=98=81?= =?UTF-8?q?=EC=97=AD=20=EB=84=93=ED=9E=88=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/java/com/ohdodok/catchytape/MainActivity.kt | 4 ++++ android/core/ui/src/main/res/values-night/themes.xml | 2 +- android/core/ui/src/main/res/values/dimens.xml | 1 + android/core/ui/src/main/res/values/themes.xml | 5 ++--- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index 6464eb3..e6b26f9 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -8,6 +8,7 @@ import android.view.View import android.widget.Toast import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.WindowCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle @@ -43,9 +44,12 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) + binding.viewModel = playViewModel binding.lifecycleOwner = this + WindowCompat.setDecorFitsSystemWindows(window, false) + setupBottomNav() setUpPlayerController() connectivityManager = getSystemService(ConnectivityManager::class.java) diff --git a/android/core/ui/src/main/res/values-night/themes.xml b/android/core/ui/src/main/res/values-night/themes.xml index 1d3cb6b..c796b91 100644 --- a/android/core/ui/src/main/res/values-night/themes.xml +++ b/android/core/ui/src/main/res/values-night/themes.xml @@ -2,7 +2,7 @@ @@ -59,7 +60,6 @@ @color/key_variant - - \ No newline at end of file From a4691f622357407b9038f1201c4c5cfc78b34697 Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 10:19:06 +0900 Subject: [PATCH 040/205] =?UTF-8?q?refacfor=20:=20path=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 통일성을 위해 /playlists/recent-played 로 수정 --- server/src/playlist/playlist.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/playlist/playlist.controller.ts b/server/src/playlist/playlist.controller.ts index 0de7907..536b1ee 100644 --- a/server/src/playlist/playlist.controller.ts +++ b/server/src/playlist/playlist.controller.ts @@ -77,7 +77,7 @@ export class PlaylistController { return await this.playlistService.getPlaylistMusics(userId, playlistId); } - @Patch('recently-played') + @Patch('recent-played') @UseGuards(AuthGuard()) @HttpCode(HTTP_STATUS_CODE.SUCCESS) async updateRecentPlay( From 8a55f531e89d9333ea59654ff548911f3b86c4e5 Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 10:23:18 +0900 Subject: [PATCH 041/205] =?UTF-8?q?refactor=20:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20else=20=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 * playlist.controller - updateRecentPlay 에서 제거 --- server/src/playlist/playlist.controller.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/server/src/playlist/playlist.controller.ts b/server/src/playlist/playlist.controller.ts index 536b1ee..c2c6d85 100644 --- a/server/src/playlist/playlist.controller.ts +++ b/server/src/playlist/playlist.controller.ts @@ -95,14 +95,13 @@ export class PlaylistController { recentPlaylistId, ), }; - } else { - return { - music_playlist_id: await this.playlistService.addMusicToPlaylist( - user_id, - recentPlaylistId, - music_id, - ), - }; } + return { + music_playlist_id: await this.playlistService.addMusicToPlaylist( + user_id, + recentPlaylistId, + music_id, + ), + }; } } From f5cfaaafe38e7ed7fbb8cc043a4f352c752f6957 Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 10:25:02 +0900 Subject: [PATCH 042/205] =?UTF-8?q?refactor=20:=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * updateRecentPlay -> updateRecentPlayMusic 으로 수정 --- server/src/playlist/playlist.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/playlist/playlist.controller.ts b/server/src/playlist/playlist.controller.ts index c2c6d85..d0af2a1 100644 --- a/server/src/playlist/playlist.controller.ts +++ b/server/src/playlist/playlist.controller.ts @@ -80,7 +80,7 @@ export class PlaylistController { @Patch('recent-played') @UseGuards(AuthGuard()) @HttpCode(HTTP_STATUS_CODE.SUCCESS) - async updateRecentPlay( + async updateRecentPlayMusic( @Req() req, @Body('musicId') music_id: string, ): Promise<{ music_playlist_id: number }> { From df02db4106340aae1acd0f63e2ce31d73153cc0d Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 13:54:02 +0900 Subject: [PATCH 043/205] =?UTF-8?q?feat=20:=20PlayerUtil=EC=97=90=20?= =?UTF-8?q?=EB=8B=A4=EC=9D=8C,=20=EC=9D=B4=EC=A0=84=20=EA=B3=A1=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EB=B0=8F=20getMediasWithMetaData=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ohdodok/catchytape/MainActivity.kt | 8 ++-- .../feature/player/PlayerFragment.kt | 6 +-- .../catchytape/feature/player/PlayerUtil.kt | 46 +++++++++++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index 5f54916..36ac48e 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -23,6 +23,8 @@ import com.ohdodok.catchytape.databinding.ActivityMainBinding import com.ohdodok.catchytape.feature.player.PlayerListener import com.ohdodok.catchytape.feature.player.PlayerViewModel import com.ohdodok.catchytape.feature.player.millisecondsPerSecond +import com.ohdodok.catchytape.feature.player.moveNextMedia +import com.ohdodok.catchytape.feature.player.movePreviousMedia import com.ohdodok.catchytape.feature.player.navigateToPlayer import com.ohdodok.catchytape.mediasession.PlaybackService import dagger.hilt.android.AndroidEntryPoint @@ -148,15 +150,13 @@ class MainActivity : AppCompatActivity() { private fun setupPreviousButton() { binding.pcvController.setOnPreviousButtonClick { - player.seekToPreviousMediaItem() - player.play() + player.movePreviousMedia() } } private fun setupNextButton() { binding.pcvController.setOnNextButtonClick { - player.seekToNextMediaItem() - player.play() + player.moveNextMedia() } } diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt index 97cc6c1..f498981 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt @@ -77,13 +77,11 @@ class PlayerFragment : BaseFragment(R.layout.fragment_pla } binding.btnNext.setOnClickListener { - player.seekToNextMediaItem() - player.play() + player.moveNextMedia() } binding.btnPrevious.setOnClickListener { - player.seekToPreviousMediaItem() - player.play() + player.movePreviousMedia() } } diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt new file mode 100644 index 0000000..8dd67e7 --- /dev/null +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt @@ -0,0 +1,46 @@ +package com.ohdodok.catchytape.feature.player + +import androidx.core.net.toUri +import androidx.media3.common.MediaItem +import androidx.media3.common.MediaMetadata +import androidx.media3.exoplayer.ExoPlayer +import com.ohdodok.catchytape.core.domain.model.Music + + +fun ExoPlayer.moveNextMedia() { + if (isPlaying) { + seekToNextMediaItem() + play() + } else { + seekToNextMediaItem() + } +} + + +fun ExoPlayer.movePreviousMedia() { + if (isPlaying) { + seekToPreviousMediaItem() + play() + } else { + seekToPreviousMediaItem() + } +} + + +fun getMediasWithMetaData(musics: List): List { + val mediaItemBuilder = MediaItem.Builder() + val mediaMetadataBuilder = MediaMetadata.Builder() + return musics.map { music -> + mediaItemBuilder + .setMediaId(music.id) + .setUri("~~~~.m3u8") // TODO :Music domain에서 변수 추가 되면 반영해야 함 + .setMediaMetadata( + mediaMetadataBuilder + .setArtist(music.artist) + .setTitle(music.title) + .setArtworkUri(music.imageUrl.toUri()) + .build() + ) + .build() + } +} \ No newline at end of file From c89d5fc765297a2efea06459f7d9eb3e339c2da4 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Tue, 5 Dec 2023 14:06:33 +0900 Subject: [PATCH 044/205] =?UTF-8?q?feat=20:=20User=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 단순히 성능을 고려하지 않고 ILIKE를 통해 구현 * /users/search API --- server/src/user/user.controller.ts | 10 ++++++++++ server/src/user/user.service.ts | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/server/src/user/user.controller.ts b/server/src/user/user.controller.ts index 1a8a145..6472de8 100644 --- a/server/src/user/user.controller.ts +++ b/server/src/user/user.controller.ts @@ -7,6 +7,7 @@ import { UseGuards, Patch, Body, + Query, } from '@nestjs/common'; import { UserService } from './user.service'; import { HTTP_STATUS_CODE } from 'src/httpStatusCode.enum'; @@ -67,4 +68,13 @@ export class UserController { const user_id = req.user.userId; return this.userService.getUserInformation(user_id); } + + @Get('search') + @UseGuards(AuthGuard()) + @HttpCode(HTTP_STATUS_CODE.SUCCESS) + async getCertainNicknameUser( + @Query('keyword') keyword: string, + ): Promise { + return this.userService.getCertainKeywordNicknameUser(keyword); + } } diff --git a/server/src/user/user.service.ts b/server/src/user/user.service.ts index a66cea9..aef2665 100644 --- a/server/src/user/user.service.ts +++ b/server/src/user/user.service.ts @@ -82,4 +82,16 @@ export class UserService { ); } } + + async getCertainKeywordNicknameUser(keyword: string): Promise { + try { + return User.getCertainUserByNickname(keyword); + } catch { + throw new CatchyException( + 'SERVER_ERROR', + HTTP_STATUS_CODE.SERVER_ERROR, + ERROR_CODE.SERVICE_ERROR, + ); + } + } } From 2df7ce61d92961d365cda08fe441ea927418a58f Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Tue, 5 Dec 2023 14:12:19 +0900 Subject: [PATCH 045/205] =?UTF-8?q?feat=20:=20Music=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * find에서 ILIKE로 조건을 걸어 단순 구현 * API path는 /musics/search --- server/src/entity/music.entity.ts | 24 +++++++++++++++++++++++- server/src/entity/user.entity.ts | 20 ++++++++++++++++++++ server/src/music/music.controller.ts | 9 +++++++++ server/src/music/music.service.ts | 12 ++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/server/src/entity/music.entity.ts b/server/src/entity/music.entity.ts index c6e3cb2..15a889c 100644 --- a/server/src/entity/music.entity.ts +++ b/server/src/entity/music.entity.ts @@ -4,10 +4,10 @@ import { CreateDateColumn, BaseEntity, JoinColumn, - PrimaryGeneratedColumn, ManyToOne, OneToMany, PrimaryColumn, + ILike, } from 'typeorm'; import { User } from './user.entity'; import { Genres } from 'src/constants'; @@ -103,4 +103,26 @@ export class Music extends BaseEntity { where: { music_id }, }); } + + static async getCertainMusicByTitle(keyword: string): Promise { + return await this.find({ + relations: { + user: false, + music_playlist: false, + }, + select: { + music_id: true, + lyrics: true, + title: true, + cover: true, + music_file: true, + }, + where: { + title: ILike(`%${keyword}%`), + }, + order: { + created_at: 'DESC', + }, + }); + } } diff --git a/server/src/entity/user.entity.ts b/server/src/entity/user.entity.ts index e0d5ae6..5d56090 100644 --- a/server/src/entity/user.entity.ts +++ b/server/src/entity/user.entity.ts @@ -5,6 +5,7 @@ import { BaseEntity, PrimaryColumn, OneToMany, + ILike, } from 'typeorm'; import { Playlist } from './playlist.entity'; import { Music } from './music.entity'; @@ -31,4 +32,23 @@ export class User extends BaseEntity { @OneToMany(() => Playlist, (playlist) => playlist.user) playlists: Playlist[]; + + static async getCertainUserByNickname(keyword: string): Promise { + return this.find({ + relations: { + musics: false, + playlists: false, + }, + select: { + user_id: true, + nickname: true, + user_email: true, + photo: true, + created_at: true, + }, + where: { + nickname: ILike(`%${keyword}%`), + }, + }); + } } diff --git a/server/src/music/music.controller.ts b/server/src/music/music.controller.ts index 4bbb80b..22e61ea 100644 --- a/server/src/music/music.controller.ts +++ b/server/src/music/music.controller.ts @@ -81,4 +81,13 @@ export class MusicController { file: await this.musicService.getEncodedChunkFiles(music_id, fileName), }; } + + @Get('search') + @UseGuards(AuthGuard()) + @HttpCode(HTTP_STATUS_CODE.SUCCESS) + async getCertainTitleMusic( + @Query('keyword') keyword: string, + ): Promise { + return this.musicService.getCertainKeywordNicknameUser(keyword); + } } diff --git a/server/src/music/music.service.ts b/server/src/music/music.service.ts index 4723a40..b291c5c 100644 --- a/server/src/music/music.service.ts +++ b/server/src/music/music.service.ts @@ -299,4 +299,16 @@ export class MusicService { ); } } + + async getCertainKeywordNicknameUser(keyword: string): Promise { + try { + return await Music.getCertainMusicByTitle(keyword); + } catch { + throw new CatchyException( + 'SERVER_ERROR', + HTTP_STATUS_CODE.SERVER_ERROR, + ERROR_CODE.SERVICE_ERROR, + ); + } + } } From c5dfd44fe0d2649d79be789e130a84ab225dc833 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Tue, 5 Dec 2023 14:19:10 +0900 Subject: [PATCH 046/205] =?UTF-8?q?chore=20:=20Music=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=20=EC=8B=9C=20User=20=EC=A0=95=EB=B3=B4=20=ED=95=A8=EA=BB=98?= =?UTF-8?q?=20=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 아티스트명은 아래에 들어가야 함 --- server/src/entity/music.entity.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/entity/music.entity.ts b/server/src/entity/music.entity.ts index 15a889c..69acd1d 100644 --- a/server/src/entity/music.entity.ts +++ b/server/src/entity/music.entity.ts @@ -107,7 +107,7 @@ export class Music extends BaseEntity { static async getCertainMusicByTitle(keyword: string): Promise { return await this.find({ relations: { - user: false, + user: true, music_playlist: false, }, select: { @@ -116,6 +116,10 @@ export class Music extends BaseEntity { title: true, cover: true, music_file: true, + user: { + user_id: true, + nickname: true, + }, }, where: { title: ILike(`%${keyword}%`), From 39d1cb95642e16ff093e3eb67e59c7d8f733e832 Mon Sep 17 00:00:00 2001 From: algosketch Date: Tue, 5 Dec 2023 14:32:10 +0900 Subject: [PATCH 047/205] =?UTF-8?q?feat=20:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=ED=99=94=EB=A9=B4=EA=B0=84=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle.kts | 1 + .../com/ohdodok/catchytape/MainActivity.kt | 23 +++++++++++++++++++ .../usecase/player/CurrentPlayListUseCase.kt | 2 ++ .../feature/player/PlayerFragment.kt | 2 +- .../feature/player/PlayerViewModel.kt | 4 +++- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 5433ef8..50150c7 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -67,6 +67,7 @@ dependencies { implementation(project(":feature:playlist")) implementation(project(":feature:mypage")) implementation(project(":core:data")) + implementation(project(":core:domain")) implementation(libs.core.ktx) implementation(libs.appcompat) diff --git a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt index 4e466fd..8033ea5 100644 --- a/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt +++ b/android/app/src/main/java/com/ohdodok/catchytape/MainActivity.kt @@ -10,6 +10,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.media3.common.MediaItem import androidx.media3.exoplayer.ExoPlayer import androidx.navigation.findNavController import androidx.navigation.fragment.NavHostFragment @@ -21,6 +22,7 @@ import com.ohdodok.catchytape.feature.player.PlayerViewModel import com.ohdodok.catchytape.feature.player.millisecondsPerSecond import com.ohdodok.catchytape.feature.player.navigateToPlayer import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.delay import kotlinx.coroutines.launch import javax.inject.Inject @@ -53,6 +55,7 @@ class MainActivity : AppCompatActivity() { setupPlayer() setupPlayButton() + observePlaylistChange() } private fun checkNetworkState() { @@ -128,6 +131,26 @@ class MainActivity : AppCompatActivity() { } } + private fun observePlaylistChange() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + playViewModel.playlistChangeEvent.consumeEach { newPlaylist -> + val newItems = newPlaylist.musics.map { + // todo : it에서 url 찾아서 넣어주기! + MediaItem.Builder().setUri("https://catchy-tape-bucket2.kr.object.ncloudstorage.com/music/8ce4b6b0-6480-479a-99b9-54ef7e913313/music.m3u8") + .setMediaId(it.id) + .build() + } + player.clearMediaItems() + player.setMediaItems(newItems) + + val index = newPlaylist.musics.indexOf(newPlaylist.startMusic) + player.seekTo(index, 0) + player.play() + } + } + } + } private fun setupPlayButton() { binding.pcvController.setOnPlayButtonClick { diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt index d0f5e11..d930094 100644 --- a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/player/CurrentPlayListUseCase.kt @@ -9,7 +9,9 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.launch import javax.inject.Inject +import javax.inject.Singleton +@Singleton class CurrentPlaylistUseCase @Inject constructor() { private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) private val _currentPlaylist = Channel() diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt index 3c775d9..3066e32 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerFragment.kt @@ -29,7 +29,7 @@ class PlayerFragment : BaseFragment(R.layout.fragment_pla setUpSeekBar() // todo : 실제 데이터로 변경 - setMedia("https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8") +// setMedia("https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8") setupButtons() collectEvents() } diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt index 9a336e1..d0beaa2 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerViewModel.kt @@ -2,6 +2,7 @@ package com.ohdodok.catchytape.feature.player import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.ohdodok.catchytape.core.domain.usecase.player.CurrentPlaylistUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -25,8 +26,9 @@ sealed interface PlayerEvent { @HiltViewModel class PlayerViewModel @Inject constructor( - + private val currentPlaylistUseCase: CurrentPlaylistUseCase, ) : ViewModel(), PlayerEventListener { + val playlistChangeEvent = currentPlaylistUseCase.currentPlaylist private val _uiState = MutableStateFlow(PlayerState()) val uiState: StateFlow = _uiState.asStateFlow() From f40934fa4dba2a92a67bb988efd5559e0c0c90c3 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Tue, 5 Dec 2023 14:52:41 +0900 Subject: [PATCH 048/205] chore : SERVER_ERROR => QUERY_ERROR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 쿼리문에 의해 에러가 발생하는 경우를 구분하기 위해 에러 코드 변경 --- server/src/music/music.service.ts | 4 ++-- server/src/user/user.service.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/music/music.service.ts b/server/src/music/music.service.ts index b291c5c..5cbf9fe 100644 --- a/server/src/music/music.service.ts +++ b/server/src/music/music.service.ts @@ -305,9 +305,9 @@ export class MusicService { return await Music.getCertainMusicByTitle(keyword); } catch { throw new CatchyException( - 'SERVER_ERROR', + 'QUERY_ERROR', HTTP_STATUS_CODE.SERVER_ERROR, - ERROR_CODE.SERVICE_ERROR, + ERROR_CODE.QUERY_ERROR, ); } } diff --git a/server/src/user/user.service.ts b/server/src/user/user.service.ts index aef2665..58f4b6c 100644 --- a/server/src/user/user.service.ts +++ b/server/src/user/user.service.ts @@ -88,9 +88,9 @@ export class UserService { return User.getCertainUserByNickname(keyword); } catch { throw new CatchyException( - 'SERVER_ERROR', + 'QUERY_ERROR', HTTP_STATUS_CODE.SERVER_ERROR, - ERROR_CODE.SERVICE_ERROR, + ERROR_CODE.QUERY_ERROR, ); } } From 32d81893f791844139a2caccebe98447b9fb0aed Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 15:11:54 +0900 Subject: [PATCH 049/205] =?UTF-8?q?refactor=20:=20move=20Media=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ohdodok/catchytape/feature/player/PlayerUtil.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt index 8dd67e7..6575553 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt @@ -8,21 +8,17 @@ import com.ohdodok.catchytape.core.domain.model.Music fun ExoPlayer.moveNextMedia() { + seekToNextMediaItem() if (isPlaying) { - seekToNextMediaItem() play() - } else { - seekToNextMediaItem() } } fun ExoPlayer.movePreviousMedia() { + seekToPreviousMediaItem() if (isPlaying) { - seekToPreviousMediaItem() play() - } else { - seekToPreviousMediaItem() } } From 485573b820330efe6c117a4afb9f73a3a0e2aa23 Mon Sep 17 00:00:00 2001 From: algosketch Date: Tue, 5 Dec 2023 15:33:47 +0900 Subject: [PATCH 050/205] =?UTF-8?q?feat=20:=20EditText=20text=20=EB=B0=94?= =?UTF-8?q?=EC=9D=B8=EB=94=A9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/feature/search/src/main/res/layout/fragment_search.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/android/feature/search/src/main/res/layout/fragment_search.xml b/android/feature/search/src/main/res/layout/fragment_search.xml index e4e7c65..feafe15 100644 --- a/android/feature/search/src/main/res/layout/fragment_search.xml +++ b/android/feature/search/src/main/res/layout/fragment_search.xml @@ -20,7 +20,6 @@ android:background="@drawable/search_bar_background" android:backgroundTint="@color/surface_bright" android:hint="@string/input_keyword" - android:text="@{viewModel.uiState.keyword}" android:onTextChanged="@{(text, s, b, c) -> viewModel.updateKeyword(text.toString())}" android:paddingHorizontal="@dimen/margin_horizontal" app:layout_constraintEnd_toEndOf="parent" From a100d115974fc3208496c71853e7c667cad1ebac Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 15:42:05 +0900 Subject: [PATCH 051/205] =?UTF-8?q?refactor=20:=20=EA=B0=9C=ED=96=89=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt index 6575553..eedceb8 100644 --- a/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt +++ b/android/feature/player/src/main/java/com/ohdodok/catchytape/feature/player/PlayerUtil.kt @@ -6,7 +6,6 @@ import androidx.media3.common.MediaMetadata import androidx.media3.exoplayer.ExoPlayer import com.ohdodok.catchytape.core.domain.model.Music - fun ExoPlayer.moveNextMedia() { seekToNextMediaItem() if (isPlaying) { @@ -14,7 +13,6 @@ fun ExoPlayer.moveNextMedia() { } } - fun ExoPlayer.movePreviousMedia() { seekToPreviousMediaItem() if (isPlaying) { @@ -22,7 +20,6 @@ fun ExoPlayer.movePreviousMedia() { } } - fun getMediasWithMetaData(musics: List): List { val mediaItemBuilder = MediaItem.Builder() val mediaMetadataBuilder = MediaMetadata.Builder() From 1bf96c223684c5a5c99c295a6b7151b074c6f2cf Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 16:19:12 +0900 Subject: [PATCH 052/205] =?UTF-8?q?feat=20:=20getSearchedMusics=20data=20l?= =?UTF-8?q?ayer=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ohdodok/catchytape/core/data/api/MusicApi.kt | 7 +++++++ .../catchytape/core/data/repository/MusicRepositoryImpl.kt | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt index 9384533..e0bbb3e 100644 --- a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt @@ -6,6 +6,7 @@ import com.ohdodok.catchytape.core.data.model.MusicResponse import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.Query interface MusicApi { @@ -22,4 +23,10 @@ interface MusicApi { @GET("musics/my-uploads") suspend fun getMyUploads(): List + + + @GET("musics/search") + suspend fun getSearchedMusics( + @Query("keyword") keyword: String + ): List } \ No newline at end of file diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/MusicRepositoryImpl.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/MusicRepositoryImpl.kt index bc2394a..96d131a 100644 --- a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/MusicRepositoryImpl.kt +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/repository/MusicRepositoryImpl.kt @@ -47,4 +47,9 @@ class MusicRepositoryImpl @Inject constructor( val myMusics = musicApi.getMyUploads() emit(myMusics.toDomains()) } + + override fun getSearchedMusics(keyword: String): Flow> = flow { + val searchedMusics = musicApi.getSearchedMusics(keyword) + emit(searchedMusics.toDomains()) + } } From a57a280cd6e3a308a8e8c2a0203a4ea9747ccd10 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 16:19:40 +0900 Subject: [PATCH 053/205] =?UTF-8?q?feat=20:=20fragment=5Fsearch=20UI=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/layout/fragment_search.xml | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/android/feature/search/src/main/res/layout/fragment_search.xml b/android/feature/search/src/main/res/layout/fragment_search.xml index feafe15..1170ec1 100644 --- a/android/feature/search/src/main/res/layout/fragment_search.xml +++ b/android/feature/search/src/main/res/layout/fragment_search.xml @@ -1,6 +1,7 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> @@ -14,6 +15,7 @@ android:layout_height="match_parent"> + + + + + + \ No newline at end of file From 9df05c160a7a707289896440d7b7423bbeaa8d09 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 16:20:43 +0900 Subject: [PATCH 054/205] =?UTF-8?q?feat=20:=20Repository=EC=97=90=20getSea?= =?UTF-8?q?rchedMusics=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20Fragment?= =?UTF-8?q?=EC=97=90=20observeEvents=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/repository/MusicRepository.kt | 1 + .../catchytape/feature/search/SearchFragment.kt | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/MusicRepository.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/MusicRepository.kt index 2168d01..349f0d0 100644 --- a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/MusicRepository.kt +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/repository/MusicRepository.kt @@ -13,4 +13,5 @@ interface MusicRepository { fun getMyMusics(): Flow> + fun getSearchedMusics(keyword: String): Flow> } \ No newline at end of file diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt index 33bd928..2c3d45a 100644 --- a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels import com.ohdodok.catchytape.core.ui.BaseFragment +import com.ohdodok.catchytape.core.ui.toMessageId import com.ohdodok.catchytape.feature.search.databinding.FragmentSearchBinding import dagger.hilt.android.AndroidEntryPoint @@ -15,5 +16,19 @@ class SearchFragment : BaseFragment(R.layout.fragment_sea override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.viewModel = viewModel + + observeEvents() + } + + private fun observeEvents() { + repeatOnStarted { + viewModel.events.collect { event -> + when (event) { + is SearchEvent.ShowMessage -> { + showMessage(event.error.toMessageId()) + } + } + } + } } } \ No newline at end of file From d093bb26849d4722e9c227f4b85d5ce114132a46 Mon Sep 17 00:00:00 2001 From: youlalala Date: Tue, 5 Dec 2023 16:24:20 +0900 Subject: [PATCH 055/205] =?UTF-8?q?feat=20:=20fitsSystemWindows=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/ui/src/main/res/values/themes.xml | 6 +++- .../src/main/res/layout/fragment_home.xml | 1 + .../main/res/layout/fragment_my_musics.xml | 3 +- .../src/main/res/layout/fragment_my_page.xml | 3 +- .../src/main/res/layout/fragment_player.xml | 3 +- .../res/layout/fragment_playlist_detail.xml | 33 +++++++++++++------ .../main/res/layout/fragment_playlists.xml | 3 +- .../src/main/res/layout/fragment_upload.xml | 3 +- 8 files changed, 39 insertions(+), 16 deletions(-) diff --git a/android/core/ui/src/main/res/values/themes.xml b/android/core/ui/src/main/res/values/themes.xml index b8c5b99..d345163 100644 --- a/android/core/ui/src/main/res/values/themes.xml +++ b/android/core/ui/src/main/res/values/themes.xml @@ -35,8 +35,12 @@ 12sp + + diff --git a/android/feature/home/src/main/res/layout/fragment_home.xml b/android/feature/home/src/main/res/layout/fragment_home.xml index de02019..990d2aa 100644 --- a/android/feature/home/src/main/res/layout/fragment_home.xml +++ b/android/feature/home/src/main/res/layout/fragment_home.xml @@ -17,6 +17,7 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + android:layout_height="match_parent" + android:fitsSystemWindows="true"> - @@ -50,11 +52,22 @@ style="@style/ToolBar" android:layout_width="match_parent" android:layout_height="wrap_content" - app:navigationIcon="@drawable/ic_arrow_back" - app:title="최근 재생 목록 (임시)" - tools:title="최근 재생 목록" /> + app:navigationIcon="@drawable/ic_arrow_back" /> - + + + + app:layout_constraintTop_toBottomOf="@id/tv_playlist_title" /> diff --git a/android/feature/playlist/src/main/res/layout/fragment_playlists.xml b/android/feature/playlist/src/main/res/layout/fragment_playlists.xml index 1df2ffd..1d53404 100644 --- a/android/feature/playlist/src/main/res/layout/fragment_playlists.xml +++ b/android/feature/playlist/src/main/res/layout/fragment_playlists.xml @@ -13,7 +13,8 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + android:layout_height="match_parent" + android:fitsSystemWindows="true"> Date: Tue, 5 Dec 2023 16:33:14 +0900 Subject: [PATCH 056/205] =?UTF-8?q?feat=20:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20dimens=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/core/ui/src/main/res/values/dimens.xml | 1 - .../ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/android/core/ui/src/main/res/values/dimens.xml b/android/core/ui/src/main/res/values/dimens.xml index ebf7d2b..65a0fd7 100644 --- a/android/core/ui/src/main/res/values/dimens.xml +++ b/android/core/ui/src/main/res/values/dimens.xml @@ -17,5 +17,4 @@ 4dp 50dp - 24dp \ No newline at end of file diff --git a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt index c053a66..953b1c3 100644 --- a/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt +++ b/android/feature/playlist/src/main/java/com/ohdodok/catchytape/feature/playlist/PlaylistsViewModel.kt @@ -77,7 +77,6 @@ class PlaylistViewModel @Inject constructor( } } - sealed interface PlaylistsEvent { data class NavigateToPlaylistDetail(val playlistId: Int) : PlaylistsEvent From 5531373dfabe0ed58f30d63e5e9ee28c5d883688 Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 17:17:18 +0900 Subject: [PATCH 057/205] =?UTF-8?q?feat=20:=20auth.controller=20=EB=A1=9C?= =?UTF-8?q?=EA=B9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * auth.controller 에서 요청 로깅 추가 --- server/src/auth/auth.controller.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts index 89731bc..8ee419c 100644 --- a/server/src/auth/auth.controller.ts +++ b/server/src/auth/auth.controller.ts @@ -31,6 +31,7 @@ export class AuthController { async login( @Body('idToken') googleIdToken: string, ): Promise<{ accessToken: string }> { + this.logger.log(`POST /users/login - idToken=${googleIdToken}`); const email: string = await this.authService.getGoogleEmail(googleIdToken); return await this.authService.login(email); } @@ -41,6 +42,7 @@ export class AuthController { async signup( @Body() userCreateDto: UserCreateDto, ): Promise<{ accessToken: string }> { + this.logger.log(`POST /users/signup - body=${userCreateDto}`); return this.authService.signup(userCreateDto); } @@ -49,7 +51,9 @@ export class AuthController { @HttpCode(HTTP_STATUS_CODE.SUCCESS) verifyToken(@Req() req): { userId: string } { const user: User = req.user; - this.logger.log(`GET /users/verify - ${user.nickname}: verified`); + this.logger.log( + `GET /users/verify - nickname=${user.nickname} : response - userId=${user.user_id}`, + ); return { userId: user.user_id }; } @@ -58,6 +62,7 @@ export class AuthController { @HttpCode(HTTP_STATUS_CODE.SUCCESS) async deleteUser(@Req() req): Promise<{ userId: string }> { const user: User = req.user; + this.logger.log(`DELETE /users - nickname=${user.nickname}`); return await this.authService.deleteUser(user); } } From a474a884059bc05ffc9d8b47c66227ae1b3f9efd Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 17:46:47 +0900 Subject: [PATCH 058/205] =?UTF-8?q?feat=20:=20auth.service=20=EB=A1=9C?= =?UTF-8?q?=EA=B9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * auth service 에서 로깅 추가 --- server/src/auth/auth.service.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/src/auth/auth.service.ts b/server/src/auth/auth.service.ts index 596f7de..b11e5b5 100644 --- a/server/src/auth/auth.service.ts +++ b/server/src/auth/auth.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable, LoggerService } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { InjectRepository } from '@nestjs/typeorm'; import { CatchyException } from 'src/config/catchyException'; @@ -10,6 +10,7 @@ import { HTTP_STATUS_CODE } from 'src/httpStatusCode.enum'; import { PlaylistService } from 'src/playlist/playlist.service'; import { Repository } from 'typeorm'; import { v4 as uuid } from 'uuid'; +import { Logger } from 'winston'; @Injectable() export class AuthService { @@ -17,6 +18,7 @@ export class AuthService { @InjectRepository(User) private userRepository: Repository, private jwtService: JwtService, private readonly playlistService: PlaylistService, + @Inject(Logger) private readonly logger: LoggerService, ) {} async login(email: string): Promise<{ accessToken: string }> { @@ -30,6 +32,7 @@ export class AuthService { return { accessToken }; } else { + this.logger.error(`auth.service - login : NOT_EXIST_USER`); throw new CatchyException( 'NOT_EXIST_USER', HTTP_STATUS_CODE['WRONG_TOKEN'], @@ -43,6 +46,7 @@ export class AuthService { const email: string = await this.getGoogleEmail(idToken); if (await this.isExistEmail(email)) { + this.logger.error(`auth.service - signup : ALREADY_EXIST_EMAIL`); throw new CatchyException( 'ALREADY_EXIST_EMAIL', HTTP_STATUS_CODE.BAD_REQUEST, @@ -64,6 +68,7 @@ export class AuthService { }); return this.login(email); } + this.logger.error(`auth.service - signup : WRONG_TOKEN`); throw new CatchyException( 'WRONG_TOKEN', HTTP_STATUS_CODE.WRONG_TOKEN, @@ -79,6 +84,7 @@ export class AuthService { }).then((res) => res.json()); if (!userInfo.email) { + this.logger.log(`auth.service - getGoogleEmail : EXPIRED_TOKEN`); throw new CatchyException( 'EXPIRED_TOKEN', HTTP_STATUS_CODE.WRONG_TOKEN, From e3019f58b52d0dbbb3921a5b4b07b3370a4b203f Mon Sep 17 00:00:00 2001 From: hyungun Date: Tue, 5 Dec 2023 18:15:48 +0900 Subject: [PATCH 059/205] =?UTF-8?q?feat=20:=20jwt.strategy=20=EB=A1=9C?= =?UTF-8?q?=EA=B9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 유저가 없을 때 로그 추가 --- server/src/auth/jwt.strategy.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/auth/jwt.strategy.ts b/server/src/auth/jwt.strategy.ts index ff3191c..f7766cf 100644 --- a/server/src/auth/jwt.strategy.ts +++ b/server/src/auth/jwt.strategy.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable, LoggerService } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { PassportStrategy } from '@nestjs/passport'; import { InjectRepository } from '@nestjs/typeorm'; @@ -8,12 +8,14 @@ import { ERROR_CODE } from 'src/config/errorCode.enum'; import { User } from 'src/entity/user.entity'; import { HTTP_STATUS_CODE } from 'src/httpStatusCode.enum'; import { Repository } from 'typeorm'; +import { Logger } from 'winston'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor( @InjectRepository(User) private userRepository: Repository, private configService: ConfigService, + @Inject(Logger) private readonly logger: LoggerService, ) { super({ secretOrKey: configService.get('JWT_SECRET_KEY'), @@ -29,6 +31,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) { }); if (!user || !user_id) { + this.logger.error(`request user_id=${user_id} : NOT_EXIST_USER`); throw new CatchyException( 'NOT_EXIST_USER', HTTP_STATUS_CODE['WRONG_TOKEN'], From 8725b09e87f20664b9ed4540052e9b90d1e823d7 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 18:19:25 +0900 Subject: [PATCH 060/205] =?UTF-8?q?feat=20:=20fetchSearchedMusics=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/search/SearchViewModel.kt | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt index 204b250..49ec61b 100644 --- a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchViewModel.kt @@ -1,26 +1,88 @@ package com.ohdodok.catchytape.feature.search import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +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 dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.plus import javax.inject.Inject data class SearchUiState( val keyword: String = "", ) +data class SearchedMusics( + val maxThreeMusics: List = emptyList(), + val totalMusics: List = emptyList() +) + @HiltViewModel class SearchViewModel @Inject constructor( - + private val musicRepository: MusicRepository ) : ViewModel() { private val _uiState = MutableStateFlow(SearchUiState()) val uiState: StateFlow = _uiState.asStateFlow() + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + private val _searchedMusics = MutableStateFlow(SearchedMusics()) + val searchedMusics: StateFlow = _searchedMusics.asStateFlow() + + + private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> + val errorType = + if (throwable is CtException) throwable.ctError + else CtErrorType.UN_KNOWN + + viewModelScope.launch { _events.emit(SearchEvent.ShowMessage(errorType)) } + } + + private val viewModelScopeWithExceptionHandler = viewModelScope + exceptionHandler + + init { + observeUiState() + } + fun updateKeyword(newKeyword: String) { _uiState.update { it.copy(keyword = newKeyword) } } + + private fun observeUiState() { + _uiState.debounce(300).onEach { uiState -> + if (uiState.keyword.isNotBlank()) { + fetchSearchedMusics(uiState.keyword) + } + }.launchIn(viewModelScopeWithExceptionHandler) + } + + private fun fetchSearchedMusics(keyword: String) { + musicRepository.getSearchedMusics(keyword).onEach { musics -> + _searchedMusics.update { + it.copy(maxThreeMusics = musics.take(3), totalMusics = musics) + } + }.launchIn(viewModelScopeWithExceptionHandler) + } + +} + + +sealed interface SearchEvent { + data class ShowMessage(val error: CtErrorType) : SearchEvent } \ No newline at end of file From f3f3c1d9f736f01d4ff5987ed0e33fd91f9f461d Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 18:19:43 +0900 Subject: [PATCH 061/205] =?UTF-8?q?feat=20:=20Fragment=EC=97=90=20setupRec?= =?UTF-8?q?yclerView=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ohdodok/catchytape/feature/search/SearchFragment.kt | 7 +++++++ .../feature/search/src/main/res/layout/fragment_search.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt index 2c3d45a..d321ab7 100644 --- a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt @@ -4,6 +4,8 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels import com.ohdodok.catchytape.core.ui.BaseFragment +import com.ohdodok.catchytape.core.ui.MusicAdapter +import com.ohdodok.catchytape.core.ui.Orientation import com.ohdodok.catchytape.core.ui.toMessageId import com.ohdodok.catchytape.feature.search.databinding.FragmentSearchBinding import dagger.hilt.android.AndroidEntryPoint @@ -18,6 +20,11 @@ class SearchFragment : BaseFragment(R.layout.fragment_sea binding.viewModel = viewModel observeEvents() + setupRecyclerView() + } + + private fun setupRecyclerView() { + binding.rvSearch.adapter = MusicAdapter(Orientation.VERTICAL) } private fun observeEvents() { diff --git a/android/feature/search/src/main/res/layout/fragment_search.xml b/android/feature/search/src/main/res/layout/fragment_search.xml index 1170ec1..376652e 100644 --- a/android/feature/search/src/main/res/layout/fragment_search.xml +++ b/android/feature/search/src/main/res/layout/fragment_search.xml @@ -64,7 +64,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/btn_more" - app:list="@{viewModel.uiState.searchedMusics}" + app:list="@{viewModel.searchedMusics.maxThreeMusics}" tools:itemCount="3" tools:listitem="@layout/item_music_vertical" /> From 73e5030fd601e312e6c4c7e73287921558598c91 Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 18:20:12 +0900 Subject: [PATCH 062/205] =?UTF-8?q?feat=20:=20music=20search=20api?= =?UTF-8?q?=EC=97=90=EC=84=9C=20genre=EB=A5=BC=20=EC=A3=BC=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EC=95=84=EC=84=9C,=20=EA=B3=B5=EB=B0=B1=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B8=B0=EB=B3=B8=EA=B0=92=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ohdodok/catchytape/core/data/model/MusicResponse.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicResponse.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicResponse.kt index 3a246bd..c1d2a72 100644 --- a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicResponse.kt +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicResponse.kt @@ -12,7 +12,7 @@ data class MusicResponse ( val cover: String, @SerialName("music_file") val musicFile : String, - val genre: String, + val genre: String = "", val user: NicknameResponse ) { fun toDomain(): Music { From 07da0f09dca69c69e022ee804445d7483335b4df Mon Sep 17 00:00:00 2001 From: 2taezeat Date: Tue, 5 Dec 2023 18:57:40 +0900 Subject: [PATCH 063/205] =?UTF-8?q?feat=20:=20=EB=8D=94=EB=B3=B4=EA=B8=B0?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/feature/search/SearchFragment.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt index d321ab7..4b6c2a6 100644 --- a/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt +++ b/android/feature/search/src/main/java/com/ohdodok/catchytape/feature/search/SearchFragment.kt @@ -3,13 +3,16 @@ package com.ohdodok.catchytape.feature.search import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels +import com.ohdodok.catchytape.core.domain.model.Music import com.ohdodok.catchytape.core.ui.BaseFragment import com.ohdodok.catchytape.core.ui.MusicAdapter import com.ohdodok.catchytape.core.ui.Orientation +import com.ohdodok.catchytape.core.ui.bindItems import com.ohdodok.catchytape.core.ui.toMessageId import com.ohdodok.catchytape.feature.search.databinding.FragmentSearchBinding import dagger.hilt.android.AndroidEntryPoint + @AndroidEntryPoint class SearchFragment : BaseFragment(R.layout.fragment_search) { @@ -20,6 +23,7 @@ class SearchFragment : BaseFragment(R.layout.fragment_sea binding.viewModel = viewModel observeEvents() + setupMoreButton() setupRecyclerView() } @@ -38,4 +42,11 @@ class SearchFragment : BaseFragment(R.layout.fragment_sea } } } + + private fun setupMoreButton() { + binding.btnMore.setOnClickListener { + binding.btnMore.visibility = View.INVISIBLE + binding.rvSearch.bindItems(viewModel.searchedMusics.value.totalMusics) + } + } } \ No newline at end of file From 268f29b5e340e3cda77da2c3b7b83506bc061d7c Mon Sep 17 00:00:00 2001 From: algosketch Date: Tue, 5 Dec 2023 21:22:45 +0900 Subject: [PATCH 064/205] =?UTF-8?q?fix=20:=20BottomNavigationView=20?= =?UTF-8?q?=EC=83=89=EA=B9=94=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/res/layout/activity_main.xml | 2 ++ .../src/main/res/color/navigation_view_item_icon_tint.xml | 8 ++++++++ android/core/ui/src/main/res/values-night/themes.xml | 2 ++ android/core/ui/src/main/res/values/themes.xml | 2 ++ 4 files changed, 14 insertions(+) create mode 100644 android/core/ui/src/main/res/color/navigation_view_item_icon_tint.xml diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml index 0439fe4..e9d7cbd 100644 --- a/android/app/src/main/res/layout/activity_main.xml +++ b/android/app/src/main/res/layout/activity_main.xml @@ -50,6 +50,8 @@ android:id="@+id/bottom_nav" android:layout_width="0dp" android:layout_height="wrap_content" + android:background="@color/surface_bright" + app:itemIconTint="@color/navigation_view_item_icon_tint" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/android/core/ui/src/main/res/color/navigation_view_item_icon_tint.xml b/android/core/ui/src/main/res/color/navigation_view_item_icon_tint.xml new file mode 100644 index 0000000..d4f0de0 --- /dev/null +++ b/android/core/ui/src/main/res/color/navigation_view_item_icon_tint.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/android/core/ui/src/main/res/values-night/themes.xml b/android/core/ui/src/main/res/values-night/themes.xml index 1d3cb6b..c90a95c 100644 --- a/android/core/ui/src/main/res/values-night/themes.xml +++ b/android/core/ui/src/main/res/values-night/themes.xml @@ -6,6 +6,8 @@ false @color/surface @color/on_surface + + @color/primary_container