From 5e716759c677fcc3dca8de9fa19d98d7dfc36e6c Mon Sep 17 00:00:00 2001 From: Lalpekhlua Peka <128338554+itzlalpekhlua@users.noreply.github.com> Date: Fri, 27 Mar 2026 06:15:40 +0100 Subject: [PATCH 1/2] perf(ui): reduce blocking work in common compose flows --- .../simpmusic/ui/component/LibraryItem.kt | 6 +- .../ui/component/ModalBottomSheet.kt | 28 +++--- .../simpmusic/ui/screen/home/SettingScreen.kt | 98 ++++++++++--------- 3 files changed, 72 insertions(+), 60 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/LibraryItem.kt b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/LibraryItem.kt index f8eaf9084..fbcd95da3 100644 --- a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/LibraryItem.kt +++ b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/LibraryItem.kt @@ -62,7 +62,6 @@ import com.maxrave.simpmusic.ui.navigation.destination.list.PodcastDestination import com.maxrave.simpmusic.ui.theme.typo import com.maxrave.simpmusic.viewModel.LibraryViewModel import com.maxrave.simpmusic.viewModel.SharedViewModel -import kotlinx.coroutines.runBlocking import org.jetbrains.compose.resources.getString import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -235,6 +234,7 @@ fun LibraryItem( ) { items(state.data) { item -> val song = item as? SongEntity ?: return@items + val radioLabel = stringResource(Res.string.radio) Box( Modifier .padding(horizontal = 10.dp) @@ -247,7 +247,7 @@ fun LibraryItem( listTracks = arrayListOf(firstQueue), firstPlayedTrack = firstQueue, playlistId = "RDAMVM${firstQueue.videoId}", - playlistName = "\"${song.title}\" ${runBlocking { getString(Res.string.radio) }}", + playlistName = "\"${song.title}\" $radioLabel", playlistType = DomainPlaylistType.RADIO, continuation = null, ), @@ -441,4 +441,4 @@ data class LibraryItemState( val type: LibraryItemType, val data: List, val isLoading: Boolean = true, -) \ No newline at end of file +) diff --git a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/ModalBottomSheet.kt b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/ModalBottomSheet.kt index 53868c994..aa1598f6d 100644 --- a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/ModalBottomSheet.kt +++ b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/component/ModalBottomSheet.kt @@ -155,7 +155,6 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import multiplatform.network.cmptoast.ToastGravity import multiplatform.network.cmptoast.showToast import org.jetbrains.compose.resources.StringResource @@ -1433,6 +1432,7 @@ fun NowPlayingBottomSheet( var isBottomSheetVisible by rememberSaveable { mutableStateOf(false) } var changePlaybackSpeedPitch by remember { mutableStateOf(false) } val crossfadeEnabled by dataStoreManager.crossfadeEnabled.collectAsState(DataStoreManager.FALSE) + val radioLabel = stringResource(Res.string.radio) LaunchedEffect(uiState) { if (uiState.songUIState.videoId.isNotEmpty() && !isBottomSheetVisible) { @@ -1819,7 +1819,7 @@ fun NowPlayingBottomSheet( viewModel.onUIEvent( NowPlayingBottomSheetUIEvent.StartRadio( videoId = uiState.songUIState.videoId, - name = "\"${uiState.songUIState.title}\" ${runBlocking { getString(Res.string.radio) }}", + name = "\"${uiState.songUIState.title}\" $radioLabel", ), ) hideModalBottomSheet() @@ -2185,6 +2185,7 @@ fun SleepTimerBottomSheet( val coroutineScope = rememberCoroutineScope() val modelBottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val sleepTimerError = stringResource(Res.string.sleep_timer_set_error) // -1 = nothing selected, Int.MAX_VALUE = End of Song, else = minutes var selectedPreset by rememberSaveable { mutableIntStateOf(-1) } @@ -2423,7 +2424,7 @@ fun SleepTimerBottomSheet( } } else { showToast( - runBlocking { getString(Res.string.sleep_timer_set_error) }, + sleepTimerError, ToastGravity.Bottom, ) } @@ -2437,7 +2438,7 @@ fun SleepTimerBottomSheet( } else -> { showToast( - runBlocking { getString(Res.string.sleep_timer_set_error) }, + sleepTimerError, ToastGravity.Bottom, ) } @@ -3135,6 +3136,9 @@ fun DevLogInBottomSheet( var value by rememberSaveable { mutableStateOf("") } var secondValue by rememberSaveable { mutableStateOf("") } + val title = stringResource(type.titleRes()) + val processingMessage = stringResource(Res.string.processing) + val emptyErrorMessage = stringResource(Res.string.can_not_be_empty) ModalBottomSheet( onDismissRequest = onDismiss, @@ -3158,7 +3162,7 @@ fun DevLogInBottomSheet( shape = RoundedCornerShape(50), ) {} Spacer(modifier = Modifier.height(10.dp)) - Text(text = runBlocking { type.getTitle() }, style = typo().labelSmall) + Text(text = title, style = typo().labelSmall) Spacer(modifier = Modifier.height(5.dp)) OutlinedTextField( value = value, @@ -3183,11 +3187,11 @@ fun DevLogInBottomSheet( if (value.isNotEmpty() && value.isNotBlank() && (type != DevLogInType.YouTube || (secondValue.isNotEmpty() && secondValue.isNotBlank())) ) { - showToast(runBlocking { getString(Res.string.processing) }, ToastGravity.Bottom) + showToast(processingMessage, ToastGravity.Bottom) onDismiss() onDone(value, secondValue) } else { - showToast(runBlocking { getString(Res.string.can_not_be_empty) }, ToastGravity.Bottom) + showToast(emptyErrorMessage, ToastGravity.Bottom) } }, modifier = Modifier.fillMaxWidth().padding(horizontal = 20.dp), @@ -3288,10 +3292,10 @@ sealed class DevLogInType { data object Discord : DevLogInType() - suspend fun getTitle(): String = + fun titleRes(): StringResource = when (this) { - is Spotify -> getString(Res.string.your_sp_dc_param_of_spotify_cookie) - is YouTube -> getString(Res.string.your_youtube_cookie) - is Discord -> getString(Res.string.your_discord_token) + Spotify -> Res.string.your_sp_dc_param_of_spotify_cookie + YouTube -> Res.string.your_youtube_cookie + Discord -> Res.string.your_discord_token } -} \ No newline at end of file +} diff --git a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt index 007d278f3..b5a09bceb 100644 --- a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt @@ -466,25 +466,33 @@ fun SettingScreen( rememberHazeState( blurEnabled = true, ) + val changeText = stringResource(Res.string.change) + val cancelText = stringResource(Res.string.cancel) + val setText = stringResource(Res.string.set) + val warningText = stringResource(Res.string.warning) + val invalidText = stringResource(Res.string.invalid) + val languageText = stringResource(Res.string.language) + val contentCountryText = stringResource(Res.string.content_country) + val qualityText = stringResource(Res.string.quality) + val your320kbpsUrlText = stringResource(Res.string.your_320kbps_url) + val downloadQualityText = stringResource(Res.string.download_quality) + val videoQualityText = stringResource(Res.string.video_quality) + val videoDownloadQualityText = stringResource(Res.string.video_download_quality) + val changeLanguageWarningText = stringResource(Res.string.change_language_warning) - val checkForUpdateSubtitle by remember { - derivedStateOf { - if (isCheckingUpdate) { - return@derivedStateOf runBlocking { getString(Res.string.checking) } - } else { - val lastCheckLong = lastCheckUpdate?.toLong() ?: 0L - return@derivedStateOf runBlocking { - getString( - Res.string.last_checked_at, - DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss") - .withZone(ZoneId.systemDefault()) - .format(Instant.ofEpochMilli(lastCheckLong)), - ) - } - } + val checkForUpdateSubtitle = + if (isCheckingUpdate) { + stringResource(Res.string.checking) + } else { + val lastCheckLong = lastCheckUpdate?.toLong() ?: 0L + stringResource( + Res.string.last_checked_at, + DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) + .format(Instant.ofEpochMilli(lastCheckLong)), + ) } - } var showYouTubeAccountDialog by rememberSaveable { mutableStateOf(false) } @@ -566,7 +574,7 @@ fun SettingScreen( onClick = { viewModel.setAlertData( SettingAlertState( - title = runBlocking { getString(Res.string.language) }, + title = languageText, selectOne = SettingAlertState.SelectData( listSelect = @@ -575,23 +583,23 @@ fun SettingScreen( }, ), confirm = - runBlocking { getString(Res.string.change) } to { state -> + changeText to { state -> val code = SUPPORTED_LANGUAGE.getCodeFromLanguage(state.selectOne?.getSelected() ?: "English") viewModel.setBasicAlertData( SettingBasicAlertState( - title = runBlocking { getString(Res.string.warning) }, - message = runBlocking { getString(Res.string.change_language_warning) }, + title = warningText, + message = changeLanguageWarningText, confirm = - runBlocking { getString(Res.string.change) } to { + changeText to { sharedViewModel.activityRecreate() viewModel.setBasicAlertData(null) viewModel.changeLanguage(code) }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, @@ -602,7 +610,7 @@ fun SettingScreen( onClick = { viewModel.setAlertData( SettingAlertState( - title = runBlocking { getString(Res.string.content_country) }, + title = contentCountryText, selectOne = SettingAlertState.SelectData( listSelect = @@ -611,12 +619,12 @@ fun SettingScreen( }, ), confirm = - runBlocking { getString(Res.string.change) } to { state -> + changeText to { state -> viewModel.changeLocation( state.selectOne?.getSelected() ?: "US", ) }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, @@ -628,7 +636,7 @@ fun SettingScreen( onClick = { viewModel.setAlertData( SettingAlertState( - title = runBlocking { getString(Res.string.quality) }, + title = qualityText, selectOne = SettingAlertState.SelectData( listSelect = @@ -637,10 +645,10 @@ fun SettingScreen( }, ), confirm = - runBlocking { getString(Res.string.change) } to { state -> + changeText to { state -> viewModel.changeQuality(state.selectOne?.getSelected()) }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, @@ -659,21 +667,21 @@ fun SettingScreen( onClick = { viewModel.setAlertData( SettingAlertState( - title = runBlocking { getString(Res.string.your_320kbps_url) }, + title = your320kbpsUrlText, textField = SettingAlertState.TextFieldData( - label = runBlocking { getString(Res.string.your_320kbps_url) }, + label = your320kbpsUrlText, value = "", verifyCodeBlock = { - (it.isNotEmpty()) to runBlocking { getString(Res.string.invalid) } + (it.isNotEmpty()) to invalidText }, ), message = "", confirm = - runBlocking { getString(Res.string.set) } to { state -> + setText to { state -> viewModel.setYour320kbpsUrl(state.textField?.value ?: "") }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, @@ -686,7 +694,7 @@ fun SettingScreen( onClick = { viewModel.setAlertData( SettingAlertState( - title = runBlocking { getString(Res.string.download_quality) }, + title = downloadQualityText, selectOne = SettingAlertState.SelectData( listSelect = @@ -695,10 +703,10 @@ fun SettingScreen( }, ), confirm = - runBlocking { getString(Res.string.change) } to { state -> + changeText to { state -> state.selectOne?.getSelected()?.let { viewModel.setDownloadQuality(it) } }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, @@ -715,7 +723,7 @@ fun SettingScreen( onClick = { viewModel.setAlertData( SettingAlertState( - title = runBlocking { getString(Res.string.video_quality) }, + title = videoQualityText, selectOne = SettingAlertState.SelectData( listSelect = @@ -724,10 +732,10 @@ fun SettingScreen( }, ), confirm = - runBlocking { getString(Res.string.change) } to { state -> + changeText to { state -> viewModel.changeVideoQuality(state.selectOne?.getSelected() ?: "") }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, @@ -738,7 +746,7 @@ fun SettingScreen( onClick = { viewModel.setAlertData( SettingAlertState( - title = runBlocking { getString(Res.string.video_download_quality) }, + title = videoDownloadQualityText, selectOne = SettingAlertState.SelectData( listSelect = @@ -747,10 +755,10 @@ fun SettingScreen( }, ), confirm = - runBlocking { getString(Res.string.change) } to { state -> + changeText to { state -> viewModel.setVideoDownloadQuality(state.selectOne?.getSelected() ?: "") }, - dismiss = runBlocking { getString(Res.string.cancel) }, + dismiss = cancelText, ), ) }, @@ -2604,4 +2612,4 @@ fun SettingScreen( containerColor = Color.Transparent, ), ) -} \ No newline at end of file +} From b953e960cec053fc324bcf738859d9a3128408dd Mon Sep 17 00:00:00 2001 From: Lalpekhlua Peka <128338554+itzlalpekhlua@users.noreply.github.com> Date: Fri, 27 Mar 2026 06:28:45 +0100 Subject: [PATCH 2/2] perf(home): smooth homepage refresh and scrolling --- .../simpmusic/ui/screen/home/HomeScreen.kt | 98 ++++++------ .../simpmusic/viewModel/HomeViewModel.kt | 143 ++++++------------ 2 files changed, 101 insertions(+), 140 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/HomeScreen.kt b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/HomeScreen.kt index d0593885b..b53c02547 100644 --- a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/ui/screen/home/HomeScreen.kt @@ -55,6 +55,7 @@ import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -219,9 +220,6 @@ fun HomeScreen( val moodMomentAndGenre by viewModel.exploreMoodItem.collectAsStateWithLifecycle() val chartLoading by viewModel.loadingChart.collectAsStateWithLifecycle() val loading by viewModel.loading.collectAsStateWithLifecycle() - var accountShow by rememberSaveable { - mutableStateOf(false) - } val regionChart by viewModel.regionCodeChart.collectAsStateWithLifecycle() val reloadDestination by sharedViewModel.reloadDestination.collectAsStateWithLifecycle() val pullToRefreshState = rememberPullToRefreshState() @@ -230,18 +228,49 @@ fun HomeScreen( val params by viewModel.params.collectAsStateWithLifecycle() val homeListState by viewModel.homeListState.collectAsStateWithLifecycle() val continuation by viewModel.continuation.collectAsStateWithLifecycle() + val quickPicksTitle = stringResource(Res.string.quick_picks) + val quickPicksItem by remember(homeData, quickPicksTitle) { + derivedStateOf { + homeData.find { it.title == quickPicksTitle }?.let { content -> + content.copy( + contents = + content.contents.mapNotNull { ct -> + ct?.copy( + artists = + ct.artists?.let { art -> + if (art.size > 1) { + art.dropLast(1) + } else { + art + } + }, + ) + }, + ) + } + } + } val shouldShowLogInAlert by viewModel.showLogInAlert.collectAsStateWithLifecycle() val openAppTime by sharedViewModel.openAppTime.collectAsStateWithLifecycle() val shareLyricsPermissions by sharedViewModel.shareSavedLyrics.collectAsStateWithLifecycle() - var topHeaderColor by remember { - mutableStateOf(md_theme_dark_background) + val accountShow by remember(homeData, accountInfo) { + derivedStateOf { + accountInfo == null || homeData.none { it.subtitle == accountInfo?.first } + } } + var topHeaderColor by remember { mutableStateOf(md_theme_dark_background) } val animatedColor by animateColorAsState(topHeaderColor, tween(500)) val mainHomeThumbnail by viewModel.mainHomeThumbnail.collectAsStateWithLifecycle() - val networkLoader = rememberNetworkLoader(HttpClient(CIO)) + val paletteClient = remember { HttpClient(CIO) } + DisposableEffect(paletteClient) { + onDispose { + paletteClient.close() + } + } + val networkLoader = rememberNetworkLoader(paletteClient) val dominantColorState = rememberDominantColorState( defaultColor = md_theme_dark_background, @@ -314,9 +343,6 @@ fun HomeScreen( } } } - LaunchedEffect(key1 = homeData) { - accountShow = homeData.find { it.subtitle == accountInfo?.first } == null - } LaunchedEffect(openAppTime, shareLyricsPermissions) { Logger.w("HomeScreen", "openAppTime: $openAppTime, shareLyricsPermissions: $shareLyricsPermissions") if (openAppTime >= 10 && openAppTime % 10 == 0 && openAppTime <= 50) { @@ -479,9 +505,13 @@ fun HomeScreen( state = scrollState, verticalArrangement = Arrangement.spacedBy(28.dp), ) { - itemsIndexed(homeData, key = { _, item -> - item.hashCode().toString() + (mainHomeThumbnail ?: "nothumb") - }) { index, item -> + itemsIndexed( + items = homeData, + key = { index, item -> + "${item.title}-${item.subtitle ?: "nosub"}-${item.channelId ?: index}" + }, + contentType = { _, item -> item.title }, + ) { index, item -> Box { if (index == 0) { Box( @@ -530,42 +560,12 @@ fun HomeScreen( ) Spacer(Modifier.height(8.dp)) } - if (item.title == stringResource(Res.string.quick_picks)) { + if (item.title == quickPicksTitle) { AnimatedVisibility( - visible = - homeData.find { - it.title == - stringResource( - Res.string.quick_picks, - ) - } != null, + visible = quickPicksItem != null, ) { QuickPicks( - homeItem = - ( - homeData.find { - it.title == - stringResource( - Res.string.quick_picks, - ) - } ?: return@AnimatedVisibility - ).let { content -> - content.copy( - contents = - content.contents.mapNotNull { ct -> - ct?.copy( - artists = - ct.artists?.let { art -> - if (art.size > 1) { - art.dropLast(1) - } else { - art - } - }, - ) - }, - ) - }, + homeItem = quickPicksItem ?: return@AnimatedVisibility, viewModel = viewModel, ) } @@ -593,7 +593,11 @@ fun HomeScreen( } } if (homeListState == ListState.PAGINATION_EXHAUST) { - items(newRelease, key = { it.hashCode() }) { + items( + items = newRelease, + key = { "${it.title}-${it.subtitle ?: "nosub"}-${it.channelId ?: "new"}" }, + contentType = { it.title }, + ) { AnimatedVisibility( visible = newRelease.isNotEmpty(), ) { @@ -1153,4 +1157,4 @@ fun ChartData( } } } -} \ No newline at end of file +} diff --git a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/HomeViewModel.kt b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/HomeViewModel.kt index 92c5f5141..94981b5df 100644 --- a/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/HomeViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/HomeViewModel.kt @@ -1,8 +1,6 @@ package com.maxrave.simpmusic.viewModel import androidx.lifecycle.viewModelScope -import com.maxrave.common.SELECTED_LANGUAGE -import com.maxrave.common.SUPPORTED_LANGUAGE import com.maxrave.domain.data.entities.SongEntity import com.maxrave.domain.data.model.home.HomeDataCombine import com.maxrave.domain.data.model.home.HomeItem @@ -27,7 +25,6 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import simpmusic.composeapp.generated.resources.Res import simpmusic.composeapp.generated.resources.music_video import simpmusic.composeapp.generated.resources.new_release @@ -65,8 +62,6 @@ class HomeViewModel( val loading = MutableStateFlow(true) val loadingChart = MutableStateFlow(true) - private var regionCode: String = "" - private var language: String = "" private val _songEntity: MutableStateFlow = MutableStateFlow(null) val songEntity: StateFlow = _songEntity @@ -87,86 +82,59 @@ class HomeViewModel( val mainHomeThumbnail: StateFlow = _mainHomeThumbnail init { - if (runBlocking { dataStoreManager.cookie.first() }.isEmpty() && - runBlocking { + viewModelScope.launch { + if (dataStoreManager.cookie.first().isEmpty() && dataStoreManager.shouldShowLogInRequiredAlert.first() == TRUE + ) { + _showLogInAlert.update { true } } - ) { - _showLogInAlert.update { true } } homeJob = Job() viewModelScope.launch { regionCodeChart.value = dataStoreManager.chartKey.first() exploreChart(regionCodeChart.value ?: "ZZ") - language = dataStoreManager.getString(SELECTED_LANGUAGE).first() - ?: SUPPORTED_LANGUAGE.codes.first() - // refresh when region change - val job1 = - launch { - dataStoreManager.location.distinctUntilChanged().collect { - regionCode = it - getHomeItemList(params.value) - } - } - // refresh when language change - val job2 = - launch { - dataStoreManager.language.distinctUntilChanged().collect { - language = it - getHomeItemList(params.value) - } + } + viewModelScope.launch { + combine( + dataStoreManager.location.distinctUntilChanged(), + dataStoreManager.language.distinctUntilChanged(), + dataStoreManager.cookie.distinctUntilChanged(), + params, + ) { _, _, cookie, params -> + HomeRefreshInput(cookie, params) + }.collectLatest { input -> + if (input.cookie.isNotEmpty()) { + Logger.w(tag, "Home refresh triggered with logged-in cookie") + delay(1000) } - val job3 = - launch { - dataStoreManager.cookie.distinctUntilChanged().collect { - getHomeItemList(params.value) - _accountInfo.emit( - Pair( - dataStoreManager.getString("AccountName").first(), - dataStoreManager.getString("AccountThumbUrl").first(), - ), + getHomeItemList(input.params) + } + } + viewModelScope.launch { + dataStoreManager.cookie.distinctUntilChanged().collectLatest { cookie -> + _accountInfo.emit( + if (cookie.isEmpty()) { + null + } else { + Pair( + dataStoreManager.getString("AccountName").first(), + dataStoreManager.getString("AccountThumbUrl").first(), ) - } - } - val job4 = - launch { - params.collectLatest { - getHomeItemList(it) - } - } - val job5 = - launch { - dataStoreManager - .cookie - .distinctUntilChanged() - .collectLatest { - if (it.isNotEmpty()) { - Logger.w(tag, "Cookie changed, refreshing home") - loading.value = true - delay(1000) // To wait for the cookie to be saved properly - getHomeItemList(params.value) - } - } - } - val job6 = - launch { - homeItemList.collectLatest { list -> - _mainHomeThumbnail.value = - list - .firstOrNull() - ?.contents - ?.firstOrNull() - ?.thumbnails - ?.lastOrNull() - ?.url - } - } - job1.join() - job2.join() - job3.join() - job4.join() - job5.join() - job6.join() + }, + ) + } + } + viewModelScope.launch { + homeItemList.collectLatest { list -> + _mainHomeThumbnail.value = + list + .firstOrNull() + ?.contents + ?.firstOrNull() + ?.thumbnails + ?.lastOrNull() + ?.url + } } } @@ -182,12 +150,6 @@ class HomeViewModel( fun getHomeItemList(params: String? = null) { loading.value = true _homeListState.value = ListState.LOADING - language = - runBlocking { - dataStoreManager.getString(SELECTED_LANGUAGE).first() - ?: SUPPORTED_LANGUAGE.codes.first() - } - regionCode = runBlocking { dataStoreManager.location.first() } homeJob?.cancel() homeJob = viewModelScope.launch { @@ -256,16 +218,6 @@ class HomeViewModel( } regionCodeChart.value = dataStoreManager.chartKey.first() Logger.d("HomeViewModel", "getHomeItemList: $result") - dataStoreManager.cookie.first().let { - if (it != "") { - _accountInfo.emit( - Pair( - dataStoreManager.getString("AccountName").first(), - dataStoreManager.getString("AccountThumbUrl").first(), - ), - ) - } - } when { home is Resource.Error -> home.message exploreMoodItem is Resource.Error -> exploreMoodItem.message @@ -365,4 +317,9 @@ class HomeViewModel( const val HOME_PARAMS_COMMUTE = "ggM8SgQIBxABSgQIBRABSgQICRABSgQIChABSgQIDRABSgQICBABSgQIBBABSgQIDhABSgQIAxADSgQIBhAB" const val HOME_PARAMS_FOCUS = "ggM8SgQIBxABSgQIBRABSgQICRABSgQIChABSgQIDRABSgQICBABSgQIBBABSgQIDhABSgQIAxABSgQIBhAD" } -} \ No newline at end of file +} + +private data class HomeRefreshInput( + val cookie: String, + val params: String?, +)