Skip to content

Commit

Permalink
[Nunu/#33] feat: 7주차 구현
Browse files Browse the repository at this point in the history
* [nunu/#33] 7주차 구현1

- homeFragment에 recycler View 구현
- Song Activity에 DB 연결 및 타이머 스레드 수정(이전/다음 곡 재생에 따른 타이머와 재생/정지에 따른 타이머)
- Album, Song Dao와 Database 구현

* [nunu/#33] feat: 7주차 구현2

- 좋아요 기능 커스텀 toast 구현

* [nunu/#33] feat: 7주차 구현3

- 좋아요 한 곡 데이터베이스 및 보관함 업데이트

* [nunu/#33] feat: 7주차 구현4

- Main<-> Song activity 간 연동을 위한 SharedPreferenceHelper 구현
- 근데 연동 안됨 ㅠㅠ...

* [nunu/#33] 7주차 구현

- 앨범 fragment 바인딩
- foreground 설정

* [nunu/#33] 7주차 구현6

- sharedPreference 통해서 SongActivity-> MainActivity 간 데이터 공유 성공
- MainActivity -> SongActivity 간 데이터 공유 필요

* [nunu/#33] 7주차 구현7

- MainActivity -> SongActivity 간 songId 데이터 공유( 근데, id가 서로 다름.. 그래서 -1 해줘서 보내줌.)

* [nunu/#33] 7주차 구현8

- album 연결
- 모든 좋아요된 음악 전체 해제 구현( bottomSheetDialog 구현)
  • Loading branch information
Ssamssamukja authored Jun 2, 2024
1 parent a4cb646 commit 95d668e
Show file tree
Hide file tree
Showing 38 changed files with 1,260 additions and 157 deletions.
4 changes: 4 additions & 0 deletions UMC_6th/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("kotlin-kapt")
}

android {
Expand Down Expand Up @@ -75,4 +76,7 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
implementation("androidx.room:room-ktx:2.6.1")
implementation("androidx.room:room-runtime:2.6.1")
kapt("androidx.room:room-compiler:2.6.1")
}
23 changes: 17 additions & 6 deletions UMC_6th/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -12,24 +17,30 @@
android:supportsRtl="true"
android:theme="@style/Theme.UMC_6th"
tools:targetApi="31">
<activity android:name=".SplashActivity"
<service
android:name=".ForegroundService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="mediaPlayback"></service>

<activity
android:name=".SplashActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:exported="true">
</activity>
android:exported="true"></activity>
<activity
android:name=".SongActivity"
android:exported="true"
android:hardwareAccelerated="true"
android:label="@string/title_activity_song"
android:theme="@style/Theme.UMC_6th"
android:hardwareAccelerated="true">
</activity>
android:theme="@style/Theme.UMC_6th"></activity>
</application>

</manifest>
13 changes: 9 additions & 4 deletions UMC_6th/app/src/main/java/com/example/umc_6th/Album.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.example.umc_6th


import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "AlbumTable")
data class Album(
var title : String? = "",
var artist : String? = "",
var coverImage : Int? = null,
var songs: ArrayList<Song>? = null
@PrimaryKey(autoGenerate = false) var id: Int = 0, // album의 pk는 임의로 지정해주기 위해 autogenerate 안씁니다.
var title: String? = "",
var artist: String? = "",
var coverImg: Int? = null
)
21 changes: 21 additions & 0 deletions UMC_6th/app/src/main/java/com/example/umc_6th/AlbumDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.umc_6th

import androidx.room.*

@Dao
interface AlbumDao {
@Insert
fun insert(album: Album)

@Update
fun update(album: Album)

@Delete
fun delete(album: Album)

@Query("SELECT * FROM AlbumTable") // 테이블의 모든 값을 가져와라
fun getAlbums(): List<Album>

@Query("SELECT * FROM AlbumTable WHERE id = :id")
fun getAlbum(id: Int): Album
}
25 changes: 24 additions & 1 deletion UMC_6th/app/src/main/java/com/example/umc_6th/AlbumFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.example.umc_6th

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand All @@ -13,18 +14,26 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
import com.example.umc_6th.adapter.AlbumPagerAdapter
import com.example.umc_6th.databinding.FragmentAlbumBinding
import com.google.android.material.tabs.TabLayoutMediator
import com.google.gson.Gson

class AlbumFragment: Fragment(R.layout.fragment_album) {
// 여기에 Fragment의 구현 내용을 작성합니다.

private var _binding: FragmentAlbumBinding? = null
private val binding get() = _binding!!
private var gson: Gson = Gson()
private val information = arrayListOf("수록곡", "상세정보", "영상")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
): View {
_binding = FragmentAlbumBinding.inflate(inflater, container, false)

//앨범 데이터
val albumToJson = arguments?.getString("album")
val album = gson.fromJson(albumToJson, Album::class.java)
setInit(album)
return binding.root
}

Expand All @@ -48,6 +57,20 @@ class AlbumFragment: Fragment(R.layout.fragment_album) {
else -> null
}
}.attach()

arguments?.getString("album")?.let { json ->
val gson = Gson()
val album = gson.fromJson(json, Album::class.java)
Log.d("AlbumFragment", "Album parsed: ${album.title}, ${album.artist}, ${album.coverImg}")
setInit(album)
}
}

private fun setInit(album : Album) {
Log.d("AlbumFragment", "Album parsed: ${album.title}, ${album.artist}, ${album.coverImg}")
binding.imgAlbumAlbumCov.setImageResource(album.coverImg!!)
binding.txAlbumAlbumTitle.text = album.title
binding.txAlbumAlbumArtist.text = album.artist
}


Expand Down
6 changes: 6 additions & 0 deletions UMC_6th/app/src/main/java/com/example/umc_6th/Constant.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.example.umc_6th

object Constant {
const val CHANNEL_ID = "ch123"
const val MUSIC_NOTIFICATION_ID = 123
}
62 changes: 62 additions & 0 deletions UMC_6th/app/src/main/java/com/example/umc_6th/ForegroundService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.example.umc_6th

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi

class ForegroundService : Service() {

override fun onBind(intent: Intent): IBinder? {
return null
}

override fun onCreate() {
super.onCreate()
createNotificationChannel()
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 버전 확인
showNotification()
}

return START_STICKY
}
@RequiresApi(Build.VERSION_CODES.O)
private fun showNotification() {
val notificationIntent = Intent(this, SongActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE
)
val notification = Notification
.Builder(this, Constant.CHANNEL_ID)
.setContentText("현재 음악이 재생 중입니다.")
.setSmallIcon(R.drawable.ic_flo_logo)
.setContentIntent(pendingIntent)
.build()

startForeground(Constant.MUSIC_NOTIFICATION_ID, notification)
}

private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
Constant.CHANNEL_ID, "Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)

val manager = getSystemService(
NotificationManager::class.java
)

manager.createNotificationChannel(serviceChannel)
}
}
}
109 changes: 99 additions & 10 deletions UMC_6th/app/src/main/java/com/example/umc_6th/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ import com.example.umc_6th.adapter.ViewPagerAdapter
import com.example.umc_6th.databinding.FragmentHomeBinding
import me.relex.circleindicator.CircleIndicator3
import android.os.Looper
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.umc_6th.adapter.AlbumRecyclerAdapter
import com.google.gson.Gson


class HomeFragment : Fragment() {
Expand All @@ -26,6 +30,10 @@ class HomeFragment : Fragment() {
private val binding get() = _binding!!
private lateinit var handler: Handler
private lateinit var runnable: Runnable
private var albumDatas = ArrayList<Album>()
private lateinit var songDB: SongDatabase


override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -34,18 +42,56 @@ class HomeFragment : Fragment() {
viewModel = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
_binding = FragmentHomeBinding.inflate(inflater, container, false)

/*
albumDatas.apply {
add(Album(0, "Love wins all", "아이유 (IU)", R.drawable.img_album_lovewinsall))
add(Album(1, "해야 (HEYA)", "IVE", R.drawable.img_album_heya))
add(Album(2, "Supernova", "에스파 (aespa)", R.drawable.img_album_supernova))
add(Album(3, "Lilac", "아이유 (IU)", R.drawable.img_album_exp2))
add(Album(4, "Drama", "에스파 (aespa)", R.drawable.img_album_drama))
add(Album(5, "Weekend", "태연 (Tae Yeon)", R.drawable.img_album_exp6))
}
*/

inputDummyAlbums()
songDB = SongDatabase.getInstance(requireContext())!!
albumDatas.addAll(songDB.albumDao().getAlbums())
Log.d("albumlist", albumDatas.toString())

val albumRecyclerAdapter = AlbumRecyclerAdapter(albumDatas)
binding.homeTodayMusicAlbum.adapter = albumRecyclerAdapter
binding.homeTodayMusicAlbum.layoutManager = LinearLayoutManager(requireActivity(), LinearLayoutManager.HORIZONTAL, false)

albumRecyclerAdapter.setItemPlayClickListener(object : AlbumRecyclerAdapter.OnItemPlayClickListener{
override fun onItemPlayClick(album: Album) {
album.title?.let { album.artist?.let { it1 -> viewModel.selectItem(it, it1) } }
}
})
albumRecyclerAdapter.setItemClickListener(object : AlbumRecyclerAdapter.OnItemClickListener {
override fun onItemClick(album : Album) {
changeToAlbumFragment(album)
}
})
return binding.root

}

private fun changeToAlbumFragment(album: Album) {
(context as MainActivity).supportFragmentManager.beginTransaction()
.replace(R.id.main_container, AlbumFragment().apply {
arguments = Bundle().apply {
val gson = Gson()
val albumToJson = gson.toJson(album)
putString("album", albumToJson)
}
})
.commitAllowingStateLoss()
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.imgSecondAlbum1.setOnClickListener {
val transaction = requireActivity().supportFragmentManager.beginTransaction()
transaction.replace(R.id.main_container, AlbumFragment())
transaction.addToBackStack(null) // 백 스택에 추가
transaction.commit()
}

val adapter = ViewPagerAdapter(this)
binding.homeViewPager.adapter = adapter

Expand All @@ -68,15 +114,16 @@ class HomeFragment : Fragment() {
}
startAutoSlide()

binding.imgSecondAlbumPlay1.setOnClickListener(){
viewModel.selectedTitle.value = binding.txSecondTitle1.getText().toString()
viewModel.selectedArtist.value = binding.txSecondArtist1.getText().toString()
}

}

class SharedViewModel : ViewModel() {
val selectedTitle = MutableLiveData<String>()
val selectedArtist = MutableLiveData<String>()
fun selectItem(title: String, artist: String) {
selectedTitle.value = title
selectedArtist.value = artist
}
}


Expand All @@ -95,6 +142,48 @@ class HomeFragment : Fragment() {
}


//ROOM_DB
private fun inputDummyAlbums() {
val songDB = SongDatabase.getInstance(requireActivity())!!
val albums = songDB.albumDao().getAlbums()

if (albums.isNotEmpty()) return
songDB.albumDao().insert(
Album(
0,
"IU 5th Album 'LILAC'", "아이유 (IU)", R.drawable.img_album_exp2
)
)

songDB.albumDao().insert(
Album(
1,
"Butter", "방탄소년단 (BTS)", R.drawable.img_album_exp
)
)

songDB.albumDao().insert(
Album(
2,
"Next Level", "에스파 (AESPA)", R.drawable.img_album_exp3
)
)

songDB.albumDao().insert(
Album(
3,
"MAP OF THE SOUL : PERSONA", "방탄소년단 (BTS)", R.drawable.img_album_exp4
)
)

songDB.albumDao().insert(
Album(
4,
"GREAT!", "모모랜드 (MOMOLAND)", R.drawable.img_album_exp5
)
)

}

class FragmentHomeBanner : Fragment(R.layout.fragment_home_banner1) {
// 필요한 경우 여기에 로직 추가
Expand Down
Loading

0 comments on commit 95d668e

Please sign in to comment.