From fe5a8507c9af2377a467256362d7d8597f369c5d Mon Sep 17 00:00:00 2001 From: GEON_HYEONG_LEE Date: Sat, 21 Jun 2025 17:15:54 +0900 Subject: [PATCH 1/2] week9_assignment --- app/src/main/AndroidManifest.xml | 10 +- .../bcsd_android_2025_1/MainActivity.kt | 106 +++++++++++++++++- .../com/example/bcsd_android_2025_1/Music.kt | 7 ++ .../bcsd_android_2025_1/MusicAdapter.kt | 40 +++++++ app/src/main/res/layout/activity_main.xml | 42 +++++-- app/src/main/res/layout/item_music.xml | 36 ++++++ app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 4 +- app/src/main/res/values/themes.xml | 9 +- 9 files changed, 231 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/com/example/bcsd_android_2025_1/Music.kt create mode 100644 app/src/main/java/com/example/bcsd_android_2025_1/MusicAdapter.kt create mode 100644 app/src/main/res/layout/item_music.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4c80941..945e5e4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,10 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.example.bcsd_android_2025_1"> + + + - - - \ No newline at end of file + diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt b/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt index 3ffa0eb..738cf4d 100644 --- a/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt +++ b/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt @@ -1,14 +1,112 @@ package com.example.bcsd_android_2025_1 +import android.Manifest +import android.content.pm.PackageManager +import android.os.Build import android.os.Bundle -import androidx.activity.enableEdgeToEdge +import android.provider.MediaStore +import android.view.View +import android.widget.Button +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView class MainActivity : AppCompatActivity() { + + private lateinit var recyclerView: RecyclerView + private lateinit var permissionLayout: View + private lateinit var btnRequestPermission: Button + + private val permissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestPermission() + ) { isGranted -> + if (isGranted) { + loadMusicFiles() + } else { + showPermissionLayout() + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + recyclerView = findViewById(R.id.musicRecyclerView) + permissionLayout = findViewById(R.id.permissionLayout) + btnRequestPermission = findViewById(R.id.btnRequestPermission) + + btnRequestPermission.setOnClickListener { + requestPermission() + } + + if (isPermissionGranted()) { + loadMusicFiles() + } else { + showPermissionLayout() + requestPermission() + } + } + + + private fun isPermissionGranted(): Boolean { + val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Manifest.permission.READ_MEDIA_AUDIO + } else { + Manifest.permission.READ_EXTERNAL_STORAGE + } + return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED + } + + private fun requestPermission() { + val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Manifest.permission.READ_MEDIA_AUDIO + } else { + Manifest.permission.READ_EXTERNAL_STORAGE + } + permissionLauncher.launch(permission) + } + + private fun showPermissionLayout() { + recyclerView.visibility = View.GONE + permissionLayout.visibility = View.VISIBLE + } + + private fun loadMusicFiles() { + recyclerView.visibility = View.VISIBLE + permissionLayout.visibility = View.GONE + + val musicList = mutableListOf() + val uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + val projection = arrayOf( + MediaStore.Audio.Media.TITLE, + MediaStore.Audio.Media.ARTIST, + MediaStore.Audio.Media.DURATION + ) + + val cursor = contentResolver.query( + uri, + projection, + MediaStore.Audio.Media.IS_MUSIC + "!= 0", + null, + null + ) + + cursor?.use { + val titleIdx = it.getColumnIndex(MediaStore.Audio.Media.TITLE) + val artistIdx = it.getColumnIndex(MediaStore.Audio.Media.ARTIST) + val durationIdx = it.getColumnIndex(MediaStore.Audio.Media.DURATION) + + while (it.moveToNext()) { + val title = it.getString(titleIdx) ?: "Unknown" + val artist = it.getString(artistIdx) ?: "Unknown" + val duration = it.getLong(durationIdx) + musicList.add(Music(title, artist, duration)) + } + } + + recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.adapter = MusicAdapter(musicList) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/Music.kt b/app/src/main/java/com/example/bcsd_android_2025_1/Music.kt new file mode 100644 index 0000000..96dbb57 --- /dev/null +++ b/app/src/main/java/com/example/bcsd_android_2025_1/Music.kt @@ -0,0 +1,7 @@ +package com.example.bcsd_android_2025_1 + +data class Music( + val title: String, + val artist: String, + val duration: Long +) diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/MusicAdapter.kt b/app/src/main/java/com/example/bcsd_android_2025_1/MusicAdapter.kt new file mode 100644 index 0000000..2d36ae1 --- /dev/null +++ b/app/src/main/java/com/example/bcsd_android_2025_1/MusicAdapter.kt @@ -0,0 +1,40 @@ +package com.example.bcsd_android_2025_1 + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView + +class MusicAdapter(private val musicList: List) : + RecyclerView.Adapter() { + + class MusicViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val title: TextView = view.findViewById(R.id.titleText) + val artist: TextView = view.findViewById(R.id.artistText) + val duration: TextView = view.findViewById(R.id.durationText) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MusicViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_music, parent, false) + return MusicViewHolder(view) + } + + override fun onBindViewHolder(holder: MusicViewHolder, position: Int) { + val music = musicList[position] + holder.title.text = music.title + holder.artist.text = music.artist + holder.duration.text = formatDuration(music.duration) + } + + override fun getItemCount(): Int = musicList.size + + private fun formatDuration(durationMs: Long): String { + val seconds = durationMs / 1000 % 60 + val minutes = durationMs / (1000 * 60) % 60 + val hours = durationMs / (1000 * 60 * 60) + return if (hours > 0) "%d:%02d:%02d".format(hours, minutes, seconds) + else "%02d:%02d".format(minutes, seconds) + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 311f3cb..88d3ae2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,19 +1,41 @@ - + android:layout_height="match_parent"> - + + + app:layout_constraintEnd_toEndOf="parent"> + + - \ No newline at end of file +