From eb103f2c320de277fd1f09ccba80f4044aa6b3bf Mon Sep 17 00:00:00 2001 From: Malopieds Date: Thu, 27 Jun 2024 10:59:46 +0200 Subject: [PATCH] feat: quick picks on last played songs closes #3 --- .../music/constants/PreferenceKeys.kt | 5 +++ .../com/zionhuang/music/db/DatabaseDao.kt | 2 + .../zionhuang/music/ui/screens/HomeScreen.kt | 6 ++- .../ui/screens/settings/ContentSettings.kt | 38 ++++++++++++++----- .../music/viewmodels/HomeViewModel.kt | 32 +++++++++++++++- app/src/main/res/values/strings.xml | 3 ++ 6 files changed, 74 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/zionhuang/music/constants/PreferenceKeys.kt b/app/src/main/java/com/zionhuang/music/constants/PreferenceKeys.kt index e07ceafcf..8917f129b 100644 --- a/app/src/main/java/com/zionhuang/music/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/zionhuang/music/constants/PreferenceKeys.kt @@ -57,6 +57,7 @@ val AlbumViewTypeKey = stringPreferencesKey("albumViewType") val PlaylistViewTypeKey = stringPreferencesKey("playlistViewType") val PlaylistEditLockKey = booleanPreferencesKey("playlistEditLock") +val QuickPicksKey = stringPreferencesKey("discover") enum class LibraryViewType { LIST, GRID; @@ -108,6 +109,10 @@ enum class MyTopFilter { } } +enum class QuickPicks { + QUICK_PICKS, LAST_LISTEN +} + val TopSize = stringPreferencesKey("topSize") val ShowLyricsKey = booleanPreferencesKey("showLyrics") diff --git a/app/src/main/java/com/zionhuang/music/db/DatabaseDao.kt b/app/src/main/java/com/zionhuang/music/db/DatabaseDao.kt index f582844f7..76a9604f1 100644 --- a/app/src/main/java/com/zionhuang/music/db/DatabaseDao.kt +++ b/app/src/main/java/com/zionhuang/music/db/DatabaseDao.kt @@ -618,6 +618,8 @@ interface DatabaseDao { @Query("SELECT COUNT(1) FROM related_song_map WHERE songId = :songId LIMIT 1") fun hasRelatedSongs(songId: String): Boolean + @Query("SELECT song.* FROM (SELECT * from related_song_map GROUP BY relatedSongId) map JOIN song ON song.id = map.relatedSongId where songId = :songId") + fun getRelatedSongs(songId: String): Flow> @Query( """ UPDATE playlist_song_map SET position = diff --git a/app/src/main/java/com/zionhuang/music/ui/screens/HomeScreen.kt b/app/src/main/java/com/zionhuang/music/ui/screens/HomeScreen.kt index 4b195ff96..b22edbe51 100644 --- a/app/src/main/java/com/zionhuang/music/ui/screens/HomeScreen.kt +++ b/app/src/main/java/com/zionhuang/music/ui/screens/HomeScreen.kt @@ -466,6 +466,7 @@ fun HomeScreen( onDismiss = menuState::dismiss ) } + else -> { } } @@ -764,6 +765,7 @@ fun HomeScreen( onDismiss = menuState::dismiss ) } + else -> { } } @@ -890,8 +892,6 @@ fun HomeScreen( playlist.author ?: run { playlist.author = Artist(name="YouTube Music", id=null) } -// if (playlist.author?.name?.isEmpty() == true || playlist.author?.name?.contains("Youtube Music") != true) -// playlist.author = Artist(name="YouTube Music", id=null) YouTubeGridItem( item = playlist, isActive = mediaMetadata?.album?.id == playlist.id, @@ -959,6 +959,7 @@ fun HomeScreen( ) } } + else -> navController.navigate("artist/${item.id}") } @@ -987,6 +988,7 @@ fun HomeScreen( onDismiss = menuState::dismiss ) } + else -> { } } diff --git a/app/src/main/java/com/zionhuang/music/ui/screens/settings/ContentSettings.kt b/app/src/main/java/com/zionhuang/music/ui/screens/settings/ContentSettings.kt index 8377dde57..259c6718b 100644 --- a/app/src/main/java/com/zionhuang/music/ui/screens/settings/ContentSettings.kt +++ b/app/src/main/java/com/zionhuang/music/ui/screens/settings/ContentSettings.kt @@ -28,10 +28,12 @@ import com.zionhuang.music.constants.ContentLanguageKey import com.zionhuang.music.constants.CountryCodeToName import com.zionhuang.music.constants.InnerTubeCookieKey import com.zionhuang.music.constants.LanguageCodeToName -import com.zionhuang.music.constants.LibraryFilter +import com.zionhuang.music.constants.LibraryFilter.* import com.zionhuang.music.constants.ProxyEnabledKey import com.zionhuang.music.constants.ProxyTypeKey import com.zionhuang.music.constants.ProxyUrlKey +import com.zionhuang.music.constants.QuickPicks.* +import com.zionhuang.music.constants.QuickPicksKey import com.zionhuang.music.constants.SYSTEM_DEFAULT import com.zionhuang.music.constants.TopSize import com.zionhuang.music.ui.component.EditTextPreference @@ -64,7 +66,8 @@ fun ContentSettings( val (proxyType, onProxyTypeChange) = rememberEnumPreference(key = ProxyTypeKey, defaultValue = Proxy.Type.HTTP) val (proxyUrl, onProxyUrlChange) = rememberPreference(key = ProxyUrlKey, defaultValue = "host:port") val (lengthTop, onLengthTopChange) = rememberPreference(key = TopSize, defaultValue = "50") - val (defaultChip, onDefaultChipChange) = rememberEnumPreference(key = ChipSortTypeKey, defaultValue = LibraryFilter.LIBRARY) + val (defaultChip, onDefaultChipChange) = rememberEnumPreference(key = ChipSortTypeKey, defaultValue = LIBRARY) + val (quickPicks, onQuickPicksChange) = rememberEnumPreference(key = QuickPicksKey, defaultValue = QUICK_PICKS) Column( @@ -131,10 +134,6 @@ fun ContentSettings( ) } - PreferenceGroupTitle( - title = "MY TOP" - ) - EditTextPreference( title = { Text(stringResource(R.string.top_length)) }, value = lengthTop, @@ -145,12 +144,33 @@ fun ContentSettings( ) ListPreference( - title = { Text("Change default chip") }, + title = { Text(stringResource(R.string.default_lib_chips)) }, selectedValue = defaultChip, - values = listOf(LibraryFilter.LIBRARY, LibraryFilter.PLAYLISTS, LibraryFilter.SONGS, LibraryFilter.ALBUMS, LibraryFilter.ARTISTS), - valueText = { it.name }, + values = listOf(LIBRARY, PLAYLISTS, SONGS, ALBUMS, ARTISTS), + valueText = { + when(it) { + SONGS -> stringResource(R.string.songs) + ARTISTS -> stringResource(R.string.artists) + ALBUMS -> stringResource(R.string.albums) + PLAYLISTS -> stringResource(R.string.playlists) + LIBRARY -> stringResource(R.string.filter_library) + } + }, onValueSelected = onDefaultChipChange ) + + ListPreference( + title = { Text(stringResource(R.string.set_quick_picks)) }, + selectedValue = quickPicks, + values = listOf(QUICK_PICKS, LAST_LISTEN), + valueText = { + when (it) { + QUICK_PICKS -> stringResource(R.string.quick_picks) + LAST_LISTEN -> stringResource(R.string.last_song_listened) + } + }, + onValueSelected = onQuickPicksChange + ) } TopAppBar( diff --git a/app/src/main/java/com/zionhuang/music/viewmodels/HomeViewModel.kt b/app/src/main/java/com/zionhuang/music/viewmodels/HomeViewModel.kt index 25901a2da..6294463d1 100644 --- a/app/src/main/java/com/zionhuang/music/viewmodels/HomeViewModel.kt +++ b/app/src/main/java/com/zionhuang/music/viewmodels/HomeViewModel.kt @@ -1,5 +1,6 @@ package com.zionhuang.music.viewmodels +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.zionhuang.innertube.YouTube @@ -11,22 +12,33 @@ import com.zionhuang.innertube.pages.ExplorePage import com.zionhuang.innertube.pages.HomePlayList import com.zionhuang.innertube.pages.HomeAlbumRecommendation import com.zionhuang.innertube.pages.HomeArtistRecommendation +import com.zionhuang.music.constants.QuickPicks +import com.zionhuang.music.constants.QuickPicksKey import com.zionhuang.music.db.MusicDatabase import com.zionhuang.music.db.entities.Artist import com.zionhuang.music.db.entities.Song +import com.zionhuang.music.extensions.toEnum +import com.zionhuang.music.utils.dataStore import com.zionhuang.music.utils.reportException import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( + @ApplicationContext context: Context, val database: MusicDatabase, ) : ViewModel() { val isRefreshing = MutableStateFlow(false) + private val quickPicksEnum = context.dataStore.data.map { + it[QuickPicksKey].toEnum(QuickPicks.QUICK_PICKS) + }.distinctUntilChanged() val quickPicks = MutableStateFlow?>(null) val explorePage = MutableStateFlow(null) @@ -55,8 +67,15 @@ class HomeViewModel @Inject constructor( val youtubePlaylists = MutableStateFlow?>(null) + private suspend fun getQuickPicks(){ + when (quickPicksEnum.first()) { + QuickPicks.QUICK_PICKS -> quickPicks.value = database.quickPicks().first().shuffled().take(20) + QuickPicks.LAST_LISTEN -> songLoad() + } + } + private suspend fun load() { - quickPicks.value = database.quickPicks().first().shuffled().take(20) + getQuickPicks() val artists = database.mostPlayedArtists(System.currentTimeMillis() - 86400000 * 7 * 2).first().shuffled().take(5) val filteredArtists = mutableListOf() artists.forEach { @@ -143,6 +162,17 @@ class HomeViewModel @Inject constructor( artistLoad(artistRecommendation.value?.getOrNull(2), homeThirdArtistRecommendation) } + private suspend fun songLoad(){ + val song = database.events().first().firstOrNull()?.song + if (song != null) { + println(song.song.title) + if (database.hasRelatedSongs(song.id)){ + val relatedSongs = database.getRelatedSongs(song.id).first().shuffled().take(20) + quickPicks.value = relatedSongs + } + } + } + private suspend fun albumLoad(song: Song?, next: MutableStateFlow){ val albumUtils = AlbumUtils(song?.song?.albumName, song?.song?.thumbnailUrl) YouTube.next(WatchEndpoint(videoId = song?.id)).onSuccess { res -> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ba5719a83..7d5e95f12 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -227,6 +227,9 @@ Enable proxy Proxy type Proxy URL + Change default library chip + Set Quick Picks + Based on last song listened Restart to take effect Player and audio