Skip to content

Commit 4d32d2f

Browse files
committed
fix: crash when adding lots of songs to queue
1 parent eda8364 commit 4d32d2f

7 files changed

Lines changed: 53 additions & 5 deletions

File tree

composeApp/src/androidMain/kotlin/paige/navic/di/PlatformModule.android.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ actual val platformModule = module {
5454
AndroidMediaPlayerViewModel(
5555
application = androidApplication(),
5656
stateRepository = get(),
57+
songRepository = get(),
5758
albumDao = get(),
59+
songDao = get(),
5860
downloadManager = get(),
5961
connectivityManager = get(),
6062
sessionManager = get(),

composeApp/src/androidMain/kotlin/paige/navic/shared/MediaPlayer.android.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import kotlinx.coroutines.withContext
5151
import org.koin.core.component.KoinComponent
5252
import org.koin.core.component.inject
5353
import paige.navic.data.database.dao.AlbumDao
54+
import paige.navic.data.database.dao.SongDao
5455
import paige.navic.data.database.mappers.toDomainModel
5556
import paige.navic.domain.manager.AndroidScrobbleManager
5657
import paige.navic.domain.manager.ConnectivityManager
@@ -66,6 +67,7 @@ import paige.navic.domain.models.DomainSong
6667
import paige.navic.domain.models.DomainSongCollection
6768
import paige.navic.domain.models.settings.ReplayGainMode
6869
import paige.navic.domain.repositories.PlayerStateRepository
70+
import paige.navic.domain.repositories.SongRepository
6971
import paige.navic.ui.core.PlayerUiState
7072
import paige.navic.util.core.Logger
7173
import paige.navic.util.core.ResourceProvider
@@ -286,16 +288,19 @@ class PlaybackService : MediaSessionService(), KoinComponent {
286288

287289
class AndroidMediaPlayerViewModel(
288290
stateRepository: PlayerStateRepository,
291+
songRepository: SongRepository,
289292
downloadManager: DownloadManager,
290293
connectivityManager: ConnectivityManager,
291294
preferenceManager: PreferenceManager,
292295
private val application: Application,
293296
private val albumDao: AlbumDao,
297+
private val songDao: SongDao,
294298
private val platformContext: CoilPlatformContext,
295299
private val sessionManager: SessionManager,
296300
private val snackBarManager: SnackBarManager
297301
) : MediaPlayerViewModel(
298302
stateRepository = stateRepository,
303+
songRepository = songRepository,
299304
connectivityManager = connectivityManager,
300305
downloadManager = downloadManager,
301306
preferenceManager = preferenceManager
@@ -650,6 +655,7 @@ class AndroidMediaPlayerViewModel(
650655
val newQueue = state.queue + song
651656
state.copy(
652657
queue = newQueue,
658+
queueIds = newQueue.map { it.id },
653659
currentIndex = if (state.currentIndex == -1) 0 else state.currentIndex,
654660
currentSong = if (state.currentIndex == -1) song else state.currentSong
655661
)
@@ -678,6 +684,7 @@ class AndroidMediaPlayerViewModel(
678684
val newQueue = state.queue + songs
679685
state.copy(
680686
queue = newQueue,
687+
queueIds = newQueue.map { it.id },
681688
currentIndex = if (state.currentIndex == -1) 0 else state.currentIndex,
682689
currentSong = if (state.currentIndex == -1) songs.firstOrNull() else state.currentSong
683690
)
@@ -701,6 +708,7 @@ class AndroidMediaPlayerViewModel(
701708
}
702709
state.copy(
703710
queue = newQueue,
711+
queueIds = newQueue.map { it.id },
704712
currentIndex = newIndex,
705713
currentSong = if (newIndex == -1) null else newQueue[newIndex]
706714
)
@@ -724,6 +732,7 @@ class AndroidMediaPlayerViewModel(
724732
}
725733
state.copy(
726734
queue = newQueue,
735+
queueIds = newQueue.map { it.id },
727736
currentIndex = newIndex,
728737
currentSong = if (newIndex == -1) null else newQueue[newIndex]
729738
)
@@ -736,6 +745,7 @@ class AndroidMediaPlayerViewModel(
736745
_uiState.update {
737746
it.copy(
738747
queue = emptyList(),
748+
queueIds = emptyList(),
739749
currentSong = null,
740750
currentIndex = -1,
741751
progress = 0f
@@ -770,6 +780,7 @@ class AndroidMediaPlayerViewModel(
770780
state.queue.slice(0..state.currentIndex) + song + state.queue.slice(state.currentIndex + 1..<state.queue.size)
771781
state.copy(
772782
queue = newQueue,
783+
queueIds = newQueue.map { it.id },
773784
currentIndex = if (state.currentIndex == -1) 0 else state.currentIndex,
774785
currentSong = if (state.currentIndex == -1) song else state.currentSong
775786
)
@@ -800,6 +811,7 @@ class AndroidMediaPlayerViewModel(
800811
)
801812
state.copy(
802813
queue = newQueue,
814+
queueIds = newQueue.map { it.id },
803815
currentIndex = if (state.currentIndex == -1) 0 else state.currentIndex,
804816
currentSong = if (state.currentIndex == -1) newCollection.firstOrNull() else state.currentSong
805817
)
@@ -873,6 +885,7 @@ class AndroidMediaPlayerViewModel(
873885
_uiState.update { state ->
874886
state.copy(
875887
queue = listOf(dummyRadioSong),
888+
queueIds = listOf(radioId),
876889
currentIndex = 0,
877890
currentSong = dummyRadioSong,
878891
isLoading = true
@@ -898,6 +911,7 @@ class AndroidMediaPlayerViewModel(
898911
_uiState.update { state ->
899912
state.copy(
900913
queue = shuffledSongs,
914+
queueIds = shuffledSongs.map { it.id },
901915
currentIndex = 0,
902916
currentSong = shuffledSongs.firstOrNull()
903917
)

composeApp/src/commonMain/kotlin/paige/navic/domain/repositories/SongRepository.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class SongRepository(
3131
return songDao.getAllSongs().map { it.toDomainModel() }
3232
}
3333

34+
suspend fun getSongsByIds(ids: List<String>): List<DomainSong> {
35+
return songDao.getSongsByIds(ids).map { it.toDomainModel() }
36+
}
37+
3438
private suspend fun getLocalData(
3539
listType: DomainSongListType,
3640
reversed: Boolean

composeApp/src/commonMain/kotlin/paige/navic/shared/MediaPlayer.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ import paige.navic.domain.models.DomainSong
2020
import paige.navic.domain.models.DomainSongCollection
2121
import paige.navic.domain.models.settings.ExplicitContentPlayback
2222
import paige.navic.domain.repositories.PlayerStateRepository
23+
import paige.navic.domain.repositories.SongRepository
2324
import paige.navic.ui.core.PlayerUiState
2425
import paige.navic.util.core.Logger
2526
import kotlin.time.Duration.Companion.seconds
2627

2728
abstract class MediaPlayerViewModel(
28-
private val stateRepository: PlayerStateRepository,
29+
protected val songRepository: SongRepository,
30+
protected val stateRepository: PlayerStateRepository,
2931
protected val connectivityManager: ConnectivityManager,
3032
protected val downloadManager: DownloadManager,
3133
protected val preferenceManager: PreferenceManager
@@ -102,7 +104,21 @@ abstract class MediaPlayerViewModel(
102104
val restoredState = Json.decodeFromJsonElement<PlayerUiState>(
103105
Json.parseToJsonElement(savedJson)
104106
)
105-
val stateToApply = restoredState.copy(isPaused = true, isLoading = false)
107+
108+
val fullQueue = if (restoredState.queueIds.isNotEmpty()) {
109+
songRepository.getSongsByIds(restoredState.queueIds)
110+
} else {
111+
emptyList()
112+
}
113+
114+
val currentSong = fullQueue.getOrNull(restoredState.currentIndex)
115+
116+
val stateToApply = restoredState.copy(
117+
queue = fullQueue,
118+
currentSong = currentSong,
119+
isPaused = true,
120+
isLoading = false
121+
)
106122

107123
_uiState.value = stateToApply
108124

@@ -142,7 +158,8 @@ abstract class MediaPlayerViewModel(
142158

143159
private suspend fun saveStateInternal(state: PlayerUiState) {
144160
try {
145-
val jsonString = Json.encodeToString(state)
161+
val persistentState = state.toPersistentState()
162+
val jsonString = Json.encodeToString(persistentState)
146163
stateRepository.saveState(jsonString)
147164
} catch (e: Exception) {
148165
Logger.e("MediaPlayerViewModel", "Failed to save state!", e)

composeApp/src/commonMain/kotlin/paige/navic/ui/core/PlayerUiState.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,12 @@ data class PlayerUiState(
1818
val playbackSpeed: Float = 1.0f,
1919
val playbackBitrate: Int? = null,
2020
val playbackSampleRate: Int? = null,
21-
val playbackMimeType: String? = null
22-
)
21+
val playbackMimeType: String? = null,
22+
val queueIds: List<String> = emptyList()
23+
) {
24+
fun toPersistentState() = copy(
25+
queue = emptyList(),
26+
currentSong = null,
27+
currentCollection = null
28+
)
29+
}

composeApp/src/iosMain/kotlin/paige/navic/di/PlatformModule.ios.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ actual val platformModule = module {
6161
viewModel<MediaPlayerViewModel> {
6262
IOSMediaPlayerViewModel(
6363
stateRepository = get(),
64+
songRepository = get(),
6465
downloadManager = get(),
6566
connectivityManager = get(),
6667
syncManager = get(),

composeApp/src/iosMain/kotlin/paige/navic/shared/MediaPlayer.ios.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import paige.navic.domain.models.DomainRadio
2222
import paige.navic.domain.models.DomainSong
2323
import paige.navic.domain.models.DomainSongCollection
2424
import paige.navic.domain.repositories.PlayerStateRepository
25+
import paige.navic.domain.repositories.SongRepository
2526
import paige.navic.ui.core.PlayerUiState
2627
import paige.navic.util.core.Logger
2728
import platform.AVFAudio.AVAudioSession
@@ -75,6 +76,7 @@ import platform.darwin.dispatch_semaphore_wait
7576

7677
class IOSMediaPlayerViewModel(
7778
stateRepository: PlayerStateRepository,
79+
songRepository: SongRepository,
7880
downloadManager: DownloadManager,
7981
connectivityManager: ConnectivityManager,
8082
preferenceManager: PreferenceManager,
@@ -83,6 +85,7 @@ class IOSMediaPlayerViewModel(
8385
private val snackBarManager: SnackBarManager
8486
) : MediaPlayerViewModel(
8587
stateRepository = stateRepository,
88+
songRepository = songRepository,
8689
connectivityManager = connectivityManager,
8790
downloadManager = downloadManager,
8891
preferenceManager = preferenceManager

0 commit comments

Comments
 (0)