refactor: extract audio player logic into a dedicated multiplatform module
This commit is contained in:
@@ -0,0 +1,55 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
|
alias(libs.plugins.androidMultiplatformLibrary)
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
iosArm64()
|
||||||
|
iosSimulatorArm64()
|
||||||
|
|
||||||
|
jvm()
|
||||||
|
|
||||||
|
js {
|
||||||
|
browser()
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalWasmDsl::class)
|
||||||
|
wasmJs {
|
||||||
|
browser()
|
||||||
|
}
|
||||||
|
|
||||||
|
androidLibrary {
|
||||||
|
namespace = "fr.ajaury.gwenedeg.core.audioplayer"
|
||||||
|
compileSdk =
|
||||||
|
libs.versions.androidCompileSdk
|
||||||
|
.get()
|
||||||
|
.toInt()
|
||||||
|
minSdk =
|
||||||
|
libs.versions.androidMinSdk
|
||||||
|
.get()
|
||||||
|
.toInt()
|
||||||
|
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget = JvmTarget.JVM_11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
androidMain.dependencies {
|
||||||
|
// Player audio
|
||||||
|
implementation(libs.media3.exoplayer)
|
||||||
|
implementation(libs.media3.common)
|
||||||
|
}
|
||||||
|
commonMain.dependencies {
|
||||||
|
// DI
|
||||||
|
implementation(project.dependencies.platform(libs.koin.bom))
|
||||||
|
implementation(libs.koin.core)
|
||||||
|
}
|
||||||
|
commonTest.dependencies {
|
||||||
|
implementation(libs.kotlin.test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -3,15 +3,14 @@ package fr.ajaury.gwenedeg.player
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import gwenedeg.shared.generated.resources.Res
|
|
||||||
|
|
||||||
class AndroidAudioPlayer(
|
class AndroidAudioPlayer(
|
||||||
context: Context,
|
context: Context,
|
||||||
) : AudioPlayer {
|
) : AudioPlayer {
|
||||||
private val player = ExoPlayer.Builder(context).build()
|
private val player = ExoPlayer.Builder(context).build()
|
||||||
|
|
||||||
override fun load(filePath: String) {
|
override fun load(uri: String) {
|
||||||
val mediaItem = MediaItem.fromUri(Res.getUri(filePath))
|
val mediaItem = MediaItem.fromUri(uri)
|
||||||
player.setMediaItem(mediaItem)
|
player.setMediaItem(mediaItem)
|
||||||
player.prepare()
|
player.prepare()
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
package fr.ajaury.gwenedeg.di
|
package fr.ajaury.gwenedeg.player.di
|
||||||
|
|
||||||
import fr.ajaury.gwenedeg.player.AndroidAudioPlayer
|
import fr.ajaury.gwenedeg.player.AndroidAudioPlayer
|
||||||
import fr.ajaury.gwenedeg.player.AndroidAudioSessionManager
|
import fr.ajaury.gwenedeg.player.AndroidAudioSessionManager
|
||||||
@@ -7,7 +7,7 @@ import fr.ajaury.gwenedeg.player.AudioSessionManager
|
|||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
actual val platformModule: Module = module {
|
actual val audioPlayerModule: Module = module {
|
||||||
single<AudioPlayer> { AndroidAudioPlayer(context = get()) }
|
single<AudioPlayer> { AndroidAudioPlayer(context = get()) }
|
||||||
single<AudioSessionManager> { AndroidAudioSessionManager() }
|
single<AudioSessionManager> { AndroidAudioSessionManager() }
|
||||||
}
|
}
|
||||||
+1
-1
@@ -9,5 +9,5 @@ interface AudioPlayer {
|
|||||||
|
|
||||||
fun release()
|
fun release()
|
||||||
|
|
||||||
fun load(filePath: String)
|
fun load(uri: String)
|
||||||
}
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package fr.ajaury.gwenedeg.player.di
|
||||||
|
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
expect val audioPlayerModule: Module
|
||||||
+1
-3
@@ -1,6 +1,5 @@
|
|||||||
package fr.ajaury.gwenedeg.player
|
package fr.ajaury.gwenedeg.player
|
||||||
|
|
||||||
import gwenedeg.shared.generated.resources.Res
|
|
||||||
import kotlinx.cinterop.ExperimentalForeignApi
|
import kotlinx.cinterop.ExperimentalForeignApi
|
||||||
import platform.AVFoundation.AVPlayer
|
import platform.AVFoundation.AVPlayer
|
||||||
import platform.AVFoundation.pause
|
import platform.AVFoundation.pause
|
||||||
@@ -12,8 +11,7 @@ class IosAudioPlayer : AudioPlayer {
|
|||||||
private var player: AVPlayer? = null
|
private var player: AVPlayer? = null
|
||||||
|
|
||||||
@OptIn(ExperimentalForeignApi::class)
|
@OptIn(ExperimentalForeignApi::class)
|
||||||
override fun load(filePath: String) {
|
override fun load(uri: String) {
|
||||||
val uri = Res.getUri(filePath)
|
|
||||||
val nsUrl = NSURL.URLWithString(uri) ?: error("Invalid audio URI: $uri")
|
val nsUrl = NSURL.URLWithString(uri) ?: error("Invalid audio URI: $uri")
|
||||||
|
|
||||||
player = AVPlayer(nsUrl)
|
player = AVPlayer(nsUrl)
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
package fr.ajaury.gwenedeg.di
|
package fr.ajaury.gwenedeg.player.di
|
||||||
|
|
||||||
import fr.ajaury.gwenedeg.player.AudioPlayer
|
import fr.ajaury.gwenedeg.player.AudioPlayer
|
||||||
import fr.ajaury.gwenedeg.player.AudioSessionManager
|
import fr.ajaury.gwenedeg.player.AudioSessionManager
|
||||||
@@ -7,7 +7,7 @@ import fr.ajaury.gwenedeg.player.IosAudioSessionManager
|
|||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
actual val platformModule: Module = module {
|
actual val audioPlayerModule: Module = module {
|
||||||
single<AudioPlayer> { IosAudioPlayer() }
|
single<AudioPlayer> { IosAudioPlayer() }
|
||||||
single<AudioSessionManager> { IosAudioSessionManager() }
|
single<AudioSessionManager> { IosAudioSessionManager() }
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package fr.ajaury.gwenedeg.player
|
package fr.ajaury.gwenedeg.player
|
||||||
|
|
||||||
class JsAudioPlayer : AudioPlayer {
|
class JsAudioPlayer : AudioPlayer {
|
||||||
override fun play(file: String) {
|
override fun play() {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class JsAudioPlayer : AudioPlayer {
|
|||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun load(filePath: String) {
|
override fun load(uri: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
package fr.ajaury.gwenedeg.di
|
package fr.ajaury.gwenedeg.player.di
|
||||||
|
|
||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
actual val platformModule: Module
|
actual val audioPlayerModule: Module
|
||||||
get() = TODO("Not yet implemented")
|
get() = TODO("Not yet implemented")
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package fr.ajaury.gwenedeg.player
|
package fr.ajaury.gwenedeg.player
|
||||||
|
|
||||||
class JvmAudioPlayer : AudioPlayer {
|
class JvmAudioPlayer : AudioPlayer {
|
||||||
override fun play(file: String) {
|
override fun play() {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class JvmAudioPlayer : AudioPlayer {
|
|||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun load(filePath: String) {
|
override fun load(uri: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package fr.ajaury.gwenedeg.player.di
|
||||||
|
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
actual val audioPlayerModule: Module
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package fr.ajaury.gwenedeg.player
|
package fr.ajaury.gwenedeg.player
|
||||||
|
|
||||||
class WasmAudioPlayer : AudioPlayer {
|
class WasmAudioPlayer : AudioPlayer {
|
||||||
override fun play(file: String) {
|
override fun play() {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class WasmAudioPlayer : AudioPlayer {
|
|||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun load(filePath: String) {
|
override fun load(uri: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package fr.ajaury.gwenedeg.player.di
|
||||||
|
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
actual val audioPlayerModule: Module
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
@@ -36,3 +36,4 @@ include(":androidApp")
|
|||||||
include(":desktopApp")
|
include(":desktopApp")
|
||||||
include(":webApp")
|
include(":webApp")
|
||||||
include(":shared")
|
include(":shared")
|
||||||
|
include(":core:audioplayer")
|
||||||
|
|||||||
@@ -56,12 +56,11 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
androidMain.dependencies {
|
androidMain.dependencies {
|
||||||
implementation(libs.compose.uiToolingPreview)
|
implementation(libs.compose.uiToolingPreview)
|
||||||
|
|
||||||
// Player audio
|
|
||||||
implementation(libs.media3.exoplayer)
|
|
||||||
implementation(libs.media3.common)
|
|
||||||
}
|
}
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
|
// Audio player module
|
||||||
|
implementation(projects.core.audioplayer)
|
||||||
|
|
||||||
implementation(libs.compose.runtime)
|
implementation(libs.compose.runtime)
|
||||||
implementation(libs.compose.foundation)
|
implementation(libs.compose.foundation)
|
||||||
implementation(libs.compose.material3)
|
implementation(libs.compose.material3)
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.navigation3.runtime.NavEntry
|
import androidx.navigation3.runtime.NavEntry
|
||||||
import androidx.navigation3.ui.NavDisplay
|
import androidx.navigation3.ui.NavDisplay
|
||||||
import androidx.savedstate.compose.serialization.serializers.SnapshotStateListSerializer
|
import androidx.savedstate.compose.serialization.serializers.SnapshotStateListSerializer
|
||||||
import fr.ajaury.gwenedeg.di.platformModule
|
|
||||||
import fr.ajaury.gwenedeg.di.sharedModule
|
import fr.ajaury.gwenedeg.di.sharedModule
|
||||||
import fr.ajaury.gwenedeg.navigation.Route
|
import fr.ajaury.gwenedeg.navigation.Route
|
||||||
|
import fr.ajaury.gwenedeg.player.di.audioPlayerModule
|
||||||
import fr.ajaury.gwenedeg.player.ui.PlayerScreen
|
import fr.ajaury.gwenedeg.player.ui.PlayerScreen
|
||||||
import fr.ajaury.gwenedeg.records.ui.RecordsScreen
|
import fr.ajaury.gwenedeg.records.ui.RecordsScreen
|
||||||
import fr.ajaury.gwenedeg.theme.GwenedegTheme
|
import fr.ajaury.gwenedeg.theme.GwenedegTheme
|
||||||
@@ -23,7 +23,7 @@ fun App() {
|
|||||||
configuration = koinConfiguration {
|
configuration = koinConfiguration {
|
||||||
modules(
|
modules(
|
||||||
sharedModule,
|
sharedModule,
|
||||||
platformModule,
|
audioPlayerModule,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import fr.ajaury.gwenedeg.player.ui.viewmodel.PlayerViewModel
|
|||||||
import fr.ajaury.gwenedeg.records.data.InMemoryRecordRepository
|
import fr.ajaury.gwenedeg.records.data.InMemoryRecordRepository
|
||||||
import fr.ajaury.gwenedeg.records.domain.RecordRepository
|
import fr.ajaury.gwenedeg.records.domain.RecordRepository
|
||||||
import fr.ajaury.gwenedeg.records.ui.viewmodel.RecordsViewModel
|
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.bind
|
||||||
import org.koin.core.module.dsl.factoryOf
|
import org.koin.core.module.dsl.factoryOf
|
||||||
import org.koin.core.module.dsl.viewModelOf
|
import org.koin.core.module.dsl.viewModelOf
|
||||||
@@ -15,5 +14,3 @@ val sharedModule = module {
|
|||||||
viewModelOf(::RecordsViewModel)
|
viewModelOf(::RecordsViewModel)
|
||||||
viewModelOf(::PlayerViewModel)
|
viewModelOf(::PlayerViewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
expect val platformModule: Module
|
|
||||||
|
|||||||
+2
-1
@@ -3,6 +3,7 @@ package fr.ajaury.gwenedeg.player.ui.viewmodel
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import fr.ajaury.gwenedeg.player.AudioPlayer
|
import fr.ajaury.gwenedeg.player.AudioPlayer
|
||||||
import fr.ajaury.gwenedeg.player.AudioSessionManager
|
import fr.ajaury.gwenedeg.player.AudioSessionManager
|
||||||
|
import gwenedeg.shared.generated.resources.Res
|
||||||
|
|
||||||
class PlayerViewModel(
|
class PlayerViewModel(
|
||||||
private val audioPlayer: AudioPlayer,
|
private val audioPlayer: AudioPlayer,
|
||||||
@@ -13,7 +14,7 @@ class PlayerViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun play(filePath: String) {
|
fun play(filePath: String) {
|
||||||
audioPlayer.load(filePath = filePath)
|
audioPlayer.load(uri = Res.getUri(filePath))
|
||||||
audioPlayer.play()
|
audioPlayer.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
package fr.ajaury.gwenedeg.di
|
|
||||||
|
|
||||||
actual val platformModule: org.koin.core.module.Module
|
|
||||||
get() = TODO("Not yet implemented")
|
|
||||||
Reference in New Issue
Block a user