Skip to content

Commit

Permalink
refactor: load cover by backend directly
Browse files Browse the repository at this point in the history
  • Loading branch information
hpp2334 committed Nov 21, 2024
1 parent fbb8235 commit f401790
Show file tree
Hide file tree
Showing 28 changed files with 253 additions and 198 deletions.
4 changes: 1 addition & 3 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ android {
minSdk = 29
targetSdk = 34
versionCode = 1
versionName = "0.2.0-beta.0"
versionName = "0.2.0-beta.2"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down Expand Up @@ -118,8 +118,6 @@ dependencies {
implementation("androidx.navigation:navigation-compose:$nav_version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("io.coil-kt.coil3:coil-compose:3.0.0-rc02")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.0-rc02")
implementation("androidx.media3:media3-exoplayer:$media3_version")
implementation("androidx.media3:media3-exoplayer-dash:$media3_version")
implementation("androidx.media3:media3-session:$media3_version")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.layout.ContentScale
import com.kutedev.easemusicplayer.core.UIBridgeController
import uniffi.ease_client_shared.DataSourceKey

@Composable
fun EaseImage(
modifier: Modifier = Modifier,
dataSourceKey: DataSourceKey,
contentScale: ContentScale
) {
val bridge = UIBridgeController.current
var bitmap by remember { mutableStateOf<ImageBitmap?>(null) }

LaunchedEffect(dataSourceKey) {
val data = bridge.bitmapDataSources.load(dataSourceKey)
bitmap = data
}

if (bitmap == null) {
return
}

Image(
modifier = modifier,
bitmap = bitmap!!,
contentDescription = null,
contentScale = contentScale,
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kutedev.easemusicplayer.components

import EaseImage
import android.provider.CalendarContract.Colors
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
Expand Down Expand Up @@ -29,16 +30,16 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil3.compose.AsyncImage
import com.kutedev.easemusicplayer.R
import uniffi.ease_client_shared.DataSourceKey

@Composable
fun ImportCover(
url: String,
dataSourceKey: DataSourceKey?,
onAdd: () -> Unit,
onRemove: () -> Unit,
) {
if (url.isNotEmpty()) {
if (dataSourceKey != null) {
Box(
modifier = Modifier
.size(90.dp)
Expand All @@ -50,9 +51,8 @@ fun ImportCover(
.width(80.dp)
.height(80.dp)
) {
AsyncImage(
model = url,
contentDescription = null,
EaseImage(
dataSourceKey = dataSourceKey,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.FillWidth
)
Expand Down Expand Up @@ -105,26 +105,4 @@ fun ImportCover(
}
}
}
}

@Preview
@Composable
private fun ImportCoverPreview() {
var url by remember { mutableStateOf("") }

Box(
modifier = Modifier
.offset(20.dp, 20.dp)
.size(300.dp),
) {
ImportCover(
url = url,
onAdd = {
url = "https://upload.wikimedia.org/wikipedia/commons/b/b6/WikiWiki.jpg"
},
onRemove = {
url = ""
}
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kutedev.easemusicplayer.components

import EaseImage
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
Expand All @@ -9,29 +10,27 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import coil3.compose.AsyncImage
import com.kutedev.easemusicplayer.R
import uniffi.ease_client_shared.DataSourceKey

@Composable
fun MusicCover(
modifier: Modifier,
coverUrl: String,
coverDataSourceKey: DataSourceKey?
) {
Box(
modifier = modifier,
) {
if (coverUrl.isEmpty()) {
if (coverDataSourceKey == null) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.cover_default_image), // Replace with actual image resource
contentDescription = null,
)
} else {
AsyncImage(
EaseImage(
modifier = Modifier.background(MaterialTheme.colorScheme.onSurfaceVariant).fillMaxSize(),
model = coverUrl,
contentDescription = null,
dataSourceKey = coverDataSourceKey,
contentScale = ContentScale.FillWidth,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ private class EaseMusicPlayerDelegate : IPlayerDelegateForeign {
override fun setMusicUrl(item: MusicToPlay) {
val player = _internal ?: return

val coverURI = if (item.coverUrl.isNotEmpty()) {
Uri.parse(item.coverUrl)
val coverURI = if (item.hasCover) {
null
} else {
Uri.parse(DEFAULT_COVER_BASE64)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import android.content.ComponentName
import android.content.pm.PackageManager
import android.os.Build
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import androidx.navigation.NavHostController
import com.google.common.util.concurrent.MoreExecutors
import com.kutedev.easemusicplayer.utils.nextTickOnMain
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import uniffi.ease_client_android.IPermissionServiceForeign
import uniffi.ease_client_android.IRouterServiceForeign
import uniffi.ease_client_android.IToastServiceForeign
Expand Down Expand Up @@ -40,8 +45,10 @@ import uniffi.ease_client_android.IAsyncAdapterForeign
import uniffi.ease_client_android.apiBuildClient
import uniffi.ease_client_android.apiDestroyClient
import uniffi.ease_client_android.apiEmitViewAction
import uniffi.ease_client_android.apiLoadAsset
import uniffi.ease_client_android.apiStartClient
import uniffi.ease_client_shared.ArgInitializeApp
import uniffi.ease_client_shared.DataSourceKey


interface IOnNotifyView {
Expand Down Expand Up @@ -126,7 +133,45 @@ private class PermissionService : IPermissionServiceForeign {
this.requestPermissionLauncher?.launch(READ_EXTERNAL_STORAGE)
}
}
}

class BitmapDataSources {
class K(key: DataSourceKey) {
private val _key = key;

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is K) return false

if (this._key is DataSourceKey.Music && other._key is DataSourceKey.Music) {
return this._key.id == other._key.id
}
if (this._key is DataSourceKey.Cover && other._key is DataSourceKey.Cover) {
return this._key.id == other._key.id
}
if (this._key is DataSourceKey.AnyEntry && other._key is DataSourceKey.AnyEntry) {
return this._key.entry.storageId == other._key.entry.storageId && this._key.entry.path == other._key.entry.path;
}
return false;
}
}

private val _map = HashMap<K, ImageBitmap?>()

suspend fun load(key: DataSourceKey): ImageBitmap? {
val cached = this._map[K(key)]
if (cached != null) {
return null
}

val data = apiLoadAsset(key)
val decoded = data?.let {
val bitmap = android.graphics.BitmapFactory.decodeByteArray(it, 0, it.size)
bitmap?.asImageBitmap()
}
this._map[K(key)] = decoded
return decoded
}
}

class UIBridge {
Expand All @@ -141,6 +186,7 @@ class UIBridge {
private val _permissionService = PermissionService()
private var _playerController: MediaController? = null
private var _executingAction = false
val bitmapDataSources = BitmapDataSources()

fun onBackendConnected() {
apiStartClient(this._handle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ val DefaultCurrentPlaylistState =
items = emptyList(),
title = "",
duration = "",
coverUrl = ""
cover = null,
)
val DefaultCurrentMusicState =
VCurrentMusicState(
Expand All @@ -53,9 +53,9 @@ val DefaultCurrentMusicState =
canChangePosition = false,
canPlayNext = false,
canPlayPrevious = false,
previousCover = "",
nextCover = "",
cover = "",
previousCover = null,
nextCover = null,
cover = null,
playMode = PlayMode.SINGLE,
playing = false,
lyricIndex = 0,
Expand Down Expand Up @@ -102,14 +102,14 @@ val DefaultCreatePlaylistState =
VCreatePlaylistState(
mode = CreatePlaylistMode.FULL,
name = "",
picture = "",
picture = null,
musicCount = 0u,
recommendPlaylistNames = emptyList(),
fullImported = false,
modalOpen = false,
canSubmit = false
)
val DefaultEditPlaylistState = VEditPlaylistState(name = "", picture = "", modalOpen = false)
val DefaultEditPlaylistState = VEditPlaylistState(name = "", picture = null, modalOpen = false)
val DefaultCurrentMusicLyricState =
VCurrentMusicLyricState(lyricLines = listOf(), loadState = LyricLoadState.LOADING)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
Expand Down Expand Up @@ -37,12 +36,13 @@ import com.kutedev.easemusicplayer.core.UIBridgeController
import com.kutedev.easemusicplayer.viewmodels.EaseViewModel
import uniffi.ease_client.MainBodyWidget
import uniffi.ease_client.MusicControlWidget
import uniffi.ease_client_shared.DataSourceKey

@Composable
private fun MiniPlayerCore(
isPlaying: Boolean,
title: String,
coverUrl: String,
cover: DataSourceKey?,
currentDurationMS: ULong,
totalDuration: String,
totalDurationMS: ULong,
Expand All @@ -62,7 +62,7 @@ private fun MiniPlayerCore(
modifier = Modifier
.clip(RoundedCornerShape(10.dp))
.size(60.dp),
coverUrl = coverUrl,
coverDataSourceKey = cover,
)
Box(modifier = Modifier.width(16.dp))
Column(
Expand Down Expand Up @@ -152,7 +152,7 @@ fun MiniPlayer(
MiniPlayerCore(
isPlaying = state.playing,
title = state.title,
coverUrl = state.cover,
cover = state.cover,
currentDurationMS = state.currentDurationMs,
totalDuration = state.totalDuration,
totalDurationMS = state.totalDurationMs,
Expand All @@ -171,7 +171,7 @@ private fun MiniPlayerPreview() {
MiniPlayerCore(
isPlaying = true,
title = "Very very very very very long music title",
coverUrl = "",
cover = null,
currentDurationMS = 10uL,
totalDuration = "00:06",
totalDurationMS = 60uL,
Expand Down
Loading

0 comments on commit f401790

Please sign in to comment.