Skip to content

Commit

Permalink
Refactor codebase
Browse files Browse the repository at this point in the history
- Move general classes over to :core:data and :core:ui
- Fix thumbnail size mess
- Reformat codebase
- Fix detekt issues
- Clean up

There should be no user-bound changes
  • Loading branch information
25huizengek1 committed Feb 2, 2024
1 parent e881e62 commit d417339
Show file tree
Hide file tree
Showing 62 changed files with 835 additions and 1,039 deletions.
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>

<intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
</intent-filter>
</service>

<receiver
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/kotlin/it/vfsfitvnm/vimusic/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ class MainActivity : ComponentActivity() {

val playerBottomSheetState = rememberBottomSheetState(
dismissedBound = 0.dp,
collapsedBound = Dimensions.collapsedPlayer + bottomDp,
collapsedBound = Dimensions.items.collapsedPlayerHeight + bottomDp,
expandedBound = maxHeight
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ object PlayerPreferences : GlobalPreferencesHolder() {
var queueLoopEnabled by queueLoopEnabledProperty
val skipSilenceProperty = boolean(false)
var skipSilence by skipSilenceProperty
val minimumSilenceProperty = long(2_000_000L)
var minimumSilence by minimumSilenceProperty
val volumeNormalizationProperty = boolean(false)
var volumeNormalization by volumeNormalizationProperty
val volumeNormalizationBaseGainProperty = float(5.00f)
Expand All @@ -26,28 +24,20 @@ object PlayerPreferences : GlobalPreferencesHolder() {
var bassBoostLevel by bassBoostLevelProperty
val resumePlaybackWhenDeviceConnectedProperty = boolean(false)
var resumePlaybackWhenDeviceConnected by resumePlaybackWhenDeviceConnectedProperty
val persistentQueueProperty = boolean(false)
var persistentQueue by persistentQueueProperty
val isShowingLyricsProperty = boolean(false)
var isShowingLyrics by isShowingLyricsProperty
val isShowingSynchronizedLyricsProperty = boolean(false)
var isShowingSynchronizedLyrics by isShowingSynchronizedLyricsProperty
val speedProperty = float(1f)
var speed by speedProperty
val isShowingPrevButtonCollapsedProperty = boolean(false)
var isShowingPrevButtonCollapsed by isShowingPrevButtonCollapsedProperty
val stopWhenClosedProperty = boolean(false)
var stopWhenClosed by stopWhenClosedProperty
val horizontalSwipeToCloseProperty = boolean(false)
var horizontalSwipeToClose by horizontalSwipeToCloseProperty
val horizontalSwipeToRemoveItemProperty = boolean(false)
var horizontalSwipeToRemoveItem by horizontalSwipeToRemoveItemProperty
val playerLayoutProperty = enum(PlayerLayout.New)
var playerLayout by playerLayoutProperty
val seekBarStyleProperty = enum(SeekBarStyle.Wavy)
var seekBarStyle by seekBarStyleProperty
val showLikeProperty = boolean(false)
var showLike by showLikeProperty

var minimumSilence by long(2_000_000L)
var persistentQueue by boolean(false)
var isShowingLyrics by boolean(false)
var isShowingSynchronizedLyrics by boolean(false)
var isShowingPrevButtonCollapsed by boolean(false)
var stopWhenClosed by boolean(false)
var horizontalSwipeToClose by boolean(false)
var horizontalSwipeToRemoveItem by boolean(false)
var playerLayout by enum(PlayerLayout.New)
var seekBarStyle by enum(SeekBarStyle.Wavy)
var showLike by boolean(false)

enum class PlayerLayout(val displayName: @Composable () -> String) {
Classic(displayName = { stringResource(R.string.classic_player_layout_name) }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ import it.vfsfitvnm.vimusic.GlobalPreferencesHolder
object UIStatePreferences : GlobalPreferencesHolder() {
var homeScreenTabIndex by int(0)
var searchResultScreenTabIndex by int(0)
var artistScreenTabIndex by int(0)

var artistScreenTabIndexProperty = int(0)
var artistScreenTabIndex by artistScreenTabIndexProperty
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
) {
bindService(intent<PlayerService>(), this, Context.BIND_AUTO_CREATE)
BrowserRoot(
MediaId.ROOT,
MediaId.ROOT.id,
bundleOf("android.media.browse.CONTENT_STYLE_BROWSABLE_HINT" to 1)
)
} else null
Expand All @@ -74,7 +74,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
result: Result<MutableList<BrowserMediaItem>>
) = runBlocking(Dispatchers.IO) {
result.sendResult(
when (parentId) {
when (MediaId(parentId)) {
MediaId.ROOT -> mutableListOf(
songsBrowserMediaItem,
playlistsBrowserMediaItem,
Expand Down Expand Up @@ -126,7 +126,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val shuffleBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.SHUFFLE)
.setMediaId(MediaId.SHUFFLE.id)
.setTitle(getString(R.string.shuffle))
.setIconUri(uriFor(R.drawable.shuffle))
.build(),
Expand All @@ -136,7 +136,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val songsBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.SONGS)
.setMediaId(MediaId.SONGS.id)
.setTitle(getString(R.string.songs))
.setIconUri(uriFor(R.drawable.musical_notes))
.build(),
Expand All @@ -146,7 +146,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val playlistsBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.PLAYLISTS)
.setMediaId(MediaId.PLAYLISTS.id)
.setTitle(getString(R.string.playlists))
.setIconUri(uriFor(R.drawable.playlist))
.build(),
Expand All @@ -156,7 +156,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val albumsBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.ALBUMS)
.setMediaId(MediaId.ALBUMS.id)
.setTitle(getString(R.string.albums))
.setIconUri(uriFor(R.drawable.disc))
.build(),
Expand All @@ -166,7 +166,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val favoritesBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.FAVORITES)
.setMediaId(MediaId.FAVORITES.id)
.setTitle(getString(R.string.favorites))
.setIconUri(uriFor(R.drawable.heart))
.build(),
Expand All @@ -176,7 +176,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val offlineBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.OFFLINE)
.setMediaId(MediaId.OFFLINE.id)
.setTitle(getString(R.string.offline))
.setIconUri(uriFor(R.drawable.airplane))
.build(),
Expand All @@ -186,7 +186,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val Song.asBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.forSong(id))
.setMediaId((MediaId.SONGS / id).id)
.setTitle(title)
.setSubtitle(artistsText)
.setIconUri(thumbnailUrl?.toUri())
Expand All @@ -197,7 +197,7 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val PlaylistPreview.asBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.forPlaylist(playlist.id))
.setMediaId((MediaId.PLAYLISTS / playlist.id.toString()).id)
.setTitle(playlist.name)
.setSubtitle(resources.getQuantityString(R.plurals.song_count_plural, songCount, songCount))
.setIconUri(uriFor(R.drawable.playlist))
Expand All @@ -208,32 +208,31 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {
private val Album.asBrowserMediaItem
inline get() = BrowserMediaItem(
BrowserMediaDescription.Builder()
.setMediaId(MediaId.forAlbum(id))
.setMediaId((MediaId.ALBUMS / id).id)
.setTitle(title)
.setSubtitle(authorsText)
.setIconUri(thumbnailUrl?.toUri())
.build(),
BrowserMediaItem.FLAG_PLAYABLE
)

private inner class SessionCallback(private val binder: PlayerService.Binder) :
MediaSession.Callback() {
private val player = binder.player

override fun onPlay() = player.play()
override fun onPause() = player.pause()
override fun onSkipToPrevious() = player.forceSeekToPrevious()
override fun onSkipToNext() = player.forceSeekToNext()
override fun onSeekTo(pos: Long) = player.seekTo(pos)
override fun onSkipToQueueItem(id: Long) = player.seekToDefaultPosition(id.toInt())
private inner class SessionCallback(
private val binder: PlayerService.Binder
) : MediaSession.Callback() {
override fun onPlay() = binder.player.play()
override fun onPause() = binder.player.pause()
override fun onSkipToPrevious() = binder.player.forceSeekToPrevious()
override fun onSkipToNext() = binder.player.forceSeekToNext()
override fun onSeekTo(pos: Long) = binder.player.seekTo(pos)
override fun onSkipToQueueItem(id: Long) = binder.player.seekToDefaultPosition(id.toInt())

@OptIn(UnstableApi::class)
override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
val data = mediaId?.split('/') ?: return
var index = 0

coroutineScope.launch {
val mediaItems = when (data.getOrNull(0)) {
val mediaItems = when (data.getOrNull(0)?.let { MediaId(it) }) {
MediaId.SHUFFLE -> lastSongs

MediaId.SONGS -> data.getOrNull(1)?.let { songId ->
Expand All @@ -243,55 +242,59 @@ class PlayerMediaBrowserService : MediaBrowserService(), ServiceConnection {

MediaId.FAVORITES ->
Database
.favorites()
.first()
.shuffled()
.favorites()
.first()
.shuffled()

MediaId.OFFLINE ->
Database
.songsWithContentLength()
.first()
.filter { binder.isCached(it) }
.map(SongWithContentLength::song)
.shuffled()
.songsWithContentLength()
.first()
.filter { binder.isCached(it) }
.map(SongWithContentLength::song)
.shuffled()

MediaId.PLAYLISTS ->
data
.getOrNull(1)
?.toLongOrNull()
?.let(Database::playlistWithSongs)
?.first()
?.songs
?.shuffled()
.getOrNull(1)
?.toLongOrNull()
?.let(Database::playlistWithSongs)
?.first()
?.songs
?.shuffled()

MediaId.ALBUMS ->
data
.getOrNull(1)
?.let(Database::albumSongs)
?.first()
.getOrNull(1)
?.let(Database::albumSongs)
?.first()

else -> emptyList()
}?.map(Song::asMediaItem) ?: return@launch

withContext(Dispatchers.Main) {
player.forcePlayAtIndex(mediaItems, index.coerceIn(0, mediaItems.size))
binder.player.forcePlayAtIndex(
items = mediaItems,
index = index.coerceIn(0, mediaItems.size)
)
}
}
}
}

private object MediaId {
const val ROOT = "root"
const val SONGS = "songs"
const val PLAYLISTS = "playlists"
const val ALBUMS = "albums"

const val FAVORITES = "favorites"
const val OFFLINE = "offline"
const val SHUFFLE = "shuffle"
@JvmInline
private value class MediaId(val id: String) : CharSequence by id {
companion object {
val ROOT = MediaId("root")
val SONGS = MediaId("songs")
val PLAYLISTS = MediaId("playlists")
val ALBUMS = MediaId("albums")

val FAVORITES = MediaId("favorites")
val OFFLINE = MediaId("offline")
val SHUFFLE = MediaId("shuffle")
}

fun forSong(id: String) = "songs/$id"
fun forPlaylist(id: Long) = "playlists/$id"
fun forAlbum(id: String) = "albums/$id"
operator fun div(other: String) = MediaId("$id/$other")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
}
}

@Suppress("ReturnCount")
private fun maybeNormalizeVolume() {
if (!PlayerPreferences.volumeNormalization) {
loudnessEnhancer?.enabled = false
Expand Down Expand Up @@ -1123,11 +1124,11 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
chunkLength ?: DEFAULT_CHUNK_LENGTH
) -> dataSpec

videoId == ringBuffer.getOrNull(0)?.first ->
dataSpec.withUri(ringBuffer.getOrNull(0)!!.second)
videoId == ringBuffer[0]?.first ->
dataSpec.withUri(ringBuffer[0]!!.second)

videoId == ringBuffer.getOrNull(1)?.first ->
dataSpec.withUri(ringBuffer.getOrNull(1)!!.second)
videoId == ringBuffer[1]?.first ->
dataSpec.withUri(ringBuffer[1]!!.second)

else -> {
val body = runBlocking(Dispatchers.IO) {
Expand Down Expand Up @@ -1181,7 +1182,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
)
}

ringBuffer.append(videoId to url.toUri())
ringBuffer += videoId to url.toUri()
dataSpec.buildUpon()
.setKey(videoId)
.setUri(url.toUri())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import androidx.media3.datasource.cache.Cache
import androidx.media3.datasource.cache.CacheSpan
import androidx.media3.datasource.cache.ContentMetadataMutations
import androidx.media3.exoplayer.offline.Download
import androidx.media3.exoplayer.offline.DownloadCursor
import androidx.media3.exoplayer.offline.DownloadManager
import androidx.media3.exoplayer.offline.DownloadNotificationHelper
import androidx.media3.exoplayer.offline.DownloadRequest
Expand Down Expand Up @@ -41,7 +40,6 @@ import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.internal.closeQuietly
import java.io.File
import java.util.concurrent.Executors
import kotlin.coroutines.resume
Expand Down Expand Up @@ -268,11 +266,3 @@ class BlockingDeferredCache(private val cache: Deferred<Cache>) : Cache {

override fun getContentMetadata(key: String) = resolvedCache.getContentMetadata(key)
}

@OptIn(UnstableApi::class)
fun <T> DownloadCursor.toList(map: (Download) -> T) = buildList {
while (moveToNext()) {
add(map(download))
}
closeQuietly()
}
Loading

0 comments on commit d417339

Please sign in to comment.