Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion newProject/.idea/misc.xml → Assignment_8/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ android {
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
}
}

dependencies {
Expand All @@ -42,6 +45,7 @@ dependencies {
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.fragment.ktx)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>

<application
android:allowBackup="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.example.assignment

import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.assignment.databinding.DialogConfirmBinding

interface ConfirmDialogInterface {
fun onClickYesButton(id: Int)
fun onClickNoButton(id: Int)
}
class ConfirmDialog(
confirmDialogInterface: ConfirmDialogInterface,
title: String, content: String?, buttonText: String, id: Int
) : DialogFragment() {
private var _binding: DialogConfirmBinding? = null
private val binding get() = _binding!!

private var confirmDialogInterface: ConfirmDialogInterface? = null

private var title: String? = null
private var content: String? = null
private var buttonText: String? = null
private var id: Int? = null

init {
this.title = title
this.content = content
this.buttonText = buttonText
this.id = id
this.confirmDialogInterface = confirmDialogInterface
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = DialogConfirmBinding.inflate(inflater, container, false)
val view = binding.root

dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
binding.dialogTitleTv.text = title

if (content == null) {
binding.dialogDescTv.visibility = View.GONE
} else {
binding.dialogDescTv.text = content
}
binding.checkBtn.text = buttonText

if (id == -1) {
binding.cancelBtn.visibility = View.GONE
}

binding.cancelBtn.setOnClickListener {
this.confirmDialogInterface?.onClickNoButton(id!!)
dismiss()
}

binding.checkBtn.setOnClickListener {
this.confirmDialogInterface?.onClickYesButton(id!!)
dismiss()
}

return view
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
151 changes: 151 additions & 0 deletions Assignment_8/app/src/main/java/com/example/assignment/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package com.example.assignment

/*
* 테스트 항목
* 1. 권한 허용
* 1-1. 권한 즉시 허용 시 > RecyclerView 즉시 생성 (0)
* 1-2. 권한 거절 이후 다이얼로그 창에서 확인 > 권한 요청 팝업 (0)
* 1-3. 권한 거절 이후 다이얼로그 창에서 취소 클릭 > 프래그먼트 표시 (0)
* 1-3-1. 프래그먼트에서 설정 창 이동 후 > 권한을 거절한 상태일 경우 앱에 복귀하면 프래그먼트 유지 (0)
* 1-3-2. 프래그먼트에서 설정 창 이동 후 > 권한을 허용하면 RecyclerView 생성 (0)
* 1-4. 권한 거절 이후 앱 종료 > 앱 재실행 시 다이얼로그 창 생성 (0)
* 1-4-1. 다이얼로그 창에서 확인 클릭 > 권한 요청 팝업 (x)
* 1-4-2. 다이얼로그 창에서 취소 클릭 > 프래그먼트 표시 (0)
* */

import android.Manifest
import android.annotation.SuppressLint
import android.media.MediaMetadataRetriever
import android.os.Bundle
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.assignment.databinding.ActivityMainBinding

const val permission = Manifest.permission.READ_MEDIA_AUDIO

class MainActivity : AppCompatActivity(), PermissionCallback {
private lateinit var binding: ActivityMainBinding
private lateinit var permissionHelper: PermissionHelper
private lateinit var musicListAdapter: MusicListAdapter
private lateinit var musicListRecyclerView: RecyclerView
private var isFragmentVisible = false
private var backPressedTime = 0L


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

permissionHelper = PermissionHelper(this, this)


checkAndRequestPermissionInMainActivity()

val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (isFragmentVisible) {
if (System.currentTimeMillis() - backPressedTime <= 3000) {
finish()
} else {
backPressedTime = System.currentTimeMillis()
Toast.makeText(this@MainActivity, "한 번 더 누르면 종료됩니다.", Toast.LENGTH_SHORT)
.show()
}
}
}
}
this.onBackPressedDispatcher.addCallback(this, callback)
}

override fun onRestart() {
super.onRestart()
if (permissionHelper.hasPermission(permission)) {
viewMusicList()
}
}

override fun onResume() {
super.onResume()
if (permissionHelper.hasPermission(permission)) {
viewMusicList()
}
}

override fun onPermissionGranted(permission: String) {
when (permission) {
Manifest.permission.READ_MEDIA_AUDIO -> {
viewMusicList()
}
}
}

private fun checkAndRequestPermissionInMainActivity() {
permissionHelper.checkAndRequestPermissions(permission)

if (!permissionHelper.hasPermission(permission)) {
permissionHelper.showPermissionRequiredFragment()
isFragmentVisible = true
} else if (permissionHelper.hasPermission(permission)) {
viewMusicList()
}
}

private fun loadMusicFromRawFolder(): List<MusicItem> {
val musicList = mutableListOf<MusicItem>()
val rawFields = R.raw::class.java.fields

for (field in rawFields) {
val mediaMetadataRetriever = MediaMetadataRetriever()
val assetFileDescriptor = resources.openRawResourceFd(field.getInt(null))

mediaMetadataRetriever.setDataSource(
assetFileDescriptor.fileDescriptor,
assetFileDescriptor.startOffset,
assetFileDescriptor.length
)

val title =
mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE)
?: "Unknown Title"
val artist =
mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST)
?: "Unknown Artist"
val durationMs =
mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
?.toLong() ?: 0
val duration = formatDuration(durationMs)

musicList.add(MusicItem(title, artist, duration))

mediaMetadataRetriever.release()
assetFileDescriptor.close()
}

return musicList
}

@SuppressLint("DefaultLocale")
private fun formatDuration(durationMs: Long): String {
val seconds = (durationMs / 1000).toInt()
val hours = seconds / 3600
val minutes = (seconds % 3600) / 60
val remainingSeconds = seconds % 60
return String.format("%02d:%02d:%02d", hours, minutes, remainingSeconds)
}



private fun viewMusicList() {
musicListRecyclerView = findViewById(R.id.music_list_recycler_view)
musicListRecyclerView.layoutManager = LinearLayoutManager(this)

val musicList = loadMusicFromRawFolder()
musicListAdapter = MusicListAdapter(musicList)
musicListRecyclerView.adapter = musicListAdapter
isFragmentVisible = false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.assignment

data class MusicItem(
val title: String,
val artist: String,
val duratin: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example.assignment

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class MusicListAdapter(private val musicList: List<MusicItem>) :
RecyclerView.Adapter<MusicListAdapter.MusicViewHolder>() {
class MusicViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val titleTextView: TextView = itemView.findViewById(R.id.title_text_view)
val artistTextView: TextView = itemView.findViewById(R.id.artist_text_view)
val durationTextView: TextView = itemView.findViewById(R.id.duration_text_view)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MusicViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_music_list, parent, false)
return MusicViewHolder(view)
}

override fun onBindViewHolder(viewHolder: MusicViewHolder, position: Int) {
viewHolder.titleTextView.text = musicList[position].title
viewHolder.artistTextView.text = musicList[position].artist
viewHolder.durationTextView.text = musicList[position].duratin
}

override fun getItemCount() = musicList.size
}
Loading