diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6479977..9f8b8ed 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -7,11 +7,12 @@ plugins { id("dagger.hilt.android.plugin") id("androidx.navigation.safeargs.kotlin") id("org.jetbrains.kotlin.kapt") + id("kotlin-kapt") } android { namespace = "umc.study.umc_7th" - compileSdk = 34 + compileSdk = 35 defaultConfig { applicationId = "umc.study.umc_7th" @@ -48,7 +49,7 @@ android { compose = true } composeOptions { - kotlinCompilerExtensionVersion = "1.5.1" + kotlinCompilerExtensionVersion = "1.5.13" } packaging { resources { @@ -69,6 +70,7 @@ dependencies { implementation(libs.androidx.storage) implementation(libs.androidx.lifecycle.runtime.compose.android) implementation(libs.common) + implementation(libs.firebase.firestore.ktx) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) @@ -86,6 +88,8 @@ dependencies { implementation(libs.androidx.navigation.fragment.ktx) implementation(libs.androidx.navigation.ui.ktx) + implementation ("me.relex:circleindicator:2.1.6") + implementation ("androidx.viewpager2:viewpager2:1.0.0") // Hilt Dependency Injection implementation("com.google.dagger:hilt-android:2.49") kapt("com.google.dagger:hilt-compiler:2.49") @@ -99,6 +103,8 @@ dependencies { implementation("com.squareup.retrofit2:converter-gson:2.9.0") implementation("com.squareup.retrofit2:converter-scalars:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + // https://github.com/square/okhttp implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.2") @@ -132,4 +138,22 @@ dependencies { annotationProcessor("androidx.room:room-compiler:2.6.1") kapt("androidx.room:room-compiler:2.6.1") implementation("androidx.room:room-ktx:2.6.1") + + implementation("androidx.room:room-migration:2.6.0") + implementation("androidx.room:room-runtime:2.6.0") + kapt("androidx.room:room-compiler:2.6.0") + +// Retrofit + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2") + implementation("com.squareup.retrofit2:adapter-rxjava2:2.9.0") + +// okHttp + implementation("com.squareup.okhttp3:okhttp:4.9.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.9.0") + +// Glide + implementation("com.github.bumptech.glide:glide:4.12.0") + annotationProcessor("com.github.bumptech.glide:compiler:4.12.0") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0318547..31292ab 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ \ + xmlns:tools="http://schemas.android.com/tools"> @@ -19,10 +19,9 @@ android:name=".MainActivity" android:exported="true" android:label="@string/app_name" - android:theme="@style/Theme.Umc_7th"> + android:theme="@style/SplashTheme"> - @@ -31,4 +30,6 @@ android:exported="true"/> + + \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/Album.kt b/app/src/main/java/umc/study/umc_7th/Album.kt new file mode 100644 index 0000000..d60cc90 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/Album.kt @@ -0,0 +1,13 @@ +package umc.study.umc_7th + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "AlbumTable") +data class Album( + // album의 pk는 임의로 지정해 줄 것이므로, autoGenerate 하지 않음 + @PrimaryKey(autoGenerate = false) var id: Int = 0, + var title: String? = "", + var singer: String? = "", + var coverImage: Int? = null +) diff --git a/app/src/main/java/umc/study/umc_7th/AlbumDao.kt b/app/src/main/java/umc/study/umc_7th/AlbumDao.kt new file mode 100644 index 0000000..8cbaafa --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/AlbumDao.kt @@ -0,0 +1,37 @@ +package umc.study.umc_7th + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update + +@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 + + @Query("SELECT * FROM AlbumTable WHERE id = :id") + fun getAlbum(id: Int): Album + + @Insert + fun likeAlbum(like : Like) + + @Query("select id from LikeTable where userId =:userId and albumId = :albumId") + fun isLikedAlbum(userId : Int, albumId : Int) : Int? + + @Query("delete from LikeTable where userId =:userId and albumId = :albumId") + fun dislikedAlbum(userId : Int, albumId : Int) + + @Query("select at.* from LikeTable as lt left join AlbumTable as at on lt.albumId = at.id where lt.userId = :userId") + fun getLikedAlbums(userId : Int) : List +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/AlbumFragment.kt b/app/src/main/java/umc/study/umc_7th/AlbumFragment.kt index b0c3ca1..f4e93f0 100644 --- a/app/src/main/java/umc/study/umc_7th/AlbumFragment.kt +++ b/app/src/main/java/umc/study/umc_7th/AlbumFragment.kt @@ -1,17 +1,32 @@ +package umc.study.umc_7th + + import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import androidx.fragment.app.setFragmentResultListener +import com.google.android.material.tabs.TabLayoutMediator +import com.google.gson.Gson +import umc.study.umc_7th.AlbumRVAdapter import umc.study.umc_7th.HomeFragment +import umc.study.umc_7th.Like import umc.study.umc_7th.MainActivity import umc.study.umc_7th.R +import umc.study.umc_7th.SongDatabase import umc.study.umc_7th.databinding.FragmentAlbumBinding class AlbumFragment : Fragment() { lateinit var binding: FragmentAlbumBinding + private var gson: Gson = Gson() + + private var isLiked : Boolean = false + + private val information = arrayListOf("수록곡", "상세정보", "영상") override fun onCreateView( inflater: LayoutInflater, @@ -20,37 +35,93 @@ class AlbumFragment : Fragment() { ): View? { binding = FragmentAlbumBinding.inflate(inflater,container,false) + val albumToJson = arguments?.getString("album") + val album = gson.fromJson(albumToJson, Album::class.java) + isLiked = isLikedAlbum(album.id) + setInit(album) + setOnClickListener(album) + + setFragmentResultListener("TitleInfo") { requestKey, bundle -> + binding.albumMusicTitleTv.text = bundle.getString("title") + } + + setFragmentResultListener("SingerInfo") { requestKey, bundle -> + binding.albumSingerNameTv.text = bundle.getString("singer") + } + + // binding.albumMusicTitleTv.text = arguments?.getString("title") + // binding.albumSingerNameTv.text = arguments?.getString("singer") + binding.albumBackIv.setOnClickListener { (context as MainActivity).supportFragmentManager.beginTransaction() .replace(R.id.main_frm, HomeFragment()) .commitAllowingStateLoss() } - binding.songLalacLayout.setOnClickListener { - Toast.makeText(activity, "LILAC", Toast.LENGTH_SHORT).show() - } + val albumAdapter = AlbumVPAdapter(this) + binding.albumContentVp.adapter = albumAdapter - binding.songFluLayout.setOnClickListener { - Toast.makeText(activity,"FLU", Toast.LENGTH_SHORT).show() - } + TabLayoutMediator(binding.albumContentTb, binding.albumContentVp) { tab, position -> + tab.text = information[position] + }.attach() - binding.songCoinLayout.setOnClickListener { - Toast.makeText(activity,"Coin", Toast.LENGTH_SHORT).show() - } + return binding.root + } - binding.songSpringLayout.setOnClickListener { - Toast.makeText(activity,"봄 안녕 봄", Toast.LENGTH_SHORT).show() - } + private fun setInit(album : Album) { + binding.albumAlbumIv.setImageResource(album.coverImage!!) + binding.albumMusicTitleTv.text = album.title.toString() + binding.albumSingerNameTv.text = album.singer.toString() - binding.songCelebrityLayout.setOnClickListener { - Toast.makeText(activity,"Celebrity", Toast.LENGTH_SHORT).show() + if(isLiked) { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_on) } - binding.songSingLayout.setOnClickListener { - Toast.makeText(activity,"돌림노래 (Feat. DEAN)", Toast.LENGTH_SHORT).show() + else { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_off) } + } - return binding.root + private fun getJwt() : Int { + val spf = requireActivity().getSharedPreferences("auth", AppCompatActivity.MODE_PRIVATE) + return spf.getInt("jwt", 0) + } + + private fun likeAlbum(userId : Int, albumId : Int) { + val songDB = SongDatabase.getInstance(requireActivity())!! + val like = Like(userId, albumId) + + songDB.albumDao().likeAlbum(like) + } + + private fun isLikedAlbum(albumId : Int) : Boolean { + val songDB = SongDatabase.getInstance(requireActivity())!! + val userId = getJwt() + + val likeId : Int? = songDB.albumDao().isLikedAlbum(userId, albumId) + return likeId != null } + private fun disLikeAlbum(albumId : Int) { + val songDB = SongDatabase.getInstance(requireActivity())!! + val userId = getJwt() + + songDB.albumDao().dislikedAlbum(userId, albumId) + } + + private fun setOnClickListener(album : Album) { + val userId = getJwt() + binding.albumLikeIv.setOnClickListener { + if(isLiked) { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_off) + disLikeAlbum(album.id) + } + + else { + binding.albumLikeIv.setImageResource((R.drawable.ic_my_like_on)) + likeAlbum(userId, album.id) + } + } + + } } \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/AlbumRVAapter.kt b/app/src/main/java/umc/study/umc_7th/AlbumRVAapter.kt new file mode 100644 index 0000000..7f0d583 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/AlbumRVAapter.kt @@ -0,0 +1,52 @@ +package umc.study.umc_7th + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import umc.study.umc_7th.databinding.ItemAlbumBinding + +class AlbumRVAdapter(private val albumList: ArrayList) : RecyclerView.Adapter(){ + + // 뷰홀더를 생성해줘야 할 때 호출되는 함수 => 아이템 뷰 객체를 만들어서 뷰홀더에 던져줍니다. + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): AlbumRVAdapter.ViewHolder { + val binding: ItemAlbumBinding = ItemAlbumBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false) + + return ViewHolder(binding) + } + + // 뷰홀더에 데이터를 바인딩해줘야 할 때마다 호출되는 함수 => 엄청나게 많이 호출 + override fun onBindViewHolder(holder: AlbumRVAdapter.ViewHolder, position: Int) { + holder.bind(albumList[position]) + holder.itemView.setOnClickListener { + itemClickListener.onItemClick(albumList[position]) + } + + holder.binding.itemAlbumPlayImgIv.setOnClickListener { + itemClickListener.onPlayAlbum(albumList[position]) + } + } + + // 데이터 세트 크기를 알려주는 함수 => 리사이클러뷰가 마지막이 언제인지를 알게 된다. + override fun getItemCount(): Int = albumList.size + + // 뷰홀더 + inner class ViewHolder(val binding: ItemAlbumBinding): RecyclerView.ViewHolder(binding.root){ + + fun bind(album: Album){ + binding.itemAlbumTitleTv.text = album.title + binding.itemAlbumSingerTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImage!!) + } + } + + interface OnItemClickListener { + fun onItemClick(album : Album) + fun onPlayAlbum(album : Album) + } + + private lateinit var itemClickListener : OnItemClickListener + + fun setItemClickListener(onItemClickListener: OnItemClickListener) { + this.itemClickListener = onItemClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/AlbumVPAdpter.kt b/app/src/main/java/umc/study/umc_7th/AlbumVPAdpter.kt new file mode 100644 index 0000000..6b31037 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/AlbumVPAdpter.kt @@ -0,0 +1,16 @@ +package umc.study.umc_7th + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class AlbumVPAdapter(fragment : Fragment) : FragmentStateAdapter(fragment) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + return when(position) { + 0 -> SongFragment() + 1 -> DetailFragment() + else -> VideoFragment() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/ApiRepository.kt b/app/src/main/java/umc/study/umc_7th/ApiRepository.kt new file mode 100644 index 0000000..2bc16d0 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/ApiRepository.kt @@ -0,0 +1,7 @@ +package umc.study.umc_7th + +class ApiRepository { + companion object { + const val BASE_URL = "http://3.35.121.185/" + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/AuthApi.kt b/app/src/main/java/umc/study/umc_7th/AuthApi.kt new file mode 100644 index 0000000..397df80 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/AuthApi.kt @@ -0,0 +1,13 @@ +////package umc.study.umc_7th +// +//import retrofit2.Call +//import retrofit2.http.Body +//import retrofit2.http.POST +// +//interface AuthApi { +// @POST("/users") +// fun signUp(@Body user: User): Call +// +// @POST("/users/login") +// fun login(@Body user: User): Call +//} diff --git a/app/src/main/java/umc/study/umc_7th/AuthService.kt b/app/src/main/java/umc/study/umc_7th/AuthService.kt new file mode 100644 index 0000000..14e80f8 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/AuthService.kt @@ -0,0 +1,53 @@ +package umc.study.umc_7th + +import android.util.Log +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class AuthService { + private lateinit var signUpView: SignUpView + private lateinit var loginView: LoginView + + fun setSignUpView(signUpView: SignUpView) { + this.signUpView = signUpView + } + + fun setLoginView(loginView: LoginView) { + this.loginView = loginView + } + + fun signUp(user : User) { + RetrofitInstance.authApi.signUp(user).enqueue(object: Callback { + override fun onResponse(call: Call, response: Response) { + Log.d("SignUp-Success", response.toString()) + val response : BaseResponse = response.body()!! + when(response.code) { + 1000 -> signUpView.onSignUpSuccess() + else -> signUpView.onSignUpFailure(response.message) + } + } + override fun onFailure(call: Call, t: Throwable) { + Log.d("SignUp-Failure", t.message.toString()) + } + }) + Log.d("SignUpActivity", "All Finished") + } + + fun login(user : User) { + RetrofitInstance.authApi.login(user).enqueue(object: Callback { + override fun onResponse(call: Call, response: Response) { + Log.d("Login-Success", response.toString()) + val response : BaseResponse = response.body()!! + when(val code = response.code) { + 1000 -> loginView.onLoginSuccess(code, response.result!!) + else -> loginView.onLoginFailure(response.message) + } + } + override fun onFailure(call: Call, t: Throwable) { + Log.d("Login-Failure", t.message.toString()) + } + }) + Log.d("LoginActivity", "All Finished") + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/BannerFragment.kt b/app/src/main/java/umc/study/umc_7th/BannerFragment.kt new file mode 100644 index 0000000..41594e9 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/BannerFragment.kt @@ -0,0 +1,27 @@ +package umc.study.umc_7th + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import umc.study.umc_7th.databinding.FragmentBannerBinding + +class BannerFragment(val imgRes : Int) : Fragment() { + + lateinit var binding : FragmentBannerBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentBannerBinding.inflate(inflater, container, false) + binding.bannerImageIv.setImageResource(imgRes) + return binding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/BannerVPAdapter.kt b/app/src/main/java/umc/study/umc_7th/BannerVPAdapter.kt new file mode 100644 index 0000000..78e400f --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/BannerVPAdapter.kt @@ -0,0 +1,22 @@ +package umc.study.umc_7th + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class BannerVPAdapter(fragment : Fragment) : FragmentStateAdapter(fragment) { + + private val fragmentList : ArrayList = ArrayList() + + override fun getItemCount(): Int { + return fragmentList.size + } + + override fun createFragment(position: Int): Fragment { + return fragmentList[position] + } + + fun addFragment(fragment: Fragment) { + fragmentList.add(fragment) + notifyItemInserted(fragmentList.size-1) + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/BaseResponse.kt b/app/src/main/java/umc/study/umc_7th/BaseResponse.kt new file mode 100644 index 0000000..b2df535 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/BaseResponse.kt @@ -0,0 +1,15 @@ +package umc.study.umc_7th + +import com.google.gson.annotations.SerializedName + +data class BaseResponse( + @SerializedName("isSuccess") val isSuccess : Boolean, + @SerializedName("code") val code : Int, + @SerializedName("message") val message : String, + @SerializedName("result") val result : Result? +) + +data class Result ( + @SerializedName("userIdx") var userIdx : Int, + @SerializedName("jwt") var jwt : String +) diff --git a/app/src/main/java/umc/study/umc_7th/BottomSheetFragment.kt b/app/src/main/java/umc/study/umc_7th/BottomSheetFragment.kt new file mode 100644 index 0000000..0281491 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/BottomSheetFragment.kt @@ -0,0 +1,43 @@ +package umc.study.umc_7th + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import umc.study.umc_7th.databinding.FragmentBottomSheetBinding + +class BottomSheetFragment : BottomSheetDialogFragment() { + + lateinit var binding : FragmentBottomSheetBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentBottomSheetBinding.inflate(inflater, container, false) + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.bottomSheetIv1.setOnClickListener { + Toast.makeText(requireActivity(), "듣기 버튼 클릭", Toast.LENGTH_SHORT).show() + } + + binding.bottomSheetIv2.setOnClickListener { + Toast.makeText(requireActivity(), "재생목록 버튼 클릭", Toast.LENGTH_SHORT).show() + } + + binding.bottomSheetIv3.setOnClickListener { + Toast.makeText(requireActivity(), "내 리스트 버튼 클릭", Toast.LENGTH_SHORT).show() + } + + binding.bottomSheetIv4.setOnClickListener { + Toast.makeText(requireActivity(), "삭제 버튼 클릭", Toast.LENGTH_SHORT).show() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/CommunicationInterface.kt b/app/src/main/java/umc/study/umc_7th/CommunicationInterface.kt new file mode 100644 index 0000000..8d8d269 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/CommunicationInterface.kt @@ -0,0 +1,6 @@ +package umc.study.umc_7th + + +interface CommunicationInterface { + fun sendData(album: Album) +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/Constant.kt b/app/src/main/java/umc/study/umc_7th/Constant.kt new file mode 100644 index 0000000..622b567 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/Constant.kt @@ -0,0 +1,6 @@ +package umc.study.umc_7th + +object Constant { + const val CHANNEL_ID = "ch123" // 아무런 값이나 입력한다. + const val MUSIC_NOTIFICATION_ID = 123 // 아무런 값이나 입력한다. +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/CustomSnackbar.kt b/app/src/main/java/umc/study/umc_7th/CustomSnackbar.kt new file mode 100644 index 0000000..2849624 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/CustomSnackbar.kt @@ -0,0 +1,48 @@ +package umc.study.umc_7th + +import android.view.LayoutInflater +import android.view.View +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import com.google.android.material.snackbar.Snackbar +import umc.study.umc_7th.databinding.CustomSnackbarBinding + +class CustomSnackbar(view: View, private val message: String) { + + companion object { + + fun make(view: View, message: String) = CustomSnackbar(view, message) + } + + private val context = view.context + private val snackbar = Snackbar.make(view, "", 5000) + private val snackbarLayout = snackbar.view as Snackbar.SnackbarLayout + + private val inflater = LayoutInflater.from(context) + private val snackbarBinding: CustomSnackbarBinding = DataBindingUtil.inflate(inflater, R.layout.custom_snackbar, null, false) + + init { + initView() + initData() + } + + private fun initView() { + with(snackbarLayout) { + removeAllViews() + setPadding(0, 0, 0, 0) + setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)) + addView(snackbarBinding.root, 0) + } + } + + private fun initData() { + snackbarBinding.customSnackbarTv.text = message + snackbarBinding.customSnackbarBtn.setOnClickListener { + // OK 버튼을 클릭했을 때 실행할 동작을 정의할 수 있다. + } + } + + fun show() { + snackbar.show() + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/DetailFragment.kt b/app/src/main/java/umc/study/umc_7th/DetailFragment.kt new file mode 100644 index 0000000..dfba4ad --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/DetailFragment.kt @@ -0,0 +1,26 @@ +package umc.study.umc_7th + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import umc.study.umc_7th.databinding.FragmentDetailBinding + +class DetailFragment : Fragment() { + + lateinit var binding : FragmentDetailBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentDetailBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/ForegroundService.kt b/app/src/main/java/umc/study/umc_7th/ForegroundService.kt new file mode 100644 index 0000000..ac08d52 --- /dev/null +++ b/app/src/main/java/umc/study/umc_7th/ForegroundService.kt @@ -0,0 +1,63 @@ +package umc.study.umc_7th + +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.app_icon) + .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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/study/umc_7th/HomeFragment.kt b/app/src/main/java/umc/study/umc_7th/HomeFragment.kt index 2889fa0..da71022 100644 --- a/app/src/main/java/umc/study/umc_7th/HomeFragment.kt +++ b/app/src/main/java/umc/study/umc_7th/HomeFragment.kt @@ -2,16 +2,34 @@ package umc.study.umc_7th import AlbumFragment import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment +import androidx.fragment.app.setFragmentResult +import androidx.viewpager2.widget.ViewPager2 import umc.study.umc_7th.databinding.FragmentHomeBinding -class HomeFragment : Fragment() { +class HomeFragment : Fragment(), CommunicationInterface { lateinit var binding : FragmentHomeBinding + private var albumDatas = ArrayList() + private lateinit var songDB: SongDatabase + + private val timer = SongActivity.Timer() + private val handler = Handler(Looper.getMainLooper()) + + override fun sendData(album: Album) { // MainActivity의 UI를 업데이트하기 위해 사용하는 메서드 + if (activity is MainActivity) { + val activity = activity as MainActivity + activity.updateMainPlayerCl(album) + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } @@ -22,10 +40,174 @@ class HomeFragment : Fragment() { ): View? { binding = FragmentHomeBinding.inflate(inflater, container, false) - binding.homePannelAlbumImgIv.setOnClickListener { - (context as MainActivity).supportFragmentManager.beginTransaction().replace(R.id.main_frm, AlbumFragment()).commitAllowingStateLoss() +// binding.homeAlbumImgIv1.setOnClickListener { +// val bundle = Bundle() +// bundle.putString("title", binding.titleLilac.text.toString()) +// bundle.putString("singer", binding.singerIu.text.toString()) +// +// val albumFragment = AlbumFragment() +// albumFragment.arguments = bundle +// +// (context as MainActivity) +// .supportFragmentManager.beginTransaction() +// .replace(R.id.main_frm, albumFragment).commitAllowingStateLoss() +// } + + inputDummyAlbums() + + songDB = SongDatabase.getInstance(requireContext())!! + albumDatas.addAll(songDB.albumDao().getAlbums()) + Log.d("albumlist", albumDatas.toString()) + + val albumRVAdapter = AlbumRVAdapter(albumDatas) + binding.homeTodayMusicAlbumRv.adapter = albumRVAdapter + binding.homeTodayMusicAlbumRv.layoutManager = LinearLayoutManager(requireActivity(), LinearLayoutManager.HORIZONTAL, false) + + albumRVAdapter.setItemClickListener(object : AlbumRVAdapter.OnItemClickListener { + override fun onItemClick(album : Album) { + changeAlbumFragment(album) + } + + override fun onPlayAlbum(album: Album) { + sendData(album) + } + }) + + val bannerAdapter = BannerVPAdapter(this) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + + binding.homeBannerVp.adapter = bannerAdapter + binding.homeBannerVp.orientation = ViewPager2.ORIENTATION_HORIZONTAL + + binding.homeBannerIndicator.setViewPager(binding.homeBannerVp) + + autoSlide(bannerAdapter) + + val pannelAdpater = PannelVpAdapter(this) + pannelAdpater.addFragment(PannelFragment(R.drawable.img_first_album_default)) + pannelAdpater.addFragment(PannelFragment(R.drawable.img_first_album_default)) + binding.homePannelBackgroundVp.adapter = pannelAdpater + binding.homePannelBackgroundVp.orientation = ViewPager2.ORIENTATION_HORIZONTAL + + binding.homePannelIndicator.setViewPager(binding.homePannelBackgroundVp) + + binding.homePannelBtnMemoIv.setOnClickListener { + val intent = Intent(requireActivity(), MemoActivity::class.java) + val activity = requireActivity() // fragment에서 SharedPreferences에 접근하려면 context가 필요함. + val sharedPreferences = activity.getSharedPreferences("memo", AppCompatActivity.MODE_PRIVATE) + val tempMemo = sharedPreferences.getString("tempMemo", null) + + if(tempMemo != null) { + val dialogView = LayoutInflater.from(activity).inflate(R.layout.dialog, null) + val builder = AlertDialog.Builder(activity) + .setView(dialogView) + .setTitle("메모 복원하기") + + val alertDialog = builder.show() + val yesBtn = alertDialog.findViewById