From c3347ca3ff0e093e97de6513e9040c7bd1cb3de6 Mon Sep 17 00:00:00 2001 From: Antoine Jaury Date: Fri, 12 Jun 2026 17:19:59 +0200 Subject: [PATCH] new: add Android audio player --- gradle/libs.versions.toml | 3 ++ shared/build.gradle.kts | 4 +++ .../fr/ajaury/gwenedeg/di/Modules.android.kt | 10 ++++++ .../gwenedeg/player/AndroidAudioPlayer.kt | 34 +++++++++++++++++++ .../kotlin/fr/ajaury/gwenedeg/App.kt | 8 +++-- .../kotlin/fr/ajaury/gwenedeg/di/Modules.kt | 7 +++- .../fr/ajaury/gwenedeg/player/AudioPlayer.kt | 13 +++++++ .../fr/ajaury/gwenedeg/di/Modules.ios.kt | 6 ++++ .../ajaury/gwenedeg/player/IosAudioPlayer.kt | 23 +++++++++++++ .../ajaury/gwenedeg/player/JsAudioPlayer.kt | 23 +++++++++++++ .../fr/ajaury/gwenedeg/di/Modules.jvm.kt | 6 ++++ .../ajaury/gwenedeg/player/JvmAudioPlayer.kt | 23 +++++++++++++ .../ajaury/gwenedeg/player/WasmAudioPlayer.kt | 23 +++++++++++++ .../fr/ajaury/gwenedeg/di/Modules.web.kt | 4 +++ 14 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/di/Modules.android.kt create mode 100644 shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/player/AndroidAudioPlayer.kt create mode 100644 shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/player/AudioPlayer.kt create mode 100644 shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/di/Modules.ios.kt create mode 100644 shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/player/IosAudioPlayer.kt create mode 100644 shared/src/jsMain/kotlin/fr/ajaury/gwenedeg/player/JsAudioPlayer.kt create mode 100644 shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/di/Modules.jvm.kt create mode 100644 shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/player/JvmAudioPlayer.kt create mode 100644 shared/src/wasmJsMain/kotlin/fr/ajaury/gwenedeg/player/WasmAudioPlayer.kt create mode 100644 shared/src/webMain/kotlin/fr/ajaury/gwenedeg/di/Modules.web.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 330c628..c4510ae 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,7 @@ androidTargetSdk = "36" androidxActivity = "1.13.0" androidxCore = "1.19.0" androidxLifecycle = "2.11.0-beta01" +media3 = "1.10.1" navigation3 = "1.1.1" composeMultiplatform = "1.11.1" kotlin = "2.4.0" @@ -34,6 +35,8 @@ kotlinx-coroutinesSwing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-s lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidxLifecycle" } lifecycle-viewmodelCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" } lifecycle-viewmodelNavigation3 = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "androidxLifecycle" } +media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3" } +media3-common = { module = "androidx.media3:media3-common", version.ref = "media3" } navigation3 = { module = "org.jetbrains.androidx.navigation3:navigation3-ui", version.ref = "navigation3" } wrappers-browser = { module = "org.jetbrains.kotlin-wrappers:kotlin-browser", version.ref = "kotlinWrappers" } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 732c2b4..3e6d628 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -56,6 +56,10 @@ kotlin { sourceSets { androidMain.dependencies { implementation(libs.compose.uiToolingPreview) + + // Player audio + implementation(libs.media3.exoplayer) + implementation(libs.media3.common) } commonMain.dependencies { implementation(libs.compose.runtime) diff --git a/shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/di/Modules.android.kt b/shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/di/Modules.android.kt new file mode 100644 index 0000000..0e61fc7 --- /dev/null +++ b/shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/di/Modules.android.kt @@ -0,0 +1,10 @@ +package fr.ajaury.gwenedeg.di + +import fr.ajaury.gwenedeg.player.AndroidAudioPlayer +import fr.ajaury.gwenedeg.player.AudioPlayer +import org.koin.core.module.Module +import org.koin.dsl.module + +actual val platformModule: Module = module { + single { AndroidAudioPlayer(context = get()) } +} diff --git a/shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/player/AndroidAudioPlayer.kt b/shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/player/AndroidAudioPlayer.kt new file mode 100644 index 0000000..68e6183 --- /dev/null +++ b/shared/src/androidMain/kotlin/fr/ajaury/gwenedeg/player/AndroidAudioPlayer.kt @@ -0,0 +1,34 @@ +package fr.ajaury.gwenedeg.player + +import android.content.Context +import androidx.media3.common.MediaItem +import androidx.media3.exoplayer.ExoPlayer +import gwenedeg.shared.generated.resources.Res + +class AndroidAudioPlayer( + context: Context, +) : AudioPlayer { + private val player = ExoPlayer.Builder(context).build() + + override fun load(filePath: String) { + val mediaItem = MediaItem.fromUri(Res.getUri(filePath)) + player.setMediaItem(mediaItem) + player.prepare() + } + + override fun play() { + player.play() + } + + override fun pause() { + player.pause() + } + + override fun stop() { + player.stop() + } + + override fun release() { + player.release() + } +} diff --git a/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/App.kt b/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/App.kt index 8532d0d..7fc32e7 100644 --- a/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/App.kt +++ b/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/App.kt @@ -7,7 +7,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.navigation3.runtime.NavEntry import androidx.navigation3.ui.NavDisplay import androidx.savedstate.compose.serialization.serializers.SnapshotStateListSerializer -import fr.ajaury.gwenedeg.di.appModule +import fr.ajaury.gwenedeg.di.platformModule +import fr.ajaury.gwenedeg.di.sharedModule import fr.ajaury.gwenedeg.navigation.Route import fr.ajaury.gwenedeg.player.ui.PlayerScreen import fr.ajaury.gwenedeg.records.ui.RecordsScreen @@ -20,7 +21,10 @@ import org.koin.dsl.koinConfiguration fun App() { KoinApplication( configuration = koinConfiguration { - modules(appModule) + modules( + sharedModule, + platformModule, + ) }, ) { val serializer = SnapshotStateListSerializer() diff --git a/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/di/Modules.kt b/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/di/Modules.kt index fb8a11e..6a1df9b 100644 --- a/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/di/Modules.kt +++ b/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/di/Modules.kt @@ -1,14 +1,19 @@ package fr.ajaury.gwenedeg.di +import fr.ajaury.gwenedeg.player.ui.viewmodel.PlayerViewModel import fr.ajaury.gwenedeg.records.data.InMemoryRecordRepository import fr.ajaury.gwenedeg.records.domain.RecordRepository import fr.ajaury.gwenedeg.records.ui.viewmodel.RecordsViewModel +import org.koin.core.module.Module import org.koin.core.module.dsl.bind import org.koin.core.module.dsl.factoryOf import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module -val appModule = module { +val sharedModule = module { factoryOf(::InMemoryRecordRepository) { bind() } viewModelOf(::RecordsViewModel) + viewModelOf(::PlayerViewModel) } + +expect val platformModule: Module diff --git a/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/player/AudioPlayer.kt b/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/player/AudioPlayer.kt new file mode 100644 index 0000000..261a303 --- /dev/null +++ b/shared/src/commonMain/kotlin/fr/ajaury/gwenedeg/player/AudioPlayer.kt @@ -0,0 +1,13 @@ +package fr.ajaury.gwenedeg.player + +interface AudioPlayer { + fun play() + + fun pause() + + fun stop() + + fun release() + + fun load(filePath: String) +} diff --git a/shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/di/Modules.ios.kt b/shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/di/Modules.ios.kt new file mode 100644 index 0000000..2761a97 --- /dev/null +++ b/shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/di/Modules.ios.kt @@ -0,0 +1,6 @@ +package fr.ajaury.gwenedeg.di + +import org.koin.core.module.Module + +actual val platformModule: Module + get() = TODO("Not yet implemented") diff --git a/shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/player/IosAudioPlayer.kt b/shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/player/IosAudioPlayer.kt new file mode 100644 index 0000000..34d4463 --- /dev/null +++ b/shared/src/iosMain/kotlin/fr/ajaury/gwenedeg/player/IosAudioPlayer.kt @@ -0,0 +1,23 @@ +package fr.ajaury.gwenedeg.player + +class IosAudioPlayer : AudioPlayer { + override fun play(file: String) { + TODO("Not yet implemented") + } + + override fun pause() { + TODO("Not yet implemented") + } + + override fun stop() { + TODO("Not yet implemented") + } + + override fun release() { + TODO("Not yet implemented") + } + + override fun load(file: String) { + TODO("Not yet implemented") + } +} diff --git a/shared/src/jsMain/kotlin/fr/ajaury/gwenedeg/player/JsAudioPlayer.kt b/shared/src/jsMain/kotlin/fr/ajaury/gwenedeg/player/JsAudioPlayer.kt new file mode 100644 index 0000000..0607c49 --- /dev/null +++ b/shared/src/jsMain/kotlin/fr/ajaury/gwenedeg/player/JsAudioPlayer.kt @@ -0,0 +1,23 @@ +package fr.ajaury.gwenedeg.player + +class JsAudioPlayer : AudioPlayer { + override fun play(file: String) { + TODO("Not yet implemented") + } + + override fun pause() { + TODO("Not yet implemented") + } + + override fun stop() { + TODO("Not yet implemented") + } + + override fun release() { + TODO("Not yet implemented") + } + + override fun load(filePath: String) { + TODO("Not yet implemented") + } +} diff --git a/shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/di/Modules.jvm.kt b/shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/di/Modules.jvm.kt new file mode 100644 index 0000000..2761a97 --- /dev/null +++ b/shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/di/Modules.jvm.kt @@ -0,0 +1,6 @@ +package fr.ajaury.gwenedeg.di + +import org.koin.core.module.Module + +actual val platformModule: Module + get() = TODO("Not yet implemented") diff --git a/shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/player/JvmAudioPlayer.kt b/shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/player/JvmAudioPlayer.kt new file mode 100644 index 0000000..f8d9079 --- /dev/null +++ b/shared/src/jvmMain/kotlin/fr/ajaury/gwenedeg/player/JvmAudioPlayer.kt @@ -0,0 +1,23 @@ +package fr.ajaury.gwenedeg.player + +class JvmAudioPlayer : AudioPlayer { + override fun play(file: String) { + TODO("Not yet implemented") + } + + override fun pause() { + TODO("Not yet implemented") + } + + override fun stop() { + TODO("Not yet implemented") + } + + override fun release() { + TODO("Not yet implemented") + } + + override fun load(filePath: String) { + TODO("Not yet implemented") + } +} diff --git a/shared/src/wasmJsMain/kotlin/fr/ajaury/gwenedeg/player/WasmAudioPlayer.kt b/shared/src/wasmJsMain/kotlin/fr/ajaury/gwenedeg/player/WasmAudioPlayer.kt new file mode 100644 index 0000000..d695cd4 --- /dev/null +++ b/shared/src/wasmJsMain/kotlin/fr/ajaury/gwenedeg/player/WasmAudioPlayer.kt @@ -0,0 +1,23 @@ +package fr.ajaury.gwenedeg.player + +class WasmAudioPlayer : AudioPlayer { + override fun play(file: String) { + TODO("Not yet implemented") + } + + override fun pause() { + TODO("Not yet implemented") + } + + override fun stop() { + TODO("Not yet implemented") + } + + override fun release() { + TODO("Not yet implemented") + } + + override fun load(filePath: String) { + TODO("Not yet implemented") + } +} diff --git a/shared/src/webMain/kotlin/fr/ajaury/gwenedeg/di/Modules.web.kt b/shared/src/webMain/kotlin/fr/ajaury/gwenedeg/di/Modules.web.kt new file mode 100644 index 0000000..bab5565 --- /dev/null +++ b/shared/src/webMain/kotlin/fr/ajaury/gwenedeg/di/Modules.web.kt @@ -0,0 +1,4 @@ +package fr.ajaury.gwenedeg.di + +actual val platformModule: org.koin.core.module.Module + get() = TODO("Not yet implemented")