Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ interface MusicDao {
suspend fun getAllTelegramSongIds(): List<Long>

@Query("""
SELECT id FROM songs
SELECT songs.id FROM songs
LEFT JOIN song_engagements ON CAST(songs.id AS TEXT) = song_engagements.song_id
WHERE source_type = 1
AND (telegram_chat_id = :chatId
OR content_uri_string LIKE 'telegram://' || :chatId || '/%')
Expand Down Expand Up @@ -680,19 +681,21 @@ interface MusicDao {
)
)
ORDER BY
CASE WHEN :sortOrder = 'song_default_order' THEN track_number END ASC,
CASE WHEN :sortOrder = 'song_title_az' THEN title END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'song_title_za' THEN title END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'song_artist' THEN artist_name END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'song_artist_desc' THEN artist_name END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'song_album' THEN album_name END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'song_album_desc' THEN album_name END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'song_date_added' THEN date_added END DESC,
CASE WHEN :sortOrder = 'song_date_added_asc' THEN date_added END ASC,
CASE WHEN :sortOrder = 'song_duration' THEN duration END DESC,
CASE WHEN :sortOrder = 'song_duration_asc' THEN duration END ASC,
title COLLATE NOCASE ASC,
id ASC
CASE WHEN :sortOrder = 'song_default_order' THEN songs.track_number END ASC,
CASE WHEN :sortOrder = 'song_title_az' THEN songs.title END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'song_title_za' THEN songs.title END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'song_artist' THEN songs.artist_name END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'song_artist_desc' THEN songs.artist_name END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'song_album' THEN songs.album_name END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'song_album_desc' THEN songs.album_name END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'song_date_added' THEN songs.date_added END DESC,
CASE WHEN :sortOrder = 'song_date_added_asc' THEN songs.date_added END ASC,
CASE WHEN :sortOrder = 'song_duration' THEN songs.duration END DESC,
CASE WHEN :sortOrder = 'song_duration_asc' THEN songs.duration END ASC,
CASE WHEN :sortOrder = 'song_listening_time' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END DESC,
CASE WHEN :sortOrder = 'song_listening_time_asc' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END ASC,
songs.title COLLATE NOCASE ASC,
songs.id ASC
""")
suspend fun getSongIdsSorted(
allowedParentDirs: List<String>,
Expand All @@ -704,6 +707,7 @@ interface MusicDao {
@Query("""
SELECT songs.id FROM songs
INNER JOIN favorites ON songs.id = favorites.songId AND favorites.isFavorite = 1
LEFT JOIN song_engagements ON CAST(songs.id AS TEXT) = song_engagements.song_id
WHERE (:applyDirectoryFilter = 0 OR songs.id < 0 OR songs.parent_directory_path IN (:allowedParentDirs))
AND (
:filterMode = 0
Expand All @@ -717,14 +721,10 @@ interface MusicDao {
)
)
ORDER BY
CASE WHEN :sortOrder = 'liked_play_time' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END DESC,
CASE WHEN :sortOrder = 'liked_play_time_asc' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END ASC,
CASE WHEN :sortOrder = 'liked_title_az' THEN songs.title END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'liked_title_za' THEN songs.title END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'liked_artist' THEN songs.artist_name END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'liked_artist_desc' THEN songs.artist_name END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'liked_album' THEN songs.album_name END COLLATE NOCASE ASC,
CASE WHEN :sortOrder = 'liked_album_desc' THEN songs.album_name END COLLATE NOCASE DESC,
CASE WHEN :sortOrder = 'liked_date_liked' THEN favorites.timestamp END DESC,
CASE WHEN :sortOrder = 'liked_date_liked_asc' THEN favorites.timestamp END ASC,
songs.title COLLATE NOCASE ASC,
songs.id ASC
""")
Expand All @@ -741,7 +741,8 @@ interface MusicDao {
* Room auto-generates the PagingSource implementation.
*/
@Query("""
SELECT * FROM songs
SELECT songs.* FROM songs
LEFT JOIN song_engagements ON CAST(songs.id AS TEXT) = song_engagements.song_id
WHERE (:applyDirectoryFilter = 0 OR id < 0 OR parent_directory_path IN (:allowedParentDirs))
AND (
:filterMode = 0
Expand All @@ -766,6 +767,8 @@ interface MusicDao {
CASE WHEN :sortOrder = 'song_date_added_asc' THEN date_added END ASC,
CASE WHEN :sortOrder = 'song_duration' THEN duration END DESC,
CASE WHEN :sortOrder = 'song_duration_asc' THEN duration END ASC,
CASE WHEN :sortOrder = 'song_listening_time' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END DESC,
CASE WHEN :sortOrder = 'song_listening_time_asc' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END ASC,

-- Secondary sort falls back to title for consistency (case-insensitive)
title COLLATE NOCASE ASC,
Expand All @@ -781,6 +784,7 @@ interface MusicDao {
@Query("""
SELECT """ + SONG_LIST_PROJECTION + """
FROM songs
LEFT JOIN song_engagements ON CAST(songs.id AS TEXT) = song_engagements.song_id
WHERE (:applyDirectoryFilter = 0 OR id < 0 OR parent_directory_path IN (:allowedParentDirs))
AND (
:filterMode = 0
Expand All @@ -805,6 +809,8 @@ interface MusicDao {
CASE WHEN :sortOrder = 'song_date_added_asc' THEN date_added END ASC,
CASE WHEN :sortOrder = 'song_duration' THEN duration END DESC,
CASE WHEN :sortOrder = 'song_duration_asc' THEN duration END ASC,
CASE WHEN :sortOrder = 'song_listening_time' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END DESC,
CASE WHEN :sortOrder = 'song_listening_time_asc' THEN COALESCE(song_engagements.total_play_duration_ms, 0) END ASC,
title COLLATE NOCASE ASC,
id ASC
LIMIT :limit OFFSET :offset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,24 @@ sealed class SortOption(
methodKey = "song_duration",
direction = SortDirection.Ascending
)
object SongListeningTime : SortOption(
storageKey = "song_listening_time",
displayName = "Listening Time",
displayNameRes = R.string.sort_display_listening_time,
methodLabel = "Listening Time",
methodLabelRes = R.string.sort_method_listening_time,
methodKey = "song_listening_time",
direction = SortDirection.Descending
)
object SongListeningTimeAsc : SortOption(
storageKey = "song_listening_time_asc",
displayName = "Listening Time (Least First)",
displayNameRes = R.string.sort_display_listening_time_least,
methodLabel = "Listening Time",
methodLabelRes = R.string.sort_method_listening_time,
methodKey = "song_listening_time",
direction = SortDirection.Ascending
)

// Album Sort Options
object AlbumTitleAZ : SortOption(
Expand Down Expand Up @@ -442,7 +460,9 @@ sealed class SortOption(
SongDateAdded,
SongDateAddedAsc,
SongDuration,
SongDurationAsc
SongDurationAsc,
SongListeningTime,
SongListeningTimeAsc
)
}

Expand Down Expand Up @@ -539,4 +559,4 @@ sealed class SortOption(
return sanitized.firstOrNull { option -> option.displayName == rawValue } ?: fallback
}
}
}
}
5 changes: 4 additions & 1 deletion app/src/main/res/values/strings_library.xml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@
<string name="sort_display_date_added_oldest">Date Added (Oldest First)</string>
<string name="sort_display_duration">Duration</string>
<string name="sort_display_duration_shortest">Duration (Shortest First)</string>
<string name="sort_display_listening_time">Listening Time</string>
<string name="sort_display_listening_time_least">Listening Time (Least First)</string>
<string name="sort_display_release_year">Release Year</string>
<string name="sort_display_release_year_oldest">Release Year (Oldest First)</string>
<string name="sort_display_fewest_songs">Fewest Songs</string>
Expand All @@ -230,6 +232,7 @@
<string name="sort_method_album">Album</string>
<string name="sort_method_date_added">Date Added</string>
<string name="sort_method_duration">Duration</string>
<string name="sort_method_listening_time">Listening Time</string>
<string name="sort_method_release_year">Release Year</string>
<string name="sort_method_song_count">Song Count</string>
<string name="sort_method_name">Name</string>
Expand Down Expand Up @@ -563,4 +566,4 @@
<string name="ai_state_daily_mix_updated">Daily Mix updated with AI</string>
<string name="ai_state_could_not_update">Could not update: %s</string>
<string name="ai_state_no_songs_for_mix">AI couldn\'t find songs for this mix</string>
</resources>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SortOptionTest {
assertEquals(SortOption.SongTitleAZ, SortOption.SongTitleZA.methodOption())
assertEquals(SortOption.SongArtist, SortOption.SongArtistDesc.methodOption())
assertEquals(SortOption.SongDateAdded, SortOption.SongDateAddedAsc.methodOption())
assertEquals(SortOption.SongListeningTime, SortOption.SongListeningTimeAsc.methodOption())
assertEquals(SortOption.SongDefaultOrder, SortOption.SongDefaultOrder.methodOption())
}

Expand Down Expand Up @@ -39,6 +40,8 @@ class SortOptionTest {
assertEquals(SortOption.SongTitleAZ, SortOption.SongTitleZA.flipDirection())
assertEquals(SortOption.LikedSongDateLikedAsc, SortOption.LikedSongDateLiked.flipDirection())
assertEquals(SortOption.FolderSongCountAsc, SortOption.FolderSongCountDesc.flipDirection())
assertEquals(SortOption.SongListeningTimeAsc, SortOption.SongListeningTime.flipDirection())
assertEquals(SortOption.SongListeningTime, SortOption.SongListeningTimeAsc.flipDirection())
assertEquals(SortOption.SongDefaultOrder, SortOption.SongDefaultOrder.flipDirection())
}

Expand Down