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
1 change: 1 addition & 0 deletions .idea/.name

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

6 changes: 6 additions & 0 deletions .idea/AndroidProjectSystem.xml

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

6 changes: 6 additions & 0 deletions .idea/compiler.xml

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

10 changes: 10 additions & 0 deletions .idea/deploymentTargetSelector.xml

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

19 changes: 19 additions & 0 deletions .idea/gradle.xml

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

6 changes: 6 additions & 0 deletions .idea/kotlinc.xml

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

10 changes: 10 additions & 0 deletions .idea/migrations.xml

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

4 changes: 4 additions & 0 deletions .idea/misc.xml

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

17 changes: 17 additions & 0 deletions .idea/runConfigurations.xml

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

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

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

6 changes: 6 additions & 0 deletions .idea/vcs.xml

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

2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ android {
}

dependencies {

implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>


<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -12,6 +21,12 @@
android:supportsRtl="true"
android:theme="@style/Theme.BCSD_Android_20251"
tools:targetApi="31">

<service
android:name=".AudioPlayer"
android:exported="false"
android:foregroundServiceType="mediaPlayback"/>

<activity
android:name=".MainActivity"
android:exported="true">
Expand All @@ -23,4 +38,5 @@
</activity>
</application>


</manifest>
64 changes: 64 additions & 0 deletions app/src/main/java/com/example/bcsd_android_2025_1/AudioAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.example.bcsd_android_2025_1

import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView

class AudioAdapter : RecyclerView.Adapter<AudioAdapter.AudioViewHolder>(){


private val items = mutableListOf<MainActivity.AudioItem>()

fun submitList(newList: List<MainActivity.AudioItem>) {
items.clear()
items.addAll(newList)
notifyDataSetChanged()
}

inner class AudioViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val titleTextView: TextView = itemView.findViewById(R.id.tv_item_title)
val artistTextView: TextView = itemView.findViewById(R.id.tv_item_artist)
val timeTextView: TextView = itemView.findViewById(R.id.tv_item_time)
}

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

override fun onBindViewHolder(holder: AudioViewHolder, position: Int) {
val item = items[position]
holder.titleTextView.text = item.name
holder.artistTextView.text = item.artist

val totalTime = item.duration/1000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

별도의 확장함수로 분리하는게 좋을 것 같습니다

val hours = totalTime/3600
val minutes = (totalTime%3600)/60
val seconds = totalTime%60
if (hours > 0){
holder.timeTextView.text = String.format("%d:%02d:%02d", hours, minutes, seconds)
} else {
holder.timeTextView.text = String.format("%d:%02d", minutes, seconds)
}

holder.itemView.setOnClickListener {
val context = holder.itemView.context
val intent = Intent(context, AudioPlayer::class.java).apply{
putExtra("AUDIO_URI",item.uri)
putExtra("AUDIO_TITLE",item.name)
}
ContextCompat.startForegroundService(context, intent)
}

}

override fun getItemCount(): Int = items.size



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.example.bcsd_android_2025_1

import android.app.Application
import android.content.ContentUris
import android.provider.MediaStore.Audio.Media
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch


class AudioListManager(application: Application) : AndroidViewModel(application) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ViewModel 사용을 시도한 것은 좋은데, ViewModel은 이렇게 사용하면 안됩니다.
자세한건 13주차 아키텍쳐에서 설명하겠습니다.

private val audioListIn = MutableLiveData<List<MainActivity.AudioItem>>()
val audioListObserve: LiveData<List<MainActivity.AudioItem>> get() = audioListIn

fun loadAudioFiles() {
viewModelScope.launch(Dispatchers.IO) {
val list = mutableListOf<MainActivity.AudioItem>()
val resolver = getApplication<Application>().contentResolver

val projection = arrayOf(
Media._ID,
Media.DISPLAY_NAME,
Media.ARTIST,
Media.DURATION
)

val selection= "${Media.IS_MUSIC} != 0 AND ${Media.DURATION} > 0"
val selectionArgs: Array<String>? = null

val sortOrder = "${Media.DATE_ADDED} DESC"

resolver.query(
Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(Media._ID)
val nameColumn = cursor.getColumnIndexOrThrow(Media.DISPLAY_NAME)
val artistColumn = cursor.getColumnIndexOrThrow(Media.ARTIST)
val durationColumn = cursor.getColumnIndexOrThrow(Media.DURATION)

while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val artists = cursor.getString(artistColumn)
val duration = cursor.getLong(durationColumn)
val uri = ContentUris.withAppendedId(Media.EXTERNAL_CONTENT_URI, id)

list.add(MainActivity.AudioItem(id, name, artists, duration, uri))

}
}

audioListIn.postValue(list)
}
}
}
Loading