From 88e010325474f4110d379d822e9cf241cf68957d Mon Sep 17 00:00:00 2001 From: Zion Huang Date: Wed, 7 Aug 2024 11:51:07 +0800 Subject: [PATCH] Update dependencies and target SDK to 34 --- app/build.gradle.kts | 33 ++- app/proguard-rules.pro | 3 + app/src/main/AndroidManifest.xml | 6 +- app/src/main/java/com/zionhuang/music/App.kt | 17 +- .../com/zionhuang/music/extensions/FileExt.kt | 2 +- .../playback/MediaLibrarySessionCallback.kt | 3 +- .../zionhuang/music/playback/MusicService.kt | 26 +- .../music/ui/utils/HorizontalPager.kt | 271 ------------------ .../utils/LazyGridSnapLayoutInfoProvider.kt | 135 +++------ .../zionhuang/music/utils/CoilBitmapLoader.kt | 4 +- .../viewmodels/BackupRestoreViewModel.kt | 5 +- build.gradle.kts | 7 +- gradle.properties | 2 + gradle/libs.versions.toml | 39 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- innertube/build.gradle.kts | 2 +- kugou/build.gradle.kts | 2 +- 17 files changed, 130 insertions(+), 429 deletions(-) delete mode 100644 app/src/main/java/com/zionhuang/music/ui/utils/HorizontalPager.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 60f218986..eedc7d25c 100755 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,8 +6,9 @@ plugins { id("com.android.application") kotlin("android") kotlin("kapt") - id("com.google.dagger.hilt.android") - id("com.google.devtools.ksp") + alias(libs.plugins.hilt) + alias(libs.plugins.kotlin.ksp) + alias(libs.plugins.compose.compiler) } if (isFullBuild && System.getenv("PULL_REQUEST") == null) { @@ -18,12 +19,12 @@ if (isFullBuild && System.getenv("PULL_REQUEST") == null) { android { namespace = "com.zionhuang.music" - compileSdk = 33 - buildToolsVersion = "30.0.3" + compileSdk = 34 + buildToolsVersion = "34.0.0" defaultConfig { applicationId = "com.zionhuang.music" minSdk = 24 - targetSdk = 33 + targetSdk = 34 versionCode = 20 versionName = "0.5.4" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -47,6 +48,16 @@ android { dimension = "version" } } + +// splits { +// abi { +// isEnable = true +// reset() +// include("armeabi-v7a", "arm64-v8a", "x86", "x86_64") +// isUniversalApk = false +// } +// } + signingConfigs { getByName("debug") { if (System.getenv("MUSIC_DEBUG_SIGNING_STORE_PASSWORD") != null) { @@ -58,22 +69,20 @@ android { } } buildFeatures { + buildConfig = true compose = true } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() - } compileOptions { isCoreLibraryDesugaringEnabled = true - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlin { - jvmToolchain(11) + jvmToolchain(17) } kotlinOptions { freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers" - jvmTarget = "11" + jvmTarget = "17" } testOptions { unitTests.isIncludeAndroidResources = true diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 570614915..0a900fd70 100755 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -58,3 +58,6 @@ -dontwarn org.openjsse.javax.net.ssl.SSLParameters -dontwarn org.openjsse.javax.net.ssl.SSLSocket -dontwarn org.openjsse.net.ssl.OpenJSSE +-dontwarn org.slf4j.impl.StaticLoggerBinder +-dontwarn com.google.firebase.perf.network.FirebasePerfOkHttpClient +-dontwarn com.google.firebase.perf.network.FirebasePerfUrlConnection diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a80f8b853..799f7b8dd 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,6 +8,8 @@ + + @@ -105,7 +107,8 @@ - @@ -133,6 +136,7 @@ diff --git a/app/src/main/java/com/zionhuang/music/App.kt b/app/src/main/java/com/zionhuang/music/App.kt index cc31c882d..6fcfc0228 100644 --- a/app/src/main/java/com/zionhuang/music/App.kt +++ b/app/src/main/java/com/zionhuang/music/App.kt @@ -11,8 +11,19 @@ import coil.disk.DiskCache import com.zionhuang.innertube.YouTube import com.zionhuang.innertube.models.YouTubeLocale import com.zionhuang.kugou.KuGou -import com.zionhuang.music.constants.* -import com.zionhuang.music.extensions.* +import com.zionhuang.music.constants.ContentCountryKey +import com.zionhuang.music.constants.ContentLanguageKey +import com.zionhuang.music.constants.CountryCodeToName +import com.zionhuang.music.constants.InnerTubeCookieKey +import com.zionhuang.music.constants.LanguageCodeToName +import com.zionhuang.music.constants.MaxImageCacheSizeKey +import com.zionhuang.music.constants.ProxyEnabledKey +import com.zionhuang.music.constants.ProxyTypeKey +import com.zionhuang.music.constants.ProxyUrlKey +import com.zionhuang.music.constants.SYSTEM_DEFAULT +import com.zionhuang.music.constants.VisitorDataKey +import com.zionhuang.music.extensions.toEnum +import com.zionhuang.music.extensions.toInetSocketAddress import com.zionhuang.music.utils.dataStore import com.zionhuang.music.utils.get import com.zionhuang.music.utils.reportException @@ -24,7 +35,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import timber.log.Timber import java.net.Proxy -import java.util.* +import java.util.Locale @HiltAndroidApp class App : Application(), ImageLoaderFactory { diff --git a/app/src/main/java/com/zionhuang/music/extensions/FileExt.kt b/app/src/main/java/com/zionhuang/music/extensions/FileExt.kt index 8a8b7cc74..0d023402c 100644 --- a/app/src/main/java/com/zionhuang/music/extensions/FileExt.kt +++ b/app/src/main/java/com/zionhuang/music/extensions/FileExt.kt @@ -8,5 +8,5 @@ import java.util.zip.ZipOutputStream operator fun File.div(child: String): File = File(this, child) -fun InputStream.zipInputStream():ZipInputStream = ZipInputStream(this) +fun InputStream.zipInputStream(): ZipInputStream = ZipInputStream(this) fun OutputStream.zipOutputStream(): ZipOutputStream = ZipOutputStream(this) \ No newline at end of file diff --git a/app/src/main/java/com/zionhuang/music/playback/MediaLibrarySessionCallback.kt b/app/src/main/java/com/zionhuang/music/playback/MediaLibrarySessionCallback.kt index cc441ba7b..68fee6779 100644 --- a/app/src/main/java/com/zionhuang/music/playback/MediaLibrarySessionCallback.kt +++ b/app/src/main/java/com/zionhuang/music/playback/MediaLibrarySessionCallback.kt @@ -14,6 +14,7 @@ import androidx.media3.session.MediaLibraryService import androidx.media3.session.MediaLibraryService.MediaLibrarySession import androidx.media3.session.MediaSession import androidx.media3.session.SessionCommand +import androidx.media3.session.SessionError import androidx.media3.session.SessionResult import com.google.common.collect.ImmutableList import com.google.common.util.concurrent.Futures @@ -182,7 +183,7 @@ class MediaLibrarySessionCallback @Inject constructor( ): ListenableFuture> = scope.future(Dispatchers.IO) { database.song(mediaId).first()?.toMediaItem()?.let { LibraryResult.ofItem(it, null) - } ?: LibraryResult.ofError(LibraryResult.RESULT_ERROR_UNKNOWN) + } ?: LibraryResult.ofError(SessionError.ERROR_UNKNOWN) } override fun onSetMediaItems( diff --git a/app/src/main/java/com/zionhuang/music/playback/MusicService.kt b/app/src/main/java/com/zionhuang/music/playback/MusicService.kt index ac7840135..70314ecf9 100644 --- a/app/src/main/java/com/zionhuang/music/playback/MusicService.kt +++ b/app/src/main/java/com/zionhuang/music/playback/MusicService.kt @@ -660,19 +660,21 @@ class MusicService : MediaLibraryService(), private fun createRenderersFactory() = object : DefaultRenderersFactory(this) { - override fun buildAudioSink(context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, enableOffload: Boolean) = - DefaultAudioSink.Builder(this@MusicService) - .setEnableFloatOutput(enableFloatOutput) - .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) - .setOffloadMode(if (enableOffload) DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED else DefaultAudioSink.OFFLOAD_MODE_DISABLED) - .setAudioProcessorChain( - DefaultAudioSink.DefaultAudioProcessorChain( - emptyArray(), - SilenceSkippingAudioProcessor(2_000_000, 20_000, 256), - SonicAudioProcessor() - ) + override fun buildAudioSink( + context: Context, + enableFloatOutput: Boolean, + enableAudioTrackPlaybackParams: Boolean, + ) = DefaultAudioSink.Builder(this@MusicService) + .setEnableFloatOutput(enableFloatOutput) + .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) + .setAudioProcessorChain( + DefaultAudioSink.DefaultAudioProcessorChain( + emptyArray(), + SilenceSkippingAudioProcessor(2_000_000, 0.01f, 2_000_000, 0, 256), + SonicAudioProcessor() ) - .build() + ) + .build() } override fun onPlaybackStatsReady(eventTime: AnalyticsListener.EventTime, playbackStats: PlaybackStats) { diff --git a/app/src/main/java/com/zionhuang/music/ui/utils/HorizontalPager.kt b/app/src/main/java/com/zionhuang/music/ui/utils/HorizontalPager.kt deleted file mode 100644 index 489a0d271..000000000 --- a/app/src/main/java/com/zionhuang/music/ui/utils/HorizontalPager.kt +++ /dev/null @@ -1,271 +0,0 @@ -@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") - -package com.zionhuang.music.ui.utils - -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.gestures.FlingBehavior -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.ScrollScope -import androidx.compose.foundation.gestures.snapping.SnapFlingBehavior -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyList -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.pager.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.semantics.* -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.dp -import kotlinx.coroutines.flow.drop -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.launch -import kotlin.math.roundToInt - -@Composable -@ExperimentalFoundationApi -fun HorizontalPager( - items: List, - modifier: Modifier = Modifier, - state: PagerState = rememberPagerState(), - contentPadding: PaddingValues = PaddingValues(0.dp), - pageSize: PageSize = PageSize.Fill, - beyondBoundsPageCount: Int = 0, - pageSpacing: Dp = 0.dp, - verticalAlignment: Alignment.Vertical = Alignment.CenterVertically, - flingBehavior: SnapFlingBehavior = PagerDefaults.flingBehavior(state = state), - userScrollEnabled: Boolean = true, - reverseLayout: Boolean = false, - key: ((item: T) -> Any)? = null, - pageNestedScrollConnection: NestedScrollConnection = PagerDefaults.pageNestedScrollConnection( - Orientation.Horizontal - ), - pageContent: @Composable (item: T) -> Unit, -) { - Pager( - modifier = modifier, - state = state, - items = items, - pageSpacing = pageSpacing, - userScrollEnabled = userScrollEnabled, - orientation = Orientation.Horizontal, - verticalAlignment = verticalAlignment, - reverseLayout = reverseLayout, - contentPadding = contentPadding, - beyondBoundsPageCount = beyondBoundsPageCount, - pageSize = pageSize, - flingBehavior = flingBehavior, - key = key, - pageNestedScrollConnection = pageNestedScrollConnection, - pageContent = pageContent - ) -} - -@OptIn(ExperimentalFoundationApi::class) -@Composable -internal fun Pager( - modifier: Modifier, - state: PagerState, - items: List, - pageSize: PageSize, - pageSpacing: Dp, - orientation: Orientation, - beyondBoundsPageCount: Int, - verticalAlignment: Alignment.Vertical = Alignment.CenterVertically, - horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, - contentPadding: PaddingValues, - flingBehavior: SnapFlingBehavior, - userScrollEnabled: Boolean, - reverseLayout: Boolean, - key: ((item: T) -> Any)?, - pageNestedScrollConnection: NestedScrollConnection, - pageContent: @Composable (item: T) -> Unit, -) { - require(beyondBoundsPageCount >= 0) { - "beyondBoundsPageCount should be greater than or equal to 0, " + - "you selected $beyondBoundsPageCount" - } - - val isVertical = orientation == Orientation.Vertical - val density = LocalDensity.current - val layoutDirection = LocalLayoutDirection.current - val calculatedContentPaddings = remember(contentPadding, orientation, layoutDirection) { - calculateContentPaddings( - contentPadding, - orientation, - layoutDirection - ) - } - - val pagerFlingBehavior = remember(flingBehavior, state) { - PagerWrapperFlingBehavior(flingBehavior, state) - } - - LaunchedEffect(density, state, pageSpacing) { - with(density) { state.pageSpacing = pageSpacing.roundToPx() } - } - - LaunchedEffect(state) { - snapshotFlow { state.isScrollInProgress } - .filter { !it } - .drop(1) // Initial scroll is false - .collect { state.updateOnScrollStopped() } - } - - val pagerSemantics = if (userScrollEnabled) { - Modifier.pagerSemantics(state, isVertical) - } else { - Modifier - } - - BoxWithConstraints(modifier = modifier.then(pagerSemantics)) { - val mainAxisSize = if (isVertical) constraints.maxHeight else constraints.maxWidth - // Calculates how pages are shown across the main axis - val pageAvailableSize = remember( - density, - mainAxisSize, - pageSpacing, - calculatedContentPaddings - ) { - with(density) { - val pageSpacingPx = pageSpacing.roundToPx() - val contentPaddingPx = calculatedContentPaddings.roundToPx() - with(pageSize) { - density.calculateMainAxisPageSize( - mainAxisSize - contentPaddingPx, - pageSpacingPx - ) - }.toDp() - } - } - - val horizontalAlignmentForSpacedArrangement = - if (!reverseLayout) Alignment.Start else Alignment.End - val verticalAlignmentForSpacedArrangement = - if (!reverseLayout) Alignment.Top else Alignment.Bottom - - val lazyListState = remember(state) { - val initialPageOffset = - with(density) { pageAvailableSize.roundToPx() } * state.initialPageOffsetFraction - LazyListState(state.initialPage, initialPageOffset.roundToInt()).also { - state.loadNewState(it) - } - } - - LazyList( - modifier = Modifier, - state = lazyListState, - contentPadding = contentPadding, - flingBehavior = pagerFlingBehavior, - horizontalAlignment = horizontalAlignment, - horizontalArrangement = Arrangement.spacedBy( - pageSpacing, - horizontalAlignmentForSpacedArrangement - ), - verticalArrangement = Arrangement.spacedBy( - pageSpacing, - verticalAlignmentForSpacedArrangement - ), - verticalAlignment = verticalAlignment, - isVertical = isVertical, - reverseLayout = reverseLayout, - userScrollEnabled = userScrollEnabled, - beyondBoundsItemCount = beyondBoundsPageCount - ) { - items(items = items, key = key) { item -> - val pageMainAxisSizeModifier = if (isVertical) { - Modifier.height(pageAvailableSize) - } else { - Modifier.width(pageAvailableSize) - } - Box( - modifier = Modifier - .then(pageMainAxisSizeModifier) - .nestedScroll(pageNestedScrollConnection), - contentAlignment = Alignment.Center - ) { - pageContent(item) - } - } - } - } -} - -private fun calculateContentPaddings( - contentPadding: PaddingValues, - orientation: Orientation, - layoutDirection: LayoutDirection, -): Dp { - - val startPadding = if (orientation == Orientation.Vertical) { - contentPadding.calculateTopPadding() - } else { - contentPadding.calculateLeftPadding(layoutDirection) - } - - val endPadding = if (orientation == Orientation.Vertical) { - contentPadding.calculateBottomPadding() - } else { - contentPadding.calculateRightPadding(layoutDirection) - } - - return startPadding + endPadding -} - -@OptIn(ExperimentalFoundationApi::class) -private class PagerWrapperFlingBehavior( - val originalFlingBehavior: SnapFlingBehavior, - val pagerState: PagerState, -) : FlingBehavior { - override suspend fun ScrollScope.performFling(initialVelocity: Float): Float { - return with(originalFlingBehavior) { - performFling(initialVelocity) { remainingScrollOffset -> - pagerState.snapRemainingScrollOffset = remainingScrollOffset - } - } - } -} - -@OptIn(ExperimentalFoundationApi::class) -@Suppress("ComposableModifierFactory") -@Composable -private fun Modifier.pagerSemantics(state: PagerState, isVertical: Boolean): Modifier { - val scope = rememberCoroutineScope() - fun performForwardPaging(): Boolean { - return if (state.canScrollForward) { - scope.launch { - state.animateToNextPage() - } - true - } else { - false - } - } - - fun performBackwardPaging(): Boolean { - return if (state.canScrollBackward) { - scope.launch { - state.animateToPreviousPage() - } - true - } else { - false - } - } - - return this.then(Modifier.semantics { - if (isVertical) { - pageUp { performBackwardPaging() } - pageDown { performForwardPaging() } - } else { - pageLeft { performBackwardPaging() } - pageRight { performForwardPaging() } - } - }) -} diff --git a/app/src/main/java/com/zionhuang/music/ui/utils/LazyGridSnapLayoutInfoProvider.kt b/app/src/main/java/com/zionhuang/music/ui/utils/LazyGridSnapLayoutInfoProvider.kt index 1cf10ed82..db0d8f6a8 100644 --- a/app/src/main/java/com/zionhuang/music/ui/utils/LazyGridSnapLayoutInfoProvider.kt +++ b/app/src/main/java/com/zionhuang/music/ui/utils/LazyGridSnapLayoutInfoProvider.kt @@ -5,129 +5,62 @@ package com.zionhuang.music.ui.utils import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.snapping.SnapLayoutInfoProvider -import androidx.compose.foundation.lazy.LazyListItemInfo -import androidx.compose.foundation.lazy.LazyListLayoutInfo import androidx.compose.foundation.lazy.grid.LazyGridItemInfo import androidx.compose.foundation.lazy.grid.LazyGridLayoutInfo import androidx.compose.foundation.lazy.grid.LazyGridState -import androidx.compose.foundation.pager.PagerState -import androidx.compose.ui.unit.Density import androidx.compose.ui.util.fastForEach -import androidx.compose.ui.util.fastSumBy + @ExperimentalFoundationApi fun SnapLayoutInfoProvider( lazyGridState: LazyGridState, - positionInLayout: Density.(layoutSize: Float, itemSize: Float) -> Float = - { layoutSize, itemSize -> (layoutSize / 2f - itemSize / 2f) }, -): SnapLayoutInfoProvider = object : SnapLayoutInfoProvider { - - private val layoutInfo: LazyGridLayoutInfo - get() = lazyGridState.layoutInfo - - // Single page snapping is the default - override fun Density.calculateApproachOffset(initialVelocity: Float): Float = 0f - - override fun Density.calculateSnappingOffsetBounds(): ClosedFloatingPointRange { - var lowerBoundOffset = Float.NEGATIVE_INFINITY - var upperBoundOffset = Float.POSITIVE_INFINITY - - layoutInfo.visibleItemsInfo.fastForEach { item -> - val offset = - calculateDistanceToDesiredSnapPosition(layoutInfo, item, positionInLayout) - - // Find item that is closest to the center - if (offset <= 0 && offset > lowerBoundOffset) { - lowerBoundOffset = offset - } - - // Find item that is closest to center, but after it - if (offset >= 0 && offset < upperBoundOffset) { - upperBoundOffset = offset + positionInLayout: (layoutSize: Float, itemSize: Float) -> Float = { layoutSize, itemSize -> + (layoutSize / 2f - itemSize / 2f) + }, +): SnapLayoutInfoProvider = + object : SnapLayoutInfoProvider { + private val layoutInfo: LazyGridLayoutInfo + get() = lazyGridState.layoutInfo + + override fun calculateApproachOffset(initialVelocity: Float): Float = 0f + + override fun calculateSnappingOffset(currentVelocity: Float): Float { + val bounds = calculateSnappingOffsetBounds() + return when { + currentVelocity < 0 -> bounds.start + currentVelocity > 0 -> bounds.endInclusive + else -> 0f } } - return lowerBoundOffset.rangeTo(upperBoundOffset) - } - - override fun Density.calculateSnapStepSize(): Float = with(layoutInfo) { - if (visibleItemsInfo.isNotEmpty()) { - visibleItemsInfo.fastSumBy { it.size.width } / visibleItemsInfo.size.toFloat() - } else { - 0f - } - } -} - -@ExperimentalFoundationApi -fun SnapLayoutInfoProvider( - pagerState: PagerState, - positionInLayout: Density.(layoutSize: Float, itemSize: Float) -> Float = - { layoutSize, itemSize -> (layoutSize / 2f - itemSize / 2f) }, -): SnapLayoutInfoProvider = object : SnapLayoutInfoProvider { - - private val layoutInfo: LazyListLayoutInfo - get() = pagerState.layoutInfo - - // Single page snapping is the default - override fun Density.calculateApproachOffset(initialVelocity: Float): Float = 0f + fun calculateSnappingOffsetBounds(): ClosedFloatingPointRange { + var lowerBoundOffset = Float.NEGATIVE_INFINITY + var upperBoundOffset = Float.POSITIVE_INFINITY - override fun Density.calculateSnappingOffsetBounds(): ClosedFloatingPointRange { - var lowerBoundOffset = Float.NEGATIVE_INFINITY - var upperBoundOffset = Float.POSITIVE_INFINITY + layoutInfo.visibleItemsInfo.fastForEach { item -> + val offset = calculateDistanceToDesiredSnapPosition(layoutInfo, item, positionInLayout) - layoutInfo.visibleItemsInfo.fastForEach { item -> - val offset = - calculateDistanceToDesiredSnapPosition(layoutInfo, item, positionInLayout) - - // Find item that is closest to the center - if (offset <= 0 && offset > lowerBoundOffset) { - lowerBoundOffset = offset - } + // Find item that is closest to the center + if (offset <= 0 && offset > lowerBoundOffset) { + lowerBoundOffset = offset + } - // Find item that is closest to center, but after it - if (offset >= 0 && offset < upperBoundOffset) { - upperBoundOffset = offset + // Find item that is closest to center, but after it + if (offset >= 0 && offset < upperBoundOffset) { + upperBoundOffset = offset + } } - } - - return lowerBoundOffset.rangeTo(upperBoundOffset) - } - override fun Density.calculateSnapStepSize(): Float = with(layoutInfo) { - if (visibleItemsInfo.isNotEmpty()) { - visibleItemsInfo.fastSumBy { it.size } / visibleItemsInfo.size.toFloat() - } else { - 0f + return lowerBoundOffset.rangeTo(upperBoundOffset) } } -} - -fun Density.calculateDistanceToDesiredSnapPosition( - layoutInfo: LazyListLayoutInfo, - item: LazyListItemInfo, - positionInLayout: Density.(layoutSize: Float, itemSize: Float) -> Float, -): Float { - val containerSize = - with(layoutInfo) { singleAxisViewportSize - beforeContentPadding - afterContentPadding } - - val desiredDistance = - positionInLayout(containerSize.toFloat(), item.size.toFloat()) - - val itemCurrentPosition = item.offset - return itemCurrentPosition - desiredDistance -} - -private val LazyListLayoutInfo.singleAxisViewportSize: Int - get() = if (orientation == Orientation.Vertical) viewportSize.height else viewportSize.width -fun Density.calculateDistanceToDesiredSnapPosition( +fun calculateDistanceToDesiredSnapPosition( layoutInfo: LazyGridLayoutInfo, item: LazyGridItemInfo, - positionInLayout: Density.(layoutSize: Float, itemSize: Float) -> Float, + positionInLayout: (layoutSize: Float, itemSize: Float) -> Float, ): Float { - val containerSize = - with(layoutInfo) { singleAxisViewportSize - beforeContentPadding - afterContentPadding } + val containerSize = layoutInfo.singleAxisViewportSize - layoutInfo.beforeContentPadding - layoutInfo.afterContentPadding val desiredDistance = positionInLayout(containerSize.toFloat(), item.size.width.toFloat()) val itemCurrentPosition = item.offset.x.toFloat() diff --git a/app/src/main/java/com/zionhuang/music/utils/CoilBitmapLoader.kt b/app/src/main/java/com/zionhuang/music/utils/CoilBitmapLoader.kt index 7a5818a4d..4255c1988 100644 --- a/app/src/main/java/com/zionhuang/music/utils/CoilBitmapLoader.kt +++ b/app/src/main/java/com/zionhuang/music/utils/CoilBitmapLoader.kt @@ -5,7 +5,7 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.drawable.BitmapDrawable import android.net.Uri -import androidx.media3.session.BitmapLoader +import androidx.media3.common.util.BitmapLoader import coil.imageLoader import coil.request.ErrorResult import coil.request.ImageRequest @@ -19,6 +19,8 @@ class CoilBitmapLoader( private val context: Context, private val scope: CoroutineScope, ) : BitmapLoader { + override fun supportsMimeType(mimeType: String): Boolean = mimeType.startsWith("image/") + override fun decodeBitmap(data: ByteArray): ListenableFuture = scope.future(Dispatchers.IO) { BitmapFactory.decodeByteArray(data, 0, data.size) ?: error("Could not decode image data") diff --git a/app/src/main/java/com/zionhuang/music/viewmodels/BackupRestoreViewModel.kt b/app/src/main/java/com/zionhuang/music/viewmodels/BackupRestoreViewModel.kt index 5a8bf5f14..9825e56ba 100644 --- a/app/src/main/java/com/zionhuang/music/viewmodels/BackupRestoreViewModel.kt +++ b/app/src/main/java/com/zionhuang/music/viewmodels/BackupRestoreViewModel.kt @@ -10,6 +10,7 @@ import com.zionhuang.music.R import com.zionhuang.music.db.InternalDatabase import com.zionhuang.music.db.MusicDatabase import com.zionhuang.music.extensions.div +import com.zionhuang.music.extensions.tryOrNull import com.zionhuang.music.extensions.zipInputStream import com.zionhuang.music.extensions.zipOutputStream import com.zionhuang.music.playback.MusicService @@ -57,7 +58,7 @@ class BackupRestoreViewModel @Inject constructor( runCatching { context.applicationContext.contentResolver.openInputStream(uri)?.use { it.zipInputStream().use { inputStream -> - var entry = inputStream.nextEntry + var entry = tryOrNull { inputStream.nextEntry } // prevent ZipException while (entry != null) { when (entry.name) { SETTINGS_FILENAME -> { @@ -76,7 +77,7 @@ class BackupRestoreViewModel @Inject constructor( } } } - entry = inputStream.nextEntry + entry = tryOrNull { inputStream.nextEntry } // prevent ZipException } } } diff --git a/build.gradle.kts b/build.gradle.kts index 5dcafdea6..4b648d70a 100755 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { - id("com.google.dagger.hilt.android").version("2.44").apply(false) - id("com.google.devtools.ksp").version("1.8.0-1.0.9").apply(false) + alias(libs.plugins.hilt) apply (false) + alias(libs.plugins.kotlin.ksp) apply (false) + alias(libs.plugins.compose.compiler) apply false } buildscript { @@ -25,7 +26,7 @@ buildscript { } tasks.register("Clean") { - delete(rootProject.buildDir) + delete(rootProject.layout.buildDirectory) } subprojects { diff --git a/gradle.properties b/gradle.properties index b1073c437..f7a8ed900 100755 --- a/gradle.properties +++ b/gradle.properties @@ -16,3 +16,5 @@ org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" android.useAndroidX=true android.enableJetifier=true org.gradle.unsafe.configuration-cache=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 30860b2b0..b320b5861 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,14 @@ [versions] -androidGradlePlugin = "7.4.2" -kotlin = "1.8.0" -compose-compiler = "1.4.0" -compose = "1.3.3" -lifecycle = "2.6.1" +androidGradlePlugin = "8.5.1" +kotlin = "2.0.0" +compose = "1.6.8" +lifecycle = "2.8.4" material3 = "1.1.0-alpha05" -media3 = "1.1.1" -room = "2.5.2" -hilt = "2.46.1" -ktor = "2.2.2" +media3 = "1.4.0" +room = "2.6.1" +hilt = "2.51.1" +ktor = "2.3.12" +ksp = "2.0.0-1.0.24" [libraries] guava = { group = "com.google.guava", name = "guava", version = "31.0.1-android" } @@ -18,11 +18,11 @@ concurrent-futures = { group = "androidx.concurrent", name = "concurrent-futures gradle = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } activity = { group = "androidx.activity", name = "activity-compose", version = "1.7.2" } navigation = { group = "androidx.navigation", name = "navigation-compose", version = "2.5.3" } -hilt-navigation = { group = "androidx.hilt", name = "hilt-navigation-compose", version = "1.0.0" } +hilt-navigation = { group = "androidx.hilt", name = "hilt-navigation-compose", version = "1.2.0" } datastore = { group = "androidx.datastore", name = "datastore-preferences", version = "1.0.0" } compose-runtime = { group = "androidx.compose.runtime", name = "runtime", version.ref = "compose" } -compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version = "1.3.1" } +compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version = "compose" } compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "compose" } compose-ui-util = { group = "androidx.compose.ui", name = "ui-util", version.ref = "compose" } compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "compose" } @@ -69,23 +69,26 @@ brotli = { group = "org.brotli", name = "dec", version = "0.1.2" } opencc4j = { group = "com.github.houbb", name = "opencc4j", version = "1.7.2" } -desugaring = { group = "com.android.tools", name = "desugar_jdk_libs", version = "1.1.5" } +desugaring = { group = "com.android.tools", name = "desugar_jdk_libs", version = "2.0.4" } junit = { group = "junit", name = "junit", version = "4.13.2" } timber = { group = "com.jakewharton.timber", name = "timber", version = "4.7.1" } -google-services = { module = "com.google.gms:google-services", version = "4.3.15" } -firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version = "32.2.3" } +google-services = { module = "com.google.gms:google-services", version = "4.4.2" } +firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version = "33.1.2" } firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics-ktx" } firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics-ktx" } -firebase-crashlytics-plugin = { module = "com.google.firebase:firebase-crashlytics-gradle", version = "2.9.9" } +firebase-crashlytics-plugin = { module = "com.google.firebase:firebase-crashlytics-gradle", version = "3.0.2" } firebase-config = { group = "com.google.firebase", name = "firebase-config-ktx" } firebase-perf = { group = "com.google.firebase", name = "firebase-perf-ktx" } firebase-perf-plugin = { module = "com.google.firebase:perf-plugin", version = "1.4.2" } -mlkit-language-id = { group = "com.google.mlkit", name = "language-id", version = "17.0.4" } -mlkit-translate = { group = "com.google.mlkit", name = "translate", version = "17.0.1" } +mlkit-language-id = { group = "com.google.mlkit", name = "language-id", version = "17.0.5" } +mlkit-translate = { group = "com.google.mlkit", name = "translate", version = "17.0.2" } [plugins] -kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } \ No newline at end of file +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } +kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b3c83cea0..fae04f381 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Oct 04 14:57:57 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/innertube/build.gradle.kts b/innertube/build.gradle.kts index f51b08d89..c2828a46f 100644 --- a/innertube/build.gradle.kts +++ b/innertube/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } kotlin { - jvmToolchain(11) + jvmToolchain(17) } dependencies { diff --git a/kugou/build.gradle.kts b/kugou/build.gradle.kts index 174aface2..4d37f48e9 100644 --- a/kugou/build.gradle.kts +++ b/kugou/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } kotlin { - jvmToolchain(11) + jvmToolchain(17) } dependencies {