From 98a3b05f1a117c7a1d89c6c6f499910a5ae48a15 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Thu, 26 May 2022 19:02:41 +0300 Subject: [PATCH 01/16] Shrinking purpose --- .../rld/justlisten/android/di/ServiceModule.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt b/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt index 04ca6ab..1b5dff1 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt @@ -3,7 +3,10 @@ package com.rld.justlisten.android.di import android.content.Context import com.google.android.exoplayer2.C import com.google.android.exoplayer2.ExoPlayer +import com.google.android.exoplayer2.RenderersFactory import com.google.android.exoplayer2.audio.AudioAttributes +import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer +import com.google.android.exoplayer2.mediacodec.MediaCodecSelector import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -11,6 +14,7 @@ import dagger.hilt.android.components.ServiceComponent import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.scopes.ServiceScoped + @Module @InstallIn(ServiceComponent::class) object ServiceModule { @@ -21,7 +25,8 @@ object ServiceModule { fun provideExoPlayer( @ApplicationContext context: Context, audioAttributes: AudioAttributes, - ) = ExoPlayer.Builder(context).build().apply { + renderersFactory: RenderersFactory + ) = ExoPlayer.Builder(context, renderersFactory).build().apply { setAudioAttributes(audioAttributes, true) setHandleAudioBecomingNoisy(true) } @@ -32,4 +37,15 @@ object ServiceModule { .setContentType(C.CONTENT_TYPE_MUSIC) .setUsage(C.USAGE_MEDIA) .build() + + @Provides + @ServiceScoped + fun provideRenderFactory(@ApplicationContext context: Context) = + RenderersFactory { handler, _, audioListener, _, _ -> + arrayOf( + MediaCodecAudioRenderer( + context, MediaCodecSelector.DEFAULT, handler, audioListener + ) + ) + } } \ No newline at end of file From f0d95359e24e5d1031158e5ffac4d7059c46fb71 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Thu, 26 May 2022 19:02:51 +0300 Subject: [PATCH 02/16] rename of app --- .../java/com/rld/justlisten/android/exoplayer/MusicSource.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicSource.kt b/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicSource.kt index b853d47..879044e 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicSource.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicSource.kt @@ -5,6 +5,7 @@ import android.support.v4.media.MediaMetadataCompat import com.rld.justlisten.android.exoplayer.State.* import com.rld.justlisten.android.exoplayer.library.extension.* import com.rld.justlisten.datalayer.utils.Constants.BASEURL +import com.rld.justlisten.datalayer.utils.Constants.appName import com.rld.justlisten.viewmodel.interfaces.Item class MusicSource { @@ -75,7 +76,7 @@ class MusicSource { } private fun setSongUrl(songId: String): String { - return "${BASEURL}/v1/tracks/${songId}/stream?app_name=EXAMPLEAPP" + return "${BASEURL}/v1/tracks/${songId}/stream?app_name=$appName" } } From 8e8f9ea96be199ea9322c175f0ab2a4b8d952498 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Thu, 26 May 2022 20:47:50 +0300 Subject: [PATCH 03/16] Caching to save data --- .../justlisten/android/di/ServiceModule.kt | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt b/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt index 1b5dff1..aeb1b7e 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt @@ -6,13 +6,22 @@ import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.RenderersFactory import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer +import com.google.android.exoplayer2.database.DatabaseProvider +import com.google.android.exoplayer2.database.StandaloneDatabaseProvider import com.google.android.exoplayer2.mediacodec.MediaCodecSelector +import com.google.android.exoplayer2.source.DefaultMediaSourceFactory +import com.google.android.exoplayer2.upstream.DefaultHttpDataSource +import com.google.android.exoplayer2.upstream.HttpDataSource +import com.google.android.exoplayer2.upstream.cache.CacheDataSource +import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor +import com.google.android.exoplayer2.upstream.cache.SimpleCache import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.components.ServiceComponent import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.scopes.ServiceScoped +import java.io.File @Module @@ -25,8 +34,10 @@ object ServiceModule { fun provideExoPlayer( @ApplicationContext context: Context, audioAttributes: AudioAttributes, - renderersFactory: RenderersFactory - ) = ExoPlayer.Builder(context, renderersFactory).build().apply { + renderersFactory: RenderersFactory, + cacheDataSourceFactory: CacheDataSource.Factory + ) = ExoPlayer.Builder(context, renderersFactory) + .setMediaSourceFactory(DefaultMediaSourceFactory(cacheDataSourceFactory)).build().apply { setAudioAttributes(audioAttributes, true) setHandleAudioBecomingNoisy(true) } @@ -48,4 +59,20 @@ object ServiceModule { ) ) } + + @Provides + @ServiceScoped + fun provideCacheFactory(@ApplicationContext context: Context): CacheDataSource.Factory { + + val httpDataSourceFactory: HttpDataSource.Factory = + DefaultHttpDataSource.Factory() + + val evictor = LeastRecentlyUsedCacheEvictor((100 * 1024 * 1024).toLong()) + val databaseProvider: DatabaseProvider = StandaloneDatabaseProvider(context) + + val simpleCache = SimpleCache(File(context.cacheDir, "media"), evictor, databaseProvider) + + return CacheDataSource.Factory().setCache(simpleCache) + .setUpstreamDataSourceFactory(httpDataSourceFactory) + } } \ No newline at end of file From 7644d44ce9cdc1125b567592871bd9c6b70ac7be Mon Sep 17 00:00:00 2001 From: laurentiu Date: Thu, 26 May 2022 21:34:41 +0300 Subject: [PATCH 04/16] lower caching --- .../main/java/com/rld/justlisten/android/di/ServiceModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt b/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt index aeb1b7e..e95d8aa 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/di/ServiceModule.kt @@ -67,7 +67,7 @@ object ServiceModule { val httpDataSourceFactory: HttpDataSource.Factory = DefaultHttpDataSource.Factory() - val evictor = LeastRecentlyUsedCacheEvictor((100 * 1024 * 1024).toLong()) + val evictor = LeastRecentlyUsedCacheEvictor((50 * 1024 * 1024).toLong()) val databaseProvider: DatabaseProvider = StandaloneDatabaseProvider(context) val simpleCache = SimpleCache(File(context.cacheDir, "media"), evictor, databaseProvider) From 71d0576124680cef462fc28dc683fea24dece48a Mon Sep 17 00:00:00 2001 From: laurentiu Date: Fri, 27 May 2022 22:59:08 +0300 Subject: [PATCH 05/16] quick fix for continuous loading --- .../datalayer/webservices/ApiClient.kt | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt b/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt index 26aa695..17684aa 100644 --- a/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt +++ b/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt @@ -5,12 +5,14 @@ import com.rld.justlisten.datalayer.utils.Constants.listOfBaseUrls import com.rld.justlisten.datalayer.utils.Constants.usedBasedUrl import com.rld.justlisten.datalayer.webservices.apis.playlistcalls.PlayListResponse import io.ktor.client.* +import io.ktor.client.features.* import io.ktor.client.features.json.JsonFeature import io.ktor.client.features.json.serializer.* import io.ktor.client.request.* import kotlinx.coroutines.delay import kotlinx.datetime.Clock import kotlinx.serialization.json.Json +import kotlin.collections.set import kotlin.random.Random class ApiClient { @@ -19,17 +21,21 @@ class ApiClient { install(JsonFeature) { serializer = KotlinxSerializer(Json { ignoreUnknownKeys = true - }) } + install(HttpTimeout) { + requestTimeoutMillis = 3000 + } } suspend inline fun getResponse(endpoint: String): T? { var numberOfCalls = 0 var wasSuccessful = false - while (numberOfCalls < 10 && !wasSuccessful) { - val baseUrl = usedBasedUrl["goodBaseUrl"] ?: listOfBaseUrls[Random.nextInt(0, listOfBaseUrls.size)] + while (numberOfCalls < 15 && !wasSuccessful) { + val random = + Random(Clock.System.now().toEpochMilliseconds()).nextInt(0, listOfBaseUrls.size) + val baseUrl = usedBasedUrl["goodBaseUrl"] ?: listOfBaseUrls[random] val url = "${baseUrl}/v1$endpoint" try { val firstTime = Clock.System.now().nanosecondsOfSecond @@ -37,16 +43,20 @@ class ApiClient { when (response) { is PlayListResponse -> wasSuccessful = response.error.isNullOrEmpty() } - if (wasSuccessful){ + if (wasSuccessful) { val secondTime = Clock.System.now().nanosecondsOfSecond val responseTime = secondTime - firstTime val savedBestResponseTime = bestResponseTime["goodBaseUrl"] ?: Int.MAX_VALUE - bestResponseTime["goodBaseUrl"] = if (savedBestResponseTime > responseTime) responseTime else savedBestResponseTime - usedBasedUrl["goodBaseUrl"] = if (bestResponseTime["goodBaseUrl"] == responseTime) baseUrl else usedBasedUrl["goodBaseUrl"] ?: baseUrl - return response } + bestResponseTime["goodBaseUrl"] = + if (savedBestResponseTime > responseTime) responseTime else savedBestResponseTime + usedBasedUrl["goodBaseUrl"] = + if (bestResponseTime["goodBaseUrl"] == responseTime) baseUrl else usedBasedUrl["goodBaseUrl"] + ?: baseUrl + return response + } } catch (e: Exception) { delay(10) - numberOfCalls +=1 + numberOfCalls += 1 } } return null From 949943176a92eb073c30975c6af0a474f5cdab88 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sat, 28 May 2022 10:36:34 +0300 Subject: [PATCH 06/16] Added shimmer effect for playlists --- androidApp/build.gradle.kts | 2 +- .../android/ui/components/AnimatedShimmer.kt | 53 +++++++++++++++++++ .../components/PlaylistRowItem.kt | 52 +++++++++--------- .../rld/justlisten/android/ui/theme/Theme.kt | 4 +- 4 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index 4da8194..ba15c5d 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { implementation("androidx.lifecycle:lifecycle-process:2.4.1") - implementation("io.coil-kt:coil-compose:2.0.0") + implementation("io.coil-kt:coil-compose:2.1.0") implementation("com.google.dagger:hilt-android:2.38.1") kapt("com.google.dagger:hilt-android-compiler:2.38.1") implementation ("com.github.bumptech.glide:glide:4.12.0") diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt new file mode 100644 index 0000000..3472bbc --- /dev/null +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt @@ -0,0 +1,53 @@ +package com.rld.justlisten.android.ui.components + +import androidx.compose.animation.core.* +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.unit.Dp + +@Composable +fun AnimatedShimmer(width: Dp, height: Dp) { + val shimmerColors = listOf( + MaterialTheme.colors.onSurface.copy(alpha = 0.6f), + MaterialTheme.colors.onSurface.copy(alpha = 0.2f), + MaterialTheme.colors.onSurface.copy(alpha = 0.6f), + ) + + val transition = rememberInfiniteTransition() + val translateAnim = transition.animateFloat( + initialValue = 0f, + targetValue = 1000f, + animationSpec = infiniteRepeatable( + animation = tween( + durationMillis = 1000, + easing = FastOutSlowInEasing + ), + repeatMode = RepeatMode.Reverse + ) + ) + + val brush = Brush.linearGradient( + colors = shimmerColors, + start = Offset.Zero, + end = Offset(x = translateAnim.value, y = translateAnim.value) + ) + + ShimmerGridItem(brush = brush, width, height) +} + +@Composable +fun ShimmerGridItem(brush: Brush, width: Dp, height: Dp) { + Box( + modifier = Modifier + .width(width) + .height(height) + .background(brush) + ) +} \ No newline at end of file diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt index 8656de7..3c12b00 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt @@ -1,27 +1,28 @@ package com.rld.justlisten.android.ui.playlistscreen.components -import android.graphics.drawable.ColorDrawable -import androidx.compose.foundation.Image import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.material.MaterialTheme +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.material.Text -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import coil.compose.rememberAsyncImagePainter +import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest +import com.rld.justlisten.android.ui.components.AnimatedShimmer import com.rld.justlisten.android.ui.theme.typography import com.rld.justlisten.viewmodel.screens.playlist.PlaylistItem @Composable fun PlaylistRowItem( playlistItem: PlaylistItem, - onPlaylistClicked: (String, String, String, String, Boolean) -> Unit) { + onPlaylistClicked: (String, String, String, String, Boolean) -> Unit +) { Column( modifier = Modifier @@ -31,30 +32,31 @@ fun PlaylistRowItem( onClick = { }) ) { - val request = ImageRequest.Builder(context = LocalContext.current) - .placeholder(ColorDrawable(MaterialTheme.colors.secondaryVariant.toArgb())) - .data(playlistItem.songIconList.songImageURL480px).build() - val painter = rememberAsyncImagePainter(model = request) - Image( - painter = painter, + SubcomposeAsyncImage(model = ImageRequest.Builder(LocalContext.current) + .data(playlistItem.songIconList.songImageURL480px) + .crossfade(true) + .build(), modifier = Modifier .width(180.dp) .height(160.dp) - .clickable( - onClick = { - onPlaylistClicked( - playlistItem.id, - playlistItem.songIconList.songImageURL480px, - playlistItem.user, - playlistItem.playlistTitle, - playlistItem.isFavorite - ) - } + .clickable(onClick = { + onPlaylistClicked( + playlistItem.id, + playlistItem.songIconList.songImageURL480px, + playlistItem.user, + playlistItem.playlistTitle, + playlistItem.isFavorite + ) + } ), contentDescription = null, - contentScale = ContentScale.Crop + contentScale = ContentScale.Crop, + loading = { + AnimatedShimmer(180.dp, 160.dp) + } ) + Text( text = "${playlistItem.playlistTitle}: by ${playlistItem.user}", style = typography.subtitle2, diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/Theme.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/Theme.kt index afd6ac2..fbbc5ef 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/Theme.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/Theme.kt @@ -45,7 +45,7 @@ private val LightPurpleColorPalette = lightColors( secondary = secondaryPurple, secondaryVariant = secondaryPurpleDark, background = Color.White, - surface = Color.White, + surface = Color.LightGray, onPrimary = Color.White, onSecondary = Color.Black, onBackground = Color.Black, @@ -106,7 +106,7 @@ private val LightGreenColorPalette = lightColors( primaryVariant = green700, secondary = teal200, background = Color.White, - surface = Color.White, + surface = Color.LightGray, onPrimary = Color.White, onSecondary = Color.Black, onBackground = Color.Black, From 45d517bf85fcf9bf051d3da5266ff5e29f5e833d Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sat, 28 May 2022 11:01:10 +0300 Subject: [PATCH 07/16] Added shimmer effect for songs list --- .../components/SongListItem.kt | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistdetailscreen/components/SongListItem.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistdetailscreen/components/SongListItem.kt index e6b51d3..16f1966 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistdetailscreen/components/SongListItem.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistdetailscreen/components/SongListItem.kt @@ -1,35 +1,37 @@ package com.rld.justlisten.android.ui.playlistdetailscreen.components -import android.graphics.drawable.ColorDrawable -import androidx.compose.foundation.Image import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme.typography import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.outlined.FavoriteBorder -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import coil.annotation.ExperimentalCoilApi -import coil.compose.rememberAsyncImagePainter +import coil.compose.SubcomposeAsyncImage +import coil.request.CachePolicy import coil.request.ImageRequest +import com.rld.justlisten.android.ui.components.AnimatedShimmer import com.rld.justlisten.datalayer.models.SongIconList import com.rld.justlisten.datalayer.models.UserModel import com.rld.justlisten.viewmodel.screens.playlist.PlaylistItem -@OptIn(ExperimentalCoilApi::class) @Composable fun SongListItem( playlistItem: PlaylistItem, onSongClicked: (String) -> Unit, @@ -45,19 +47,19 @@ fun SongListItem( ), verticalAlignment = Alignment.CenterVertically, ) { - val painter = rememberAsyncImagePainter( - model = ImageRequest.Builder(context = LocalContext.current) - .placeholder(ColorDrawable(MaterialTheme.colors.secondaryVariant.toArgb())) - .data(playlistItem.songIconList.songImageURL150px).allowHardware(false).build() - ) - - Image( - painter = painter, + SubcomposeAsyncImage(model = ImageRequest.Builder(LocalContext.current) + .data(playlistItem.songIconList.songImageURL150px) + .memoryCachePolicy(CachePolicy.ENABLED) + .diskCachePolicy(CachePolicy.ENABLED) + .build(), contentDescription = null, contentScale = ContentScale.Crop, modifier = Modifier .size(55.dp) - .padding(4.dp) + .padding(4.dp), + loading = { + AnimatedShimmer(width = 55.dp, height = 55.dp) + } ) Column( modifier = Modifier From 2d5a11f36653589ccdb67cb3a1776ce844ed5e61 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sat, 28 May 2022 13:06:05 +0300 Subject: [PATCH 08/16] shimmer change --- .../rld/justlisten/android/ui/components/AnimatedShimmer.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt index 3472bbc..68b6de1 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/components/AnimatedShimmer.kt @@ -15,9 +15,9 @@ import androidx.compose.ui.unit.Dp @Composable fun AnimatedShimmer(width: Dp, height: Dp) { val shimmerColors = listOf( + MaterialTheme.colors.onSurface.copy(alpha = 0.4f), MaterialTheme.colors.onSurface.copy(alpha = 0.6f), - MaterialTheme.colors.onSurface.copy(alpha = 0.2f), - MaterialTheme.colors.onSurface.copy(alpha = 0.6f), + MaterialTheme.colors.onSurface.copy(alpha = 0.4f), ) val transition = rememberInfiniteTransition() From 782eedcc06c2f253273d49deddff8fc948d9db55 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sat, 28 May 2022 14:18:42 +0300 Subject: [PATCH 09/16] update status bar color when extended --- .../rld/justlisten/android/MainActivity.kt | 21 +++++-- .../justlisten/android/ui/MainComposable.kt | 6 +- .../com/rld/justlisten/android/ui/OnePane.kt | 14 +++-- .../com/rld/justlisten/android/ui/Router.kt | 20 +++++-- .../ui/bottombars/playbar/PlayerBottomBar.kt | 6 +- .../playbar/components/PlayBarSwipeActions.kt | 56 ++++++++++--------- 6 files changed, 80 insertions(+), 43 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/MainActivity.kt b/androidApp/src/main/java/com/rld/justlisten/android/MainActivity.kt index 56e2e30..90f206e 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/MainActivity.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/MainActivity.kt @@ -9,8 +9,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.graphics.toArgb import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import com.rld.justlisten.android.ui.MainComposable -import com.rld.justlisten.android.ui.theme.JustListenTheme import com.rld.justlisten.android.ui.theme.ColorPallet +import com.rld.justlisten.android.ui.theme.JustListenTheme import com.rld.justlisten.android.ui.utils.getColorPallet import com.rld.justlisten.datalayer.datacalls.settings.getSettingsInfo @@ -31,15 +31,24 @@ class MainActivity : ComponentActivity() { darkTheme = settingsInfo.value.isDarkThemeOn, colorPallet = getColorPallet(settingsInfo.value.palletColor) ) { - window.statusBarColor = if (getColorPallet(settingsInfo.value.palletColor) == ColorPallet.Dark) MaterialTheme.colors.background.toArgb() - else MaterialTheme.colors.primary.toArgb() - window.navigationBarColor = if (getColorPallet(settingsInfo.value.palletColor) == ColorPallet.Dark) - MaterialTheme.colors.background.toArgb() else MaterialTheme.colors.primary.toArgb() + val statusBarColor = + if (getColorPallet(settingsInfo.value.palletColor) == ColorPallet.Dark) MaterialTheme.colors.background.toArgb() + else MaterialTheme.colors.primary.toArgb() + window.statusBarColor = statusBarColor + window.navigationBarColor = + if (getColorPallet(settingsInfo.value.palletColor) == ColorPallet.Dark) + MaterialTheme.colors.background.toArgb() else MaterialTheme.colors.primary.toArgb() MainComposable( model, musicServiceConnection, settingsUpdated = { settingsInfo.value = model.repository.getSettingsInfo() }, - hasNavigationDonationOn = settingsInfo.value.hasNavigationDonationOn + hasNavigationDonationOn = settingsInfo.value.hasNavigationDonationOn, + updateStatusBarColor = { color, extended -> + if (extended) + window.statusBarColor = color + else + window.statusBarColor = statusBarColor + } ) } } diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/MainComposable.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/MainComposable.kt index f92759b..95dda79 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/MainComposable.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/MainComposable.kt @@ -13,9 +13,11 @@ fun MainComposable( model: JustListenViewModel, musicServiceConnection: MusicServiceConnection, settingsUpdated: () -> Unit, - hasNavigationDonationOn: Boolean + hasNavigationDonationOn: Boolean, + updateStatusBarColor: (Int, Boolean) -> Unit ) { val appState by model.stateFlow.collectAsState() val justlistenNav = appState.getNavigation(model = model) - justlistenNav.Router(musicServiceConnection, settingsUpdated = settingsUpdated, hasNavigationDonationOn) + justlistenNav.Router(musicServiceConnection, settingsUpdated = settingsUpdated, hasNavigationDonationOn, + updateStatusBarColor) } \ No newline at end of file diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt index dcac8b1..70edb41 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt @@ -2,7 +2,10 @@ package com.rld.justlisten.android.ui import android.media.session.PlaybackState import android.widget.Toast -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf @@ -36,7 +39,9 @@ fun Navigation.OnePane( saveableStateHolder: SaveableStateHolder, musicServiceConnection: MusicServiceConnection, settingsUpdated: () -> Unit, - hasNavigationFundOn: Boolean + hasNavigationFundOn: Boolean, + backgroundColor: Int, + updateStatusBarColor: (Int, Boolean) -> Unit ) { val shouldHavePlayBar = musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_PLAYING @@ -53,7 +58,7 @@ fun Navigation.OnePane( val context = LocalContext.current - val dominantColorMutable = rememberSaveable { mutableMapOf("null" to 12312312) } + val dominantColorMutable = rememberSaveable { mutableMapOf("null" to backgroundColor) } val addPlaylistList = remember { mutableStateOf(events.getPlaylist()) } @@ -80,7 +85,7 @@ fun Navigation.OnePane( currentFraction = scaffoldState.fraction, onSkipNextPressed = { musicServiceConnection.transportControls.skipToNext() }, musicServiceConnection = musicServiceConnection, - dominantColor = dominantColorMutable[id] ?: 12312312, + dominantColor = dominantColorMutable[id] ?: backgroundColor, onFavoritePressed = { id, title, userModel, songIconList, isFavorite -> events.saveSongToFavorites( id, @@ -115,6 +120,7 @@ fun Navigation.OnePane( }, newDominantColor = {songId, color -> dominantColorMutable[songId] = color + updateStatusBarColor(color, scaffoldState.bottomSheetState.isExpanded) }, playBarMinimizedClicked = { coroutineScope.launch { scaffoldState.bottomSheetState.expand() } diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt index 1ed5a59..5c6f4e3 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt @@ -2,8 +2,10 @@ package com.rld.justlisten.android.ui import androidx.activity.compose.BackHandler import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.saveable.rememberSaveableStateHolder +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.util.fastForEach import coil.annotation.ExperimentalCoilApi import com.rld.justlisten.Navigation @@ -12,11 +14,21 @@ import com.rld.justlisten.android.exoplayer.MusicServiceConnection @ExperimentalCoilApi @ExperimentalMaterialApi @Composable -fun Navigation.Router(musicServiceConnection: MusicServiceConnection, settingsUpdated: () -> Unit, - hasNavigationFundOn: Boolean) { +fun Navigation.Router( + musicServiceConnection: MusicServiceConnection, settingsUpdated: () -> Unit, + hasNavigationFundOn: Boolean, + updateStatusBarColor: (Int, Boolean) -> Unit +) { val screenUIisStateHolder = rememberSaveableStateHolder() - - OnePane(screenUIisStateHolder, musicServiceConnection, settingsUpdated = settingsUpdated, hasNavigationFundOn) + val backgroundColor = MaterialTheme.colors.background.toArgb() + OnePane( + screenUIisStateHolder, + musicServiceConnection, + settingsUpdated = settingsUpdated, + hasNavigationFundOn, + backgroundColor, + updateStatusBarColor = updateStatusBarColor + ) screenStatesToRemove.fastForEach { screenUIisStateHolder.removeState(it.URI) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt index 2df35a4..0f532f9 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt @@ -1,7 +1,9 @@ package com.rld.justlisten.android.ui.bottombars.playbar import androidx.compose.foundation.layout.* -import androidx.compose.material.* +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Icon +import androidx.compose.material.LinearProgressIndicator import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -41,7 +43,7 @@ fun PlayerBottomBar( newDominantColor: (String, Int) -> Unit, playBarMinimizedClicked: () -> Unit ) { - val list = listOf(Color(dominantColor), Color(dominantColor).copy(alpha = 0.6f)) + val list = listOf(Color(dominantColor), Color(dominantColor).copy(alpha = 0.8f)) BoxWithConstraints( modifier = if (currentFraction > 0.001) Modifier .verticalGradientBackground(list) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt index f886830..3609985 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt @@ -1,9 +1,7 @@ package com.rld.justlisten.android.ui.bottombars.playbar.components -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale @@ -11,13 +9,13 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.core.graphics.drawable.toBitmap import androidx.palette.graphics.Palette -import coil.annotation.ExperimentalCoilApi -import coil.compose.AsyncImagePainter -import coil.compose.rememberAsyncImagePainter +import coil.compose.SubcomposeAsyncImage +import coil.compose.SubcomposeAsyncImageContent import coil.request.ImageRequest import coil.size.Size import com.rld.justlisten.android.exoplayer.MusicServiceConnection import com.rld.justlisten.android.exoplayer.library.extension.id +import com.rld.justlisten.android.ui.components.AnimatedShimmer import com.rld.justlisten.android.ui.utils.heightSize import com.rld.justlisten.android.ui.utils.offsetX import com.rld.justlisten.android.ui.utils.widthSize @@ -32,31 +30,19 @@ fun PlayBarSwipeActions( onFavoritePressed: (String, String, UserModel, SongIconList, Boolean) -> Unit, newDominantColor: (String, Int) -> Unit, playBarMinimizedClicked: () -> Unit - ) { +) { Row( modifier = Modifier .fillMaxWidth() ) { - val painter = rememberAsyncImagePainter( - model = ImageRequest.Builder(context = LocalContext.current) - .data(songIcon).allowHardware(false).size(Size.ORIGINAL).build(), - - ) val id = musicServiceConnection.currentPlayingSong.value?.id.toString() - (painter.state as? AsyncImagePainter.State.Success)?.let { successState -> - painterLoaded(successState.painter) - LaunchedEffect(painter) { - val drawable = successState.result.drawable - Palette.Builder(drawable.toBitmap()).generate { palette -> - palette?.dominantSwatch?.let { swatch -> - newDominantColor(id, swatch.rgb) - } - } - } - } - Image( - painter = painter, + SubcomposeAsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(songIcon) + .allowHardware(false) + .size(Size.ORIGINAL) + .build(), modifier = Modifier .size( width = widthSize(currentFraction, constraints.maxWidth.value).dp, @@ -64,7 +50,27 @@ fun PlayBarSwipeActions( ) .offset(x = offsetX(currentFraction, constraints.maxWidth.value).dp), contentDescription = null, - contentScale = ContentScale.FillBounds + contentScale = ContentScale.FillBounds, + success = { state -> + painterLoaded(state.painter) + val drawable = state.result.drawable + Palette.Builder(drawable.toBitmap()).generate { palette -> + palette?.dominantSwatch?.let { swatch -> + newDominantColor(id, swatch.rgb) + } + } + SubcomposeAsyncImageContent() + }, + loading = { + if (currentFraction == 1f) { + AnimatedShimmer( + width = widthSize( + currentFraction, + constraints.maxWidth.value + ).dp, height = heightSize(currentFraction, constraints.maxHeight.value).dp + ) + } + } ) PlayBarActionsMinimized( currentFraction, From 9e07ebbe1af205ea7aa19892f4a238cbc95691cc Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sat, 28 May 2022 15:02:23 +0300 Subject: [PATCH 10/16] Fix for color change when playbar is expanded --- .../com/rld/justlisten/android/ui/OnePane.kt | 2 +- .../playbar/PlayerBarSheetContent.kt | 4 ++-- .../ui/bottombars/playbar/PlayerBottomBar.kt | 23 +++++++++++-------- .../ui/theme/modifiers/ModifierExtentions.kt | 14 +++++++++++ 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt index 70edb41..c4ab4f5 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt @@ -83,9 +83,9 @@ fun Navigation.OnePane( onCollapsedClicked = { coroutineScope.launch { scaffoldState.bottomSheetState.collapse() } }, bottomPadding = bottomBarPadding, currentFraction = scaffoldState.fraction, + isExpanded = scaffoldState.bottomSheetState.isExpanded, onSkipNextPressed = { musicServiceConnection.transportControls.skipToNext() }, musicServiceConnection = musicServiceConnection, - dominantColor = dominantColorMutable[id] ?: backgroundColor, onFavoritePressed = { id, title, userModel, songIconList, isFavorite -> events.saveSongToFavorites( id, diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt index 2cd33c6..45fc7ba 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt @@ -23,9 +23,9 @@ import kotlinx.coroutines.launch fun PlayerBarSheetContent( bottomPadding: Dp, currentFraction: Float, + isExpanded: Boolean, onSkipNextPressed: () -> Unit, musicServiceConnection: MusicServiceConnection, - dominantColor: Int, onCollapsedClicked: () -> Unit, onFavoritePressed: (String, String, UserModel, SongIconList, Boolean) -> Unit, addPlaylistList: List, @@ -91,6 +91,7 @@ fun PlayerBarSheetContent( onCollapsedClicked = onCollapsedClicked, bottomPadding = bottomPadding, currentFraction = currentFraction, + isExtended = isExpanded, songIcon = songIcon, title = title, musicServiceConnection = musicServiceConnection, onSkipNextPressed = onSkipNextPressed, @@ -106,7 +107,6 @@ fun PlayerBarSheetContent( mutablePainter.value = painter }, playBarMinimizedClicked = playBarMinimizedClicked, - dominantColor = dominantColor, onFavoritePressed = onFavoritePressed, newDominantColor = newDominantColor ) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt index 0f532f9..5d0e5e3 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt @@ -4,10 +4,9 @@ import androidx.compose.foundation.layout.* import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Icon import androidx.compose.material.LinearProgressIndicator -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource @@ -20,7 +19,7 @@ import com.rld.justlisten.android.ui.bottombars.playbar.components.PlayBarAction import com.rld.justlisten.android.ui.bottombars.playbar.components.PlayBarSwipeActions import com.rld.justlisten.android.ui.bottombars.playbar.components.PlayBarTopSection import com.rld.justlisten.android.ui.extensions.noRippleClickable -import com.rld.justlisten.android.ui.theme.modifiers.verticalGradientBackground +import com.rld.justlisten.android.ui.theme.modifiers.verticalGradientBackgroundColor import com.rld.justlisten.datalayer.models.SongIconList import com.rld.justlisten.datalayer.models.UserModel import kotlinx.coroutines.InternalCoroutinesApi @@ -30,6 +29,7 @@ import kotlinx.coroutines.InternalCoroutinesApi fun PlayerBottomBar( bottomPadding: Dp, currentFraction: Float, + isExtended: Boolean, songIcon: String, title: String, musicServiceConnection: MusicServiceConnection, @@ -38,15 +38,17 @@ fun PlayerBottomBar( onMoreClicked: () -> Unit, onBackgroundClicked: () -> Unit, painterLoaded: (Painter) -> Unit, - dominantColor: Int, onFavoritePressed: (String, String, UserModel, SongIconList, Boolean) -> Unit, newDominantColor: (String, Int) -> Unit, playBarMinimizedClicked: () -> Unit ) { - val list = listOf(Color(dominantColor), Color(dominantColor).copy(alpha = 0.8f)) + var gradientColor by remember { + mutableStateOf(11111111) + } + BoxWithConstraints( - modifier = if (currentFraction > 0.001) Modifier - .verticalGradientBackground(list) + modifier = if (isExtended) Modifier + .verticalGradientBackgroundColor(gradientColor) .noRippleClickable { onBackgroundClicked() } else Modifier.noRippleClickable { onBackgroundClicked() } ) { val constraints = this@BoxWithConstraints @@ -57,8 +59,11 @@ fun PlayerBottomBar( PlayBarSwipeActions( songIcon, currentFraction, constraints, title, musicServiceConnection, onSkipNextPressed, painterLoaded, onFavoritePressed, - newDominantColor = newDominantColor, - playBarMinimizedClicked = playBarMinimizedClicked + newDominantColor = { key, color -> + gradientColor = color + newDominantColor(key, color) + }, + playBarMinimizedClicked = playBarMinimizedClicked ) LinearProgressIndicator( progress = musicServiceConnection.songDuration.value / curSongDuration.toFloat(), diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt index 585a33d..49bfa25 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt @@ -34,6 +34,20 @@ fun Modifier.verticalGradientBackground( ) } +fun Modifier.verticalGradientBackgroundColor( + color: Int +): Modifier { + val colors = listOf(Color(color), Color(color).copy(alpha = 0.8f)) + + return this.gradientBackground(colors) { gradientColors, size -> + Brush.verticalGradient( + colors = gradientColors, + startY = 0f, + endY = size.width + ) + } +} + fun Modifier.diagonalGradientTint( colors: List, blendMode: BlendMode From 1c46026f7ff7577ad1a6a3b6370c79e7f89bda8b Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sat, 28 May 2022 15:09:19 +0300 Subject: [PATCH 11/16] Change the windows status bar color faster, --- .../java/com/rld/justlisten/android/ui/OnePane.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt index c4ab4f5..06120e3 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt @@ -118,9 +118,13 @@ fun Navigation.OnePane( Toast.LENGTH_SHORT ).show() }, - newDominantColor = {songId, color -> + newDominantColor = { songId, color -> dominantColorMutable[songId] = color - updateStatusBarColor(color, scaffoldState.bottomSheetState.isExpanded) + updateStatusBarColor( + color, + scaffoldState.bottomSheetState.isExpanded && + scaffoldState.bottomSheetState.targetValue != BottomSheetValue.Collapsed + ) }, playBarMinimizedClicked = { coroutineScope.launch { scaffoldState.bottomSheetState.expand() } @@ -132,7 +136,8 @@ fun Navigation.OnePane( Modifier.padding(bottom = bottomBarPadding) ) { saveableStateHolder.SaveableStateProvider(currentScreenIdentifier.URI) { - ScreenPicker(currentScreenIdentifier, + ScreenPicker( + currentScreenIdentifier, musicServiceConnection, settingsUpdated = settingsUpdated ) From b72e03d36928788a89fdac8f1a3fc1b99410affa Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sat, 28 May 2022 15:42:08 +0300 Subject: [PATCH 12/16] remove unused --- .../main/java/com/rld/justlisten/android/ui/OnePane.kt | 9 +-------- .../main/java/com/rld/justlisten/android/ui/Router.kt | 5 +---- .../ui/bottombars/playbar/PlayerBarSheetContent.kt | 2 +- .../android/ui/bottombars/playbar/PlayerBottomBar.kt | 6 +++--- .../bottombars/playbar/components/PlayBarSwipeActions.kt | 7 ++----- 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt index 06120e3..553065c 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt @@ -12,7 +12,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.SaveableStateHolder -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp @@ -40,7 +39,6 @@ fun Navigation.OnePane( musicServiceConnection: MusicServiceConnection, settingsUpdated: () -> Unit, hasNavigationFundOn: Boolean, - backgroundColor: Int, updateStatusBarColor: (Int, Boolean) -> Unit ) { val shouldHavePlayBar = @@ -54,12 +52,8 @@ fun Navigation.OnePane( bottomSheetState = rememberBottomSheetState(initialValue = BottomSheetValue.Collapsed) ) - val id = musicServiceConnection.currentPlayingSong.value?.id.toString() - val context = LocalContext.current - val dominantColorMutable = rememberSaveable { mutableMapOf("null" to backgroundColor) } - val addPlaylistList = remember { mutableStateOf(events.getPlaylist()) } val coroutineScope = rememberCoroutineScope() @@ -118,8 +112,7 @@ fun Navigation.OnePane( Toast.LENGTH_SHORT ).show() }, - newDominantColor = { songId, color -> - dominantColorMutable[songId] = color + newDominantColor = { color -> updateStatusBarColor( color, scaffoldState.bottomSheetState.isExpanded && diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt index 5c6f4e3..0053ae2 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/Router.kt @@ -2,10 +2,8 @@ package com.rld.justlisten.android.ui import androidx.activity.compose.BackHandler import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.saveable.rememberSaveableStateHolder -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.util.fastForEach import coil.annotation.ExperimentalCoilApi import com.rld.justlisten.Navigation @@ -20,13 +18,12 @@ fun Navigation.Router( updateStatusBarColor: (Int, Boolean) -> Unit ) { val screenUIisStateHolder = rememberSaveableStateHolder() - val backgroundColor = MaterialTheme.colors.background.toArgb() + OnePane( screenUIisStateHolder, musicServiceConnection, settingsUpdated = settingsUpdated, hasNavigationFundOn, - backgroundColor, updateStatusBarColor = updateStatusBarColor ) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt index 45fc7ba..9954891 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt @@ -32,7 +32,7 @@ fun PlayerBarSheetContent( onAddPlaylistClicked: (String, String?) -> Unit, getLatestPlaylist: () -> Unit, clickedToAddSongToPlaylist: (String, String?, List) -> Unit, - newDominantColor: (String, Int) -> Unit, + newDominantColor: (Int) -> Unit, playBarMinimizedClicked: () -> Unit ) { val songIcon = diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt index 5d0e5e3..eaa0b7b 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt @@ -39,7 +39,7 @@ fun PlayerBottomBar( onBackgroundClicked: () -> Unit, painterLoaded: (Painter) -> Unit, onFavoritePressed: (String, String, UserModel, SongIconList, Boolean) -> Unit, - newDominantColor: (String, Int) -> Unit, + newDominantColor: (Int) -> Unit, playBarMinimizedClicked: () -> Unit ) { var gradientColor by remember { @@ -59,9 +59,9 @@ fun PlayerBottomBar( PlayBarSwipeActions( songIcon, currentFraction, constraints, title, musicServiceConnection, onSkipNextPressed, painterLoaded, onFavoritePressed, - newDominantColor = { key, color -> + newDominantColor = { color -> gradientColor = color - newDominantColor(key, color) + newDominantColor(color) }, playBarMinimizedClicked = playBarMinimizedClicked ) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt index 3609985..11589bc 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/components/PlayBarSwipeActions.kt @@ -14,7 +14,6 @@ import coil.compose.SubcomposeAsyncImageContent import coil.request.ImageRequest import coil.size.Size import com.rld.justlisten.android.exoplayer.MusicServiceConnection -import com.rld.justlisten.android.exoplayer.library.extension.id import com.rld.justlisten.android.ui.components.AnimatedShimmer import com.rld.justlisten.android.ui.utils.heightSize import com.rld.justlisten.android.ui.utils.offsetX @@ -28,15 +27,13 @@ fun PlayBarSwipeActions( musicServiceConnection: MusicServiceConnection, onSkipNextPressed: () -> Unit, painterLoaded: (Painter) -> Unit, onFavoritePressed: (String, String, UserModel, SongIconList, Boolean) -> Unit, - newDominantColor: (String, Int) -> Unit, + newDominantColor: (Int) -> Unit, playBarMinimizedClicked: () -> Unit ) { Row( modifier = Modifier .fillMaxWidth() ) { - val id = musicServiceConnection.currentPlayingSong.value?.id.toString() - SubcomposeAsyncImage( model = ImageRequest.Builder(LocalContext.current) .data(songIcon) @@ -56,7 +53,7 @@ fun PlayBarSwipeActions( val drawable = state.result.drawable Palette.Builder(drawable.toBitmap()).generate { palette -> palette?.dominantSwatch?.let { swatch -> - newDominantColor(id, swatch.rgb) + newDominantColor(swatch.rgb) } } SubcomposeAsyncImageContent() From 326a9d34fbdabe40c1140371835cc9d10946c067 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sun, 29 May 2022 14:10:56 +0300 Subject: [PATCH 13/16] performance improvement --- .../com/rld/justlisten/android/ui/OnePane.kt | 198 +++++++++--------- .../playbar/PlayerBarSheetContent.kt | 15 +- .../ui/bottombars/playbar/PlayerBottomBar.kt | 5 +- .../components/PlaylistRowItem.kt | 2 +- .../android/ui/screenpicker/ScreenPicker.kt | 28 ++- .../ui/theme/modifiers/ModifierExtentions.kt | 79 +------ 6 files changed, 131 insertions(+), 196 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt index 553065c..e2e5c6b 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/OnePane.kt @@ -7,10 +7,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.material.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.SaveableStateHolder import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -41,104 +38,107 @@ fun Navigation.OnePane( hasNavigationFundOn: Boolean, updateStatusBarColor: (Int, Boolean) -> Unit ) { - val shouldHavePlayBar = - musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_PLAYING - || musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_PAUSED - || musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_SKIPPING_TO_NEXT - || musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_BUFFERING - || musicServiceConnection.currentPlayingSong.value != null + val shouldHavePlayBar by remember { + derivedStateOf { + musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_PLAYING + || musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_PAUSED + || musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_SKIPPING_TO_NEXT + || musicServiceConnection.playbackState.value?.state == PlaybackState.STATE_BUFFERING + || musicServiceConnection.currentPlayingSong.value != null + } + } - val scaffoldState = rememberBottomSheetScaffoldState( - bottomSheetState = rememberBottomSheetState(initialValue = BottomSheetValue.Collapsed) - ) + val scaffoldState = rememberBottomSheetScaffoldState( + bottomSheetState = rememberBottomSheetState(initialValue = BottomSheetValue.Collapsed) + ) - val context = LocalContext.current + val context = LocalContext.current - val addPlaylistList = remember { mutableStateOf(events.getPlaylist()) } + val addPlaylistList = remember { mutableStateOf(events.getPlaylist()) } - val coroutineScope = rememberCoroutineScope() - Scaffold( - bottomBar = { - if (currentScreenIdentifier.screen.navigationLevel == 1) { - Level1BottomBar( - currentScreenIdentifier, - Modifier.offset(y = lerp(0f, 65f, scaffoldState.fraction).dp), - hasNavigationFundOn - ) - } - }, - content = { - val bottomBarPadding = it.calculateBottomPadding() - BottomSheetScaffold( - modifier = Modifier.fillMaxSize(), - scaffoldState = scaffoldState, - sheetContent = { - PlayerBarSheetContent( - onCollapsedClicked = { coroutineScope.launch { scaffoldState.bottomSheetState.collapse() } }, - bottomPadding = bottomBarPadding, - currentFraction = scaffoldState.fraction, - isExpanded = scaffoldState.bottomSheetState.isExpanded, - onSkipNextPressed = { musicServiceConnection.transportControls.skipToNext() }, - musicServiceConnection = musicServiceConnection, - onFavoritePressed = { id, title, userModel, songIconList, isFavorite -> - events.saveSongToFavorites( - id, - title, - userModel, - songIconList, - isFavorite = isFavorite - ) - updateFavorite(isFavorite, musicServiceConnection, id) - }, - addPlaylistList = addPlaylistList.value, - onAddPlaylistClicked = { playlistName, playlistDescription -> - events.addPlaylist(playlistName, playlistDescription) - addPlaylistList.value = events.getPlaylist() - }, - getLatestPlaylist = { - addPlaylistList.value = events.getPlaylist() - }, - clickedToAddSongToPlaylist = { playlistTitle, playlistDescription, songList -> - val list = songList.toMutableList() - list.add(musicServiceConnection.currentPlayingSong.value?.id ?: "") - events.updatePlaylistSongs( - playlistTitle, - playlistDescription, - list - ) - Toast.makeText( - context, - "The song was added to $playlistTitle", - Toast.LENGTH_SHORT - ).show() - }, - newDominantColor = { color -> - updateStatusBarColor( - color, - scaffoldState.bottomSheetState.isExpanded && - scaffoldState.bottomSheetState.targetValue != BottomSheetValue.Collapsed - ) - }, - playBarMinimizedClicked = { - coroutineScope.launch { scaffoldState.bottomSheetState.expand() } - } + val coroutineScope = rememberCoroutineScope() + Scaffold( + bottomBar = { + if (currentScreenIdentifier.screen.navigationLevel == 1) { + Level1BottomBar( + currentScreenIdentifier, + Modifier.offset(y = lerp(0f, 65f, scaffoldState.fraction).dp), + hasNavigationFundOn ) - }, content = { - Column( - modifier = if (shouldHavePlayBar) Modifier.padding(bottom = bottomBarPadding + 55.dp) else - Modifier.padding(bottom = bottomBarPadding) - ) { - saveableStateHolder.SaveableStateProvider(currentScreenIdentifier.URI) { - ScreenPicker( - currentScreenIdentifier, - musicServiceConnection, - settingsUpdated = settingsUpdated - ) + } + }, + content = { + val bottomBarPadding = it.calculateBottomPadding() + BottomSheetScaffold( + modifier = Modifier.fillMaxSize(), + scaffoldState = scaffoldState, + sheetContent = { + PlayerBarSheetContent( + onCollapsedClicked = { coroutineScope.launch { scaffoldState.bottomSheetState.collapse() } }, + bottomPadding = bottomBarPadding, + currentFraction = scaffoldState.fraction, + isExtended = scaffoldState.bottomSheetState.isExpanded, + onSkipNextPressed = { musicServiceConnection.transportControls.skipToNext() }, + musicServiceConnection = musicServiceConnection, + onFavoritePressed = { id, title, userModel, songIconList, isFavorite -> + events.saveSongToFavorites( + id, + title, + userModel, + songIconList, + isFavorite = isFavorite + ) + updateFavorite(isFavorite, musicServiceConnection, id) + }, + addPlaylistList = addPlaylistList.value, + onAddPlaylistClicked = { playlistName, playlistDescription -> + events.addPlaylist(playlistName, playlistDescription) + addPlaylistList.value = events.getPlaylist() + }, + getLatestPlaylist = { + addPlaylistList.value = events.getPlaylist() + }, + clickedToAddSongToPlaylist = { playlistTitle, playlistDescription, songList -> + val list = songList.toMutableList() + list.add(musicServiceConnection.currentPlayingSong.value?.id ?: "") + events.updatePlaylistSongs( + playlistTitle, + playlistDescription, + list + ) + Toast.makeText( + context, + "The song was added to $playlistTitle", + Toast.LENGTH_SHORT + ).show() + }, + newDominantColor = { color -> + updateStatusBarColor( + color, + scaffoldState.bottomSheetState.isExpanded && + scaffoldState.bottomSheetState.targetValue != BottomSheetValue.Collapsed + ) + }, + playBarMinimizedClicked = { + coroutineScope.launch { scaffoldState.bottomSheetState.expand() } + } + ) + }, content = { + Column( + modifier = if (shouldHavePlayBar) Modifier.padding(bottom = bottomBarPadding + 55.dp) else + Modifier.padding(bottom = bottomBarPadding) + ) { + saveableStateHolder.SaveableStateProvider(currentScreenIdentifier.URI) { + ScreenPicker( + currentScreenIdentifier, + musicServiceConnection, + settingsUpdated = settingsUpdated + ) + } } - } - }, sheetPeekHeight = if (shouldHavePlayBar) { - bottomBarPadding + 65.dp - } else bottomBarPadding - 50.dp - ) - }) -} \ No newline at end of file + }, sheetPeekHeight = if (shouldHavePlayBar) { + bottomBarPadding + 65.dp + } else bottomBarPadding - 50.dp + ) + }) + } \ No newline at end of file diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt index 9954891..cfede5d 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBarSheetContent.kt @@ -23,7 +23,7 @@ import kotlinx.coroutines.launch fun PlayerBarSheetContent( bottomPadding: Dp, currentFraction: Float, - isExpanded: Boolean, + isExtended: Boolean, onSkipNextPressed: () -> Unit, musicServiceConnection: MusicServiceConnection, onCollapsedClicked: () -> Unit, @@ -31,14 +31,13 @@ fun PlayerBarSheetContent( addPlaylistList: List, onAddPlaylistClicked: (String, String?) -> Unit, getLatestPlaylist: () -> Unit, - clickedToAddSongToPlaylist: (String, String?, List) -> Unit, + clickedToAddSongToPlaylist: (String, String?, List) -> Unit, newDominantColor: (Int) -> Unit, playBarMinimizedClicked: () -> Unit ) { - val songIcon = - musicServiceConnection.currentPlayingSong.value?.description?.iconUri.toString() - val title = - musicServiceConnection.currentPlayingSong.value?.description?.title.toString() + val songIcon by remember { derivedStateOf { musicServiceConnection.currentPlayingSong.value?.description?.iconUri.toString() } } + val title by remember { derivedStateOf { + musicServiceConnection.currentPlayingSong.value?.description?.title.toString() } } val scaffoldState = rememberBottomSheetScaffoldState( bottomSheetState = rememberBottomSheetState(initialValue = BottomSheetValue.Collapsed) @@ -91,7 +90,7 @@ fun PlayerBarSheetContent( onCollapsedClicked = onCollapsedClicked, bottomPadding = bottomPadding, currentFraction = currentFraction, - isExtended = isExpanded, + isExtended = isExtended, songIcon = songIcon, title = title, musicServiceConnection = musicServiceConnection, onSkipNextPressed = onSkipNextPressed, @@ -106,7 +105,7 @@ fun PlayerBarSheetContent( painterLoaded = { painter -> mutablePainter.value = painter }, - playBarMinimizedClicked = playBarMinimizedClicked, + playBarMinimizedClicked = playBarMinimizedClicked, onFavoritePressed = onFavoritePressed, newDominantColor = newDominantColor ) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt index eaa0b7b..5c6a6dd 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/bottombars/playbar/PlayerBottomBar.kt @@ -4,11 +4,13 @@ import androidx.compose.foundation.layout.* import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Icon import androidx.compose.material.LinearProgressIndicator +import androidx.compose.material.MaterialTheme import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -42,8 +44,9 @@ fun PlayerBottomBar( newDominantColor: (Int) -> Unit, playBarMinimizedClicked: () -> Unit ) { + val color = MaterialTheme.colors.background.toArgb() var gradientColor by remember { - mutableStateOf(11111111) + mutableStateOf(color) } BoxWithConstraints( diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt index 3c12b00..881ab22 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/playlistscreen/components/PlaylistRowItem.kt @@ -35,7 +35,7 @@ fun PlaylistRowItem( SubcomposeAsyncImage(model = ImageRequest.Builder(LocalContext.current) .data(playlistItem.songIconList.songImageURL480px) - .crossfade(true) + .allowHardware(true) .build(), modifier = Modifier .width(180.dp) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/screenpicker/ScreenPicker.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/screenpicker/ScreenPicker.kt index bd2fe10..afb3073 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/screenpicker/ScreenPicker.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/screenpicker/ScreenPicker.kt @@ -10,12 +10,10 @@ import com.rld.justlisten.android.exoplayer.library.extension.id import com.rld.justlisten.android.exoplayer.library.extension.title import com.rld.justlisten.android.ui.addplaylistscreen.AddPlaylistScreen import com.rld.justlisten.android.ui.donationscreen.DonationScreen -import com.rld.justlisten.android.ui.playlistscreen.PlaylistScreen import com.rld.justlisten.android.ui.libraryscreen.LibraryScreen -import com.rld.justlisten.viewmodel.screens.playlist.* -import com.rld.justlisten.viewmodel.screens.playlist.PlayListEnum.* import com.rld.justlisten.android.ui.playlistdetailscreen.PlaylistDetailScreen import com.rld.justlisten.android.ui.playlistdetailscreen.playMusicFromId +import com.rld.justlisten.android.ui.playlistscreen.PlaylistScreen import com.rld.justlisten.android.ui.searchscreen.SearchScreen import com.rld.justlisten.android.ui.settingsscreen.SettingsScreen import com.rld.justlisten.datalayer.models.SongIconList @@ -27,12 +25,15 @@ import com.rld.justlisten.viewmodel.screens.addplaylist.updatePlaylist import com.rld.justlisten.viewmodel.screens.library.getLastPlayed import com.rld.justlisten.viewmodel.screens.library.saveSongToFavorites import com.rld.justlisten.viewmodel.screens.library.saveSongToRecent +import com.rld.justlisten.viewmodel.screens.playlist.PlayListEnum.* +import com.rld.justlisten.viewmodel.screens.playlist.PlaylistState +import com.rld.justlisten.viewmodel.screens.playlist.playMusicFromPlaylist +import com.rld.justlisten.viewmodel.screens.playlist.refreshScreen import com.rld.justlisten.viewmodel.screens.playlistdetail.PlaylistDetailParams import com.rld.justlisten.viewmodel.screens.playlistdetail.PlaylistDetailState import com.rld.justlisten.viewmodel.screens.search.SearchScreenState import com.rld.justlisten.viewmodel.screens.search.saveSearchInfo import com.rld.justlisten.viewmodel.screens.search.searchFor -import com.rld.justlisten.viewmodel.screens.search.updateSearch import com.rld.justlisten.viewmodel.screens.settings.saveSettingsInfo import com.rld.justlisten.viewmodel.screens.settings.updateScreen @@ -47,15 +48,22 @@ fun Navigation.ScreenPicker( mutableStateOf(false) } - val currentId = remember {musicServiceConnection.currentPlayingSong.value?.id} - if (currentId != musicServiceConnection.currentPlayingSong.value?.id) { + val currentId = remember { musicServiceConnection.currentPlayingSong.value?.id } + val updateRecentSong = + remember { derivedStateOf { currentId != musicServiceConnection.currentPlayingSong.value?.id } } + if (updateRecentSong.value) { LaunchedEffect(musicServiceConnection.currentPlayingSong.value?.id) { val title = musicServiceConnection.currentPlayingSong.value?.title ?: "title" val newId = musicServiceConnection.currentPlayingSong.value?.id ?: "id" val user = UserModel("asd") - val songIcon = musicServiceConnection.currentPlayingSong.value?.displayIconUri.toString() - val icon = SongIconList(songImageURL150px = songIcon, songImageURL480px = songIcon, songImageURL1000px = songIcon.replace("480", "1000")) - events.saveSongToRecent(newId, title, user,icon) + val songIcon = + musicServiceConnection.currentPlayingSong.value?.displayIconUri.toString() + val icon = SongIconList( + songImageURL150px = songIcon, + songImageURL480px = songIcon, + songImageURL1000px = songIcon.replace("480", "1000") + ) + events.saveSongToRecent(newId, title, user, icon) } } @@ -99,7 +107,7 @@ fun Navigation.ScreenPicker( }, onSearchClicked = { navigate(Search) }, refreshScreen = { events.refreshScreen() }, - onSongPressed = {songId, title, user, songIcon -> + onSongPressed = { songId, title, user, songIcon -> if (isPlayerReady.value) { isPlayerReady.value = false } diff --git a/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt b/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt index 49bfa25..713992f 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/ui/theme/modifiers/ModifierExtentions.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.composed +import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size @@ -72,10 +73,9 @@ fun Modifier.gradientBackground( ): Modifier = composed { var size by remember { mutableStateOf(Size.Zero) } val gradient = remember(colors, size) { brushProvider(colors, size) } - drawWithContent { + drawBehind { size = this.size drawRect(brush = gradient) - drawContent() } } @@ -96,78 +96,3 @@ fun Modifier.gradientTint( } } -//TODO fix drag obervers -//fun Modifier.swipeGesture( -// swipeValue: AnimatedFloat, -// swipeDirection: Direction = Direction.LEFT, -// maxSwipe: Float, -// onItemSwiped: () -> Unit -//): Modifier = composed { -// (this then dragGestureFilter( -// canDrag = { it == swipeDirection }, -// dragObserver = dragObserver( -// swipeValue = swipeValue, -// maxSwipe = maxSwipe, -// onItemSwiped = onItemSwiped -// ) -// )).then(object : LayoutModifier { -// override fun MeasureScope.measure( -// measurable: Measurable, -// constraints: Constraints -// ): MeasureResult { -// val children = measurable.measure(constraints) -// // swipeValue.setBounds(-children.width.toFloat()-100f, children.width.toFloat()+100f) -// return layout(children.width, children.height) { -// children.place(swipeValue.value.toInt(), 0) -// } -// } -// }) -//} -// -//@Composable -//fun dragObserver( -// swipeValue: AnimatedFloat, -// maxSwipe: Float, -// onItemSwiped: () -> Unit -//): DragObserver { -// -// return object : DragObserver { -// override fun onStart(downPosition: Offset) { -// // swipeValue.setBounds(-maxSwipe, maxSwipe) -// } -// -// private fun reset() { -// swipeValue.animateTo( -// 0f, -// anim = SpringSpec( -// dampingRatio = 0.8f, stiffness = 300f -// ) -// ) -// } -// -// override fun onDrag(dragDistance: Offset): Offset { -// swipeValue.snapTo(swipeValue.targetValue + dragDistance.x) -// return dragDistance -// } -// -// override fun onStop(velocity: Offset) { -// if (abs(swipeValue.targetValue) < 400f) { -// reset() -// } else { -// val animateTo = if (swipeValue.value > 0) maxSwipe else -maxSwipe -// swipeValue.animateTo( -// animateTo, -// anim = SpringSpec( -// dampingRatio = 0.8f, stiffness = 300f -// ), -// onEnd = { _, _ -> -// // On swiped do something -// // onItemSwiped.invoke() -// } -// ) -// // actually it should be in animation end but it's bit slow animation I put it out. -// onItemSwiped.invoke() -// } -// } -// } -//} From 028c5e025be121e6558bffee37640f0cd45d1d47 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sun, 29 May 2022 15:31:36 +0300 Subject: [PATCH 14/16] rollback for showing icons in notifications --- .../exoplayer/MusicNotificationManager.kt | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicNotificationManager.kt b/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicNotificationManager.kt index 6257285..acb7937 100644 --- a/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicNotificationManager.kt +++ b/androidApp/src/main/java/com/rld/justlisten/android/exoplayer/MusicNotificationManager.kt @@ -9,11 +9,11 @@ import android.support.v4.media.session.MediaSessionCompat import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.request.RequestOptions +import com.google.android.exoplayer2.Player +import com.google.android.exoplayer2.ui.PlayerNotificationManager import com.rld.justlisten.android.R import com.rld.justlisten.android.exoplayer.utils.Constants.NOTIFICATION_CHANNEL_ID import com.rld.justlisten.android.exoplayer.utils.Constants.NOTIFICATION_ID -import com.google.android.exoplayer2.Player -import com.google.android.exoplayer2.ui.PlayerNotificationManager import kotlinx.coroutines.* class MusicNotificationManager( @@ -97,19 +97,14 @@ class MusicNotificationManager( } private suspend fun resolveUriAsBitmap(uri: Uri): Bitmap? { - withContext(Dispatchers.IO) { + return withContext(Dispatchers.IO) { // Block on downloading artwork. - return@withContext try { - Glide.with(context).applyDefaultRequestOptions(glideOptions) - .asBitmap() - .load(uri) - .submit(NOTIFICATION_LARGE_ICON_SIZE, NOTIFICATION_LARGE_ICON_SIZE) - .get() - } catch (e: Exception) { - return@withContext null - } + Glide.with(context).applyDefaultRequestOptions(glideOptions) + .asBitmap() + .load(uri) + .submit(NOTIFICATION_LARGE_ICON_SIZE, NOTIFICATION_LARGE_ICON_SIZE) + .get() } - return null } } } From d9593d66271b71280a8818f93ff9f09013a4d9b4 Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sun, 29 May 2022 15:45:30 +0300 Subject: [PATCH 15/16] update version and timeout to 4s, quick fix for now --- androidApp/build.gradle.kts | 28 ++++---- androidApp/proguard-rules.pro | 11 +++ .../kotlin/com/rld/justlisten/StateManager.kt | 72 ++++++++++--------- .../datalayer/webservices/ApiClient.kt | 4 +- 4 files changed, 65 insertions(+), 50 deletions(-) diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index ba15c5d..682e04b 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -12,37 +12,37 @@ dependencies { implementation("androidx.appcompat:appcompat:1.4.1") implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.1") - implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0-rc01") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0-rc01") implementation("androidx.activity:activity-compose:1.4.0") - implementation ("androidx.palette:palette-ktx:1.0.0") + implementation("androidx.palette:palette-ktx:1.0.0") - implementation ("androidx.compose.ui:ui-util:1.2.0-beta02") + implementation("androidx.compose.ui:ui-util:1.2.0-beta02") implementation("androidx.compose.animation:animation:1.1.1") implementation("androidx.compose.ui:ui:1.2.0-beta02") - debugImplementation ("androidx.compose.ui:ui-tooling:1.1.1") - implementation ("androidx.compose.ui:ui-tooling-preview:1.1.1") + debugImplementation("androidx.compose.ui:ui-tooling:1.1.1") + implementation("androidx.compose.ui:ui-tooling-preview:1.1.1") implementation("androidx.compose.material:material:1.2.0-beta02") - implementation ("com.google.android.exoplayer:exoplayer:2.17.1") - implementation ("com.google.android.exoplayer:extension-mediasession:2.17.1") - implementation ("com.google.android.exoplayer:extension-cast:2.17.1") + implementation("com.google.android.exoplayer:exoplayer:2.17.1") + implementation("com.google.android.exoplayer:extension-mediasession:2.17.1") + implementation("com.google.android.exoplayer:extension-cast:2.17.1") implementation("androidx.lifecycle:lifecycle-process:2.4.1") implementation("io.coil-kt:coil-compose:2.1.0") implementation("com.google.dagger:hilt-android:2.38.1") kapt("com.google.dagger:hilt-android-compiler:2.38.1") - implementation ("com.github.bumptech.glide:glide:4.12.0") - annotationProcessor ("com.github.bumptech.glide:compiler:4.12.0") + implementation("com.github.bumptech.glide:glide:4.13.2") + annotationProcessor("com.github.bumptech.glide:compiler:4.13.2") - implementation ("com.google.accompanist:accompanist-swiperefresh:0.24.1-alpha") + implementation("com.google.accompanist:accompanist-swiperefresh:0.24.1-alpha") implementation("androidx.core:core-splashscreen:1.0.0-rc01") androidTestImplementation("androidx.compose.ui:ui-test-junit4:${rootProject.extra["compose_version"]}") debugImplementation("androidx.compose.ui:ui-tooling:${rootProject.extra["compose_version"]}") - debugImplementation ("com.squareup.leakcanary:leakcanary-android:2.7") + debugImplementation("com.squareup.leakcanary:leakcanary-android:2.7") } kapt { @@ -55,8 +55,8 @@ android { applicationId = "com.rld.justlisten.android" minSdk = 21 targetSdk = 31 - versionCode = 13 - versionName = "1.0.1" + versionCode = 14 + versionName = "1.0.2" vectorDrawables { useSupportLibrary = true } diff --git a/androidApp/proguard-rules.pro b/androidApp/proguard-rules.pro index 18d7a90..3fd415d 100644 --- a/androidApp/proguard-rules.pro +++ b/androidApp/proguard-rules.pro @@ -48,3 +48,14 @@ # @Serializable and @Polymorphic are used at runtime for polymorphic serialization. -keepattributes RuntimeVisibleAnnotations,AnnotationDefault +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep class * extends com.bumptech.glide.module.AppGlideModule { + (...); +} +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} +-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { + *** rewind(); +} diff --git a/shared/src/commonMain/kotlin/com/rld/justlisten/StateManager.kt b/shared/src/commonMain/kotlin/com/rld/justlisten/StateManager.kt index 4ec5146..035fd73 100644 --- a/shared/src/commonMain/kotlin/com/rld/justlisten/StateManager.kt +++ b/shared/src/commonMain/kotlin/com/rld/justlisten/StateManager.kt @@ -14,21 +14,26 @@ interface ScreenParams class StateManager(repo: Repository) { internal val mutableStateFlow = MutableStateFlow(AppState()) - val screenStatesMap : MutableMap = mutableMapOf() // map of screen states currently in memory - val screenScopesMap : MutableMap = mutableMapOf() // map of coroutine scopes associated to current screen states + val screenStatesMap: MutableMap = + mutableMapOf() // map of screen states currently in memory + private val screenScopesMap: MutableMap = + mutableMapOf() // map of coroutine scopes associated to current screen states - val level1Backstack: MutableList = mutableListOf() // list elements are only NavigationLevel1 screenIdentifiers - val verticalBackstacks: MutableMap> = mutableMapOf() // the map keys is NavigationLevel1 screenIdentifier URI - val verticalNavigationLevels : MutableMap> = mutableMapOf() // the first map key is the NavigationLevel1 screenIdentifier URI, the second map key is the NavigationLevel numbers + private val level1Backstack: MutableList = + mutableListOf() // list elements are only NavigationLevel1 screenIdentifiers + private val verticalBackstacks: MutableMap> = + mutableMapOf() // the map keys is NavigationLevel1 screenIdentifier URI + val verticalNavigationLevels: MutableMap> = + mutableMapOf() // the first map key is the NavigationLevel1 screenIdentifier URI, the second map key is the NavigationLevel numbers - val lastRemovedScreens = mutableListOf() + private val lastRemovedScreens = mutableListOf() internal val dataRepository by lazy { repo } - val currentScreenIdentifier : ScreenIdentifier + val currentScreenIdentifier: ScreenIdentifier get() = currentVerticalBackstack.lastOrNull() ?: level1Backstack.last() - val currentLevel1ScreenIdentifier : ScreenIdentifier + private val currentLevel1ScreenIdentifier: ScreenIdentifier get() = level1Backstack.last() val currentVerticalBackstack: MutableList @@ -37,12 +42,12 @@ class StateManager(repo: Repository) { val currentVerticalNavigationLevelsMap: MutableMap get() = verticalNavigationLevels[currentLevel1ScreenIdentifier.URI]!! - val only1ScreenInBackstack : Boolean + val only1ScreenInBackstack: Boolean get() = level1Backstack.size + currentVerticalBackstack.size == 2 // used by Compose apps - fun getScreenStatesToRemove() : List { + fun getScreenStatesToRemove(): List { val screenStatesToRemove = lastRemovedScreens.toList() lastRemovedScreens.clear() // clear list return screenStatesToRemove @@ -55,11 +60,11 @@ class StateManager(repo: Repository) { return screenIdentifiers } - fun isInTheStatesMap(screenIdentifier: ScreenIdentifier) : Boolean { + private fun isInTheStatesMap(screenIdentifier: ScreenIdentifier): Boolean { return screenStatesMap.containsKey(screenIdentifier.URI) } - fun isInAnyVerticalBackstack(screenIdentifier: ScreenIdentifier) : Boolean { + private fun isInAnyVerticalBackstack(screenIdentifier: ScreenIdentifier): Boolean { verticalBackstacks.forEach { verticalBackstack -> verticalBackstack.value.forEach { if (it.URI == screenIdentifier.URI) { @@ -70,15 +75,15 @@ class StateManager(repo: Repository) { return false } - inline fun updateScreen( + inline fun updateScreen( stateClass: KClass, update: (T) -> T, ) { //debugLogger.log("updateScreen: "+currentScreenIdentifier.URI) - lateinit var screenIdentifier : ScreenIdentifier - var screenState : T? = null - for(i in currentVerticalNavigationLevelsMap.keys.sortedDescending()) { + lateinit var screenIdentifier: ScreenIdentifier + var screenState: T? = null + for (i in currentVerticalNavigationLevelsMap.keys.sortedDescending()) { screenState = screenStatesMap[currentVerticalNavigationLevelsMap[i]?.URI] as? T if (screenState != null) { screenIdentifier = currentVerticalNavigationLevelsMap[i]!! @@ -92,7 +97,7 @@ class StateManager(repo: Repository) { } fun triggerRecomposition() { - mutableStateFlow.value = AppState(mutableStateFlow.value.recompositionIndex+1) + mutableStateFlow.value = AppState(mutableStateFlow.value.recompositionIndex + 1) } // ADD SCREEN FUNCTIONS @@ -112,10 +117,11 @@ class StateManager(repo: Repository) { } } - fun addScreenToBackstack(screenIdentifier: ScreenIdentifier) { + private fun addScreenToBackstack(screenIdentifier: ScreenIdentifier) { if (screenIdentifier.screen.navigationLevel == 1) { if (level1Backstack.size > 0) { - val sameAsNewScreen = screenIdentifier.screen == currentLevel1ScreenIdentifier.screen + val sameAsNewScreen = + screenIdentifier.screen == currentLevel1ScreenIdentifier.screen clearLevel1Screen(currentLevel1ScreenIdentifier, sameAsNewScreen) } setupNewLevel1Screen(screenIdentifier) @@ -135,7 +141,8 @@ class StateManager(repo: Repository) { currentVerticalBackstack.add(screenIdentifier) } } - currentVerticalNavigationLevelsMap[screenIdentifier.screen.navigationLevel] = screenIdentifier + currentVerticalNavigationLevelsMap[screenIdentifier.screen.navigationLevel] = + screenIdentifier } // REMOVE SCREEN FUNCTIONS @@ -146,14 +153,15 @@ class StateManager(repo: Repository) { } else { currentVerticalNavigationLevelsMap.remove(screenIdentifier.screen.navigationLevel) currentVerticalBackstack.removeAll { it.URI == screenIdentifier.URI } - currentVerticalNavigationLevelsMap[currentScreenIdentifier.screen.navigationLevel] = currentScreenIdentifier // set new currentScreenIdentifier, after the removal + currentVerticalNavigationLevelsMap[currentScreenIdentifier.screen.navigationLevel] = + currentScreenIdentifier // set new currentScreenIdentifier, after the removal if (!isInAnyVerticalBackstack(screenIdentifier)) { removeScreenStateAndScope(screenIdentifier) } } } - fun removeScreenStateAndScope(screenIdentifier: ScreenIdentifier) { + private fun removeScreenStateAndScope(screenIdentifier: ScreenIdentifier) { screenScopesMap[screenIdentifier.URI]?.cancel() // cancel screen's coroutine scope screenScopesMap.remove(screenIdentifier.URI) screenStatesMap.remove(screenIdentifier.URI) @@ -161,7 +169,7 @@ class StateManager(repo: Repository) { } // LEVEL 1 NAVIGATION FUNCTIONS - fun clearLevel1Screen(screenIdentifier: ScreenIdentifier, sameAsNewScreen: Boolean) { + private fun clearLevel1Screen(screenIdentifier: ScreenIdentifier, sameAsNewScreen: Boolean) { // debugLogger.log("clear vertical backstack /"+screenIdentifier.URI) if (!screenIdentifier.level1VerticalBackstackEnabled()) { currentVerticalBackstack.forEach { @@ -169,7 +177,7 @@ class StateManager(repo: Repository) { removeScreenStateAndScope(it) } } - currentVerticalBackstack.removeAll{ it.URI != screenIdentifier.URI } + currentVerticalBackstack.removeAll { it.URI != screenIdentifier.URI } currentVerticalNavigationLevelsMap.keys.removeAll { it != 1 } } if (sameAsNewScreen && !screenIdentifier.screen.stackableInstances) { @@ -180,7 +188,7 @@ class StateManager(repo: Repository) { } } - fun setupNewLevel1Screen(screenIdentifier: ScreenIdentifier) { + private fun setupNewLevel1Screen(screenIdentifier: ScreenIdentifier) { level1Backstack.removeAll { it.URI == screenIdentifier.URI } if (navigationSettings.alwaysQuitOnHomeScreen) { if (screenIdentifier.URI == navigationSettings.homeScreen.screenIdentifier.URI) { @@ -201,16 +209,15 @@ class StateManager(repo: Repository) { } - // COROUTINE SCOPES FUNCTIONS - fun initScreenScope(screenIdentifier: ScreenIdentifier) { + private fun initScreenScope(screenIdentifier: ScreenIdentifier) { //debugLogger.log("initScreenScope()") screenScopesMap[screenIdentifier.URI]?.cancel() screenScopesMap[screenIdentifier.URI] = CoroutineScope(Job() + Dispatchers.Main) } - fun reinitScreenScopes() : List { + fun reinitScreenScopes(): List { //debugLogger.log("reinitScreenScopes()") currentVerticalNavigationLevelsMap.forEach { screenScopesMap[it.value.URI] = CoroutineScope(Job() + Dispatchers.Main) @@ -219,7 +226,7 @@ class StateManager(repo: Repository) { } // we run each event function on a Dispatchers.Main coroutine - fun runInScreenScope (screenIdentifier: ScreenIdentifier? = null, block: suspend () -> Unit) { + fun runInScreenScope(screenIdentifier: ScreenIdentifier? = null, block: suspend () -> Unit) { val URI = screenIdentifier?.URI ?: currentScreenIdentifier.URI val screenScope = screenScopesMap[URI] screenScope?.launch { @@ -237,13 +244,12 @@ class StateManager(repo: Repository) { } - // APPSTATE DATA CLASS DEFINITION -data class AppState ( - val recompositionIndex : Int = 0, +data class AppState( + val recompositionIndex: Int = 0, ) { - fun getNavigation(model: JustListenViewModel) : Navigation { + fun getNavigation(model: JustListenViewModel): Navigation { return model.navigation } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt b/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt index 17684aa..590da9e 100644 --- a/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt +++ b/shared/src/commonMain/kotlin/com/rld/justlisten/datalayer/webservices/ApiClient.kt @@ -9,7 +9,6 @@ import io.ktor.client.features.* import io.ktor.client.features.json.JsonFeature import io.ktor.client.features.json.serializer.* import io.ktor.client.request.* -import kotlinx.coroutines.delay import kotlinx.datetime.Clock import kotlinx.serialization.json.Json import kotlin.collections.set @@ -24,7 +23,7 @@ class ApiClient { }) } install(HttpTimeout) { - requestTimeoutMillis = 3000 + requestTimeoutMillis = 4000 } } @@ -55,7 +54,6 @@ class ApiClient { return response } } catch (e: Exception) { - delay(10) numberOfCalls += 1 } } From e153d9fb1fdaa6dfacc38f7d621375855dfc8d6d Mon Sep 17 00:00:00 2001 From: laurentiu Date: Sun, 29 May 2022 17:10:28 +0300 Subject: [PATCH 16/16] switch to supervisorScope --- .../rld/justlisten/viewmodel/screens/playlist/PlaylistInit.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/src/commonMain/kotlin/com/rld/justlisten/viewmodel/screens/playlist/PlaylistInit.kt b/shared/src/commonMain/kotlin/com/rld/justlisten/viewmodel/screens/playlist/PlaylistInit.kt index fcb7d99..251b1c6 100644 --- a/shared/src/commonMain/kotlin/com/rld/justlisten/viewmodel/screens/playlist/PlaylistInit.kt +++ b/shared/src/commonMain/kotlin/com/rld/justlisten/viewmodel/screens/playlist/PlaylistInit.kt @@ -9,7 +9,7 @@ import com.rld.justlisten.viewmodel.screens.ScreenInitSettings import com.rld.justlisten.viewmodel.screens.search.TrackItem import kotlinx.coroutines.Deferred import kotlinx.coroutines.async -import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.supervisorScope import kotlinx.serialization.Serializable import kotlin.random.Random @@ -31,7 +31,7 @@ fun Navigation.initPlaylist(params: PlaylistParams) = ScreenInitSettings( queryIndex -= 1 else queryIndex += 1 } - coroutineScope { + supervisorScope { playlist = async { dataRepository.getPlaylist(index = 20, PlayListEnum.TOP_PLAYLIST) } tracks = async { dataRepository.getTracks(limit = 16, "Electronic", "week") } remix = async { dataRepository.getPlaylist(index = 20, PlayListEnum.REMIX, queryPlaylist = list[queryIndex]) }