Refactor: Upgrade Coil to v3 and update dependencies

- Upgraded image loading library from Coil 2 to Coil 3, updating related APIs across the app.
- Migrated `viewModel()` to a singleton pattern for `AgentViewModel` to optimize instantiation.
- Updated various dependencies, including Android Gradle Plugin, Kotlin, Compose, and other libraries.
- Upgraded Gradle wrapper to version 8.11.1.
- Removed deprecated `windowInsets` and `animateItemPlacement` parameters in Compose components to align with latest API versions.
This commit is contained in:
2025-11-11 18:44:01 +08:00
parent 71718ee9c9
commit 45c5aa29b0
27 changed files with 152 additions and 123 deletions

View File

@@ -1,21 +1,22 @@
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android) alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.compose.compiler)
id("com.google.gms.google-services") id("com.google.gms.google-services")
id("com.google.firebase.crashlytics") id("com.google.firebase.crashlytics")
id("com.google.firebase.firebase-perf") id("com.google.firebase.firebase-perf")
id("org.jetbrains.kotlin.kapt") id("org.jetbrains.kotlin.kapt")
id("com.google.devtools.ksp") version "1.9.10-1.0.13" alias(libs.plugins.ksp)
} }
android { android {
namespace = "com.aiosman.ravenow" namespace = "com.aiosman.ravenow"
compileSdk = 34 compileSdk = 35
defaultConfig { defaultConfig {
applicationId = "com.aiosman.ravenow" applicationId = "com.aiosman.ravenow"
minSdk = 24 minSdk = 24
targetSdk = 34 targetSdk = 35
versionCode = 1000019 versionCode = 1000019
versionName = "1.0.000.19" versionName = "1.0.000.19"
@@ -46,19 +47,16 @@ android {
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_17
} }
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "17"
} }
buildFeatures { buildFeatures {
compose = true compose = true
buildConfig = true buildConfig = true
} }
composeOptions {
kotlinCompilerExtensionVersion = "1.5.3"
}
packaging { packaging {
resources { resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}" excludes += "/META-INF/{AL2.0,LGPL2.1}"
@@ -99,11 +97,13 @@ dependencies {
debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest) debugImplementation(libs.androidx.ui.test.manifest)
implementation(libs.androidx.animation) implementation(libs.androidx.animation)
implementation(libs.coil.compose)
implementation(libs.coil) implementation(libs.coil)
implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp)
implementation(libs.play.services.auth) implementation(libs.play.services.auth)
implementation(libs.kotlin.faker) implementation(libs.kotlin.faker)
implementation(libs.androidx.material) implementation(libs.androidx.material)
implementation(libs.androidx.material.icons.extended)
implementation(libs.zoomable) implementation(libs.zoomable)
implementation(libs.retrofit) implementation(libs.retrofit)
implementation(libs.converter.gson) implementation(libs.converter.gson)

View File

@@ -7,11 +7,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import coil.compose.rememberAsyncImagePainter import coil3.ImageLoader
import coil.request.ImageRequest import coil3.compose.rememberAsyncImagePainter
import coil.ImageLoader import coil3.disk.DiskCache
import coil.disk.DiskCache import coil3.memory.MemoryCache
import coil.memory.MemoryCache import coil3.request.ImageRequest
import coil3.request.crossfade
import okio.Path.Companion.toPath
data class ImageItem(val url: String) data class ImageItem(val url: String)
@@ -53,14 +55,15 @@ fun ImageItem(item: ImageItem, imageLoader: ImageLoader, context: Context) { //
fun getImageLoader(context: Context): ImageLoader { fun getImageLoader(context: Context): ImageLoader {
return ImageLoader.Builder(context) return ImageLoader.Builder(context)
.memoryCache { .memoryCache {
MemoryCache.Builder(context) MemoryCache.Builder()
.maxSizePercent(0.25) // 设置内存缓存大小为可用内存的 25% .maxSizePercent(context,0.25) // 设置内存缓存大小为可用内存的 25%
.build() .build()
} }
.diskCache { .diskCache {
val cacheDir = context.cacheDir.resolve("image_cache")
DiskCache.Builder() DiskCache.Builder()
.directory(context.cacheDir.resolve("image_cache")) .directory(cacheDir.absolutePath.toPath())
.maxSizePercent(0.02) // 设置磁盘缓存大小为可用存储空间的 2% .maxSizeBytes(250L * 1024 * 1024) // 250MB
.build() .build()
} }
.build() .build()

View File

@@ -71,7 +71,7 @@ fun AboutScreen() {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
// app version // app version
Text( Text(
text = stringResource(R.string.version_text, versionText), text = stringResource(R.string.version_text, versionText ?: ""),
fontSize = 16.sp, fontSize = 16.sp,
color = appColors.secondaryText, color = appColors.secondaryText,
fontWeight = FontWeight.Normal fontWeight = FontWeight.Normal

View File

@@ -118,8 +118,7 @@ fun CommentModalContent(
skipPartiallyExpanded = true skipPartiallyExpanded = true
), ),
dragHandle = {}, dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
windowInsets = WindowInsets(0)
) { ) {
CommentMenuModal( CommentMenuModal(
onDeleteClick = { onDeleteClick = {

View File

@@ -8,9 +8,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.drawable.toDrawable
import coil.annotation.ExperimentalCoilApi import coil3.annotation.ExperimentalCoilApi
import coil.compose.AsyncImage import coil3.compose.AsyncImage
import coil.request.ImageRequest import coil3.request.ImageRequest
import coil3.request.crossfade
import coil3.request.fallback
import coil3.request.placeholder
import com.aiosman.ravenow.utils.BlurHashDecoder import com.aiosman.ravenow.utils.BlurHashDecoder
import com.aiosman.ravenow.utils.Utils.getImageLoader import com.aiosman.ravenow.utils.Utils.getImageLoader

View File

@@ -2,6 +2,7 @@ package com.aiosman.ravenow.ui.composables
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.composed import androidx.compose.ui.composed
@@ -68,7 +69,6 @@ fun Modifier.debouncedClickableWithRipple(
clickable( clickable(
enabled = enabled && isClickable, enabled = enabled && isClickable,
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = androidx.compose.material.ripple.rememberRipple()
) { ) {
if (isClickable) { if (isClickable) {
isClickable = false isClickable = false

View File

@@ -123,7 +123,7 @@ fun LazyGridItemScope.DraggableItem(
translationY = dragDropState.previousItemOffset.value.y translationY = dragDropState.previousItemOffset.value.y
} }
} else { } else {
Modifier.animateItemPlacement() Modifier
} }
Box(modifier = modifier.then(draggingModifier).clip(RoundedCornerShape(8.dp)), propagateMinConstraints = true) { Box(modifier = modifier.then(draggingModifier).clip(RoundedCornerShape(8.dp)), propagateMinConstraints = true) {
content(dragging) content(dragging)

View File

@@ -16,11 +16,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import coil.ImageLoader import coil3.ImageLoader
import coil.compose.AsyncImage import coil3.asDrawable
import coil.request.ImageRequest import coil3.asImage
import coil.request.SuccessResult import coil3.compose.AsyncImage
import coil3.request.CachePolicy
import coil3.request.ImageRequest
import coil3.request.SuccessResult
import coil3.request.crossfade
import com.aiosman.ravenow.utils.Utils.getImageLoader import com.aiosman.ravenow.utils.Utils.getImageLoader
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -59,7 +64,11 @@ fun rememberImageBitmap(imageUrl: String, imageLoader: ImageLoader): Bitmap? {
.build() .build()
val result = withContext(Dispatchers.IO) { val result = withContext(Dispatchers.IO) {
(imageLoader.execute(request) as? SuccessResult)?.drawable?.toBitmap() val successResult = imageLoader.execute(request) as? SuccessResult
successResult?.let {
val drawable = it.image.asDrawable(context.resources)
drawable.toBitmap()
}
} }
bitmap = result bitmap = result
@@ -138,25 +147,33 @@ fun CustomAsyncImage(
} }
// 处理字符串URL // 处理字符串URL
val ctx = context ?: localContext
val placeholderImage = remember(placeholderRes, ctx) {
placeholderRes?.let { resId ->
ContextCompat.getDrawable(ctx, resId)?.asImage()
}
}
val errorImage = remember(errorRes, ctx) {
errorRes?.let { resId ->
ContextCompat.getDrawable(ctx, resId)?.asImage()
}
}
if (showShimmer) { if (showShimmer) {
var isLoading by remember { mutableStateOf(true) } var isLoading by remember { mutableStateOf(true) }
Box(modifier = modifier) { Box(modifier = modifier) {
AsyncImage( AsyncImage(
model = ImageRequest.Builder(context ?: localContext) model = ImageRequest.Builder(ctx)
.data(imageUrl) .data(imageUrl)
.crossfade(200) .crossfade(200)
.memoryCachePolicy(coil.request.CachePolicy.ENABLED) .memoryCachePolicy(coil3.request.CachePolicy.ENABLED)
.diskCachePolicy(coil.request.CachePolicy.ENABLED) .diskCachePolicy(coil3.request.CachePolicy.ENABLED)
.apply { .apply {
// 设置占位符图片 // 设置占位符图片
if (placeholderRes != null) { placeholderImage?.let { placeholder(it) }
placeholder(placeholderRes)
}
// 设置错误时显示的图片 // 设置错误时显示的图片
if (errorRes != null) { errorImage?.let { error(it) }
error(errorRes)
}
} }
.build(), .build(),
contentDescription = contentDescription, contentDescription = contentDescription,
@@ -177,20 +194,16 @@ fun CustomAsyncImage(
} }
} else { } else {
AsyncImage( AsyncImage(
model = ImageRequest.Builder(context ?: localContext) model = ImageRequest.Builder(ctx)
.data(imageUrl) .data(imageUrl)
.crossfade(200) .crossfade(200)
.memoryCachePolicy(coil.request.CachePolicy.ENABLED) .memoryCachePolicy(CachePolicy.ENABLED)
.diskCachePolicy(coil.request.CachePolicy.ENABLED) .diskCachePolicy(CachePolicy.ENABLED)
.apply { .apply {
// 设置占位符图片 // 设置占位符图片
if (placeholderRes != null) { placeholderImage?.let { placeholder(it) }
placeholder(placeholderRes)
}
// 设置错误时显示的图片 // 设置错误时显示的图片
if (errorRes != null) { errorImage?.let { error(it) }
error(errorRes)
}
} }
.build(), .build(),
contentDescription = contentDescription, contentDescription = contentDescription,

View File

@@ -450,7 +450,6 @@ fun MomentBottomOperateRowGroup(
sheetState = rememberModalBottomSheetState( sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true skipPartiallyExpanded = true
), ),
windowInsets = WindowInsets(0),
dragHandle = { dragHandle = {
Box( Box(
modifier = Modifier modifier = Modifier

View File

@@ -71,7 +71,6 @@ fun PolicyCheckbox(
showModal = false showModal = false
}, },
sheetState = modalSheetState, sheetState = modalSheetState,
windowInsets = WindowInsets(0),
containerColor = Color.White, containerColor = Color.White,
) { ) {
WebViewDisplay( WebViewDisplay(

View File

@@ -47,7 +47,6 @@ fun CreateBottomSheet(
ModalBottomSheet( ModalBottomSheet(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
sheetState = sheetState, sheetState = sheetState,
windowInsets = BottomSheetDefaults.windowInsets,
containerColor = appColors.background, containerColor = appColors.background,
dragHandle = null, dragHandle = null,
shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)

View File

@@ -265,7 +265,6 @@ fun IndexScreen() {
modifier = Modifier modifier = Modifier
.background(AppColors.background) .background(AppColors.background)
.padding(0.dp), .padding(0.dp),
beyondBoundsPageCount = 4,
userScrollEnabled = false userScrollEnabled = false
) { page -> ) { page ->
when (page) { when (page) {

View File

@@ -54,7 +54,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.aiosman.ravenow.AppStore import com.aiosman.ravenow.AppStore
import com.aiosman.ravenow.GuestLoginCheckOut import com.aiosman.ravenow.GuestLoginCheckOut
@@ -115,7 +114,7 @@ fun Agent() {
var pagerState = rememberPagerState { tabCount } var pagerState = rememberPagerState { tabCount }
var scope = rememberCoroutineScope() var scope = rememberCoroutineScope()
val viewModel: AgentViewModel = viewModel() val viewModel: AgentViewModel = AgentViewModel
// 确保推荐Agent数据已加载 // 确保推荐Agent数据已加载
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
@@ -183,7 +182,6 @@ fun Agent() {
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = AppColors.background containerColor = AppColors.background
), ),
windowInsets = WindowInsets(0, 0, 0, 0),
modifier = Modifier modifier = Modifier
.height(44.dp + statusBarPaddingValues.calculateTopPadding()) .height(44.dp + statusBarPaddingValues.calculateTopPadding())
.padding(top = statusBarPaddingValues.calculateTopPadding()) .padding(top = statusBarPaddingValues.calculateTopPadding())
@@ -899,7 +897,7 @@ fun ChatRoomCard(
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val cardSize = 180.dp val cardSize = 180.dp
val viewModel: AgentViewModel = viewModel() val viewModel: AgentViewModel = AgentViewModel
val context = LocalContext.current val context = LocalContext.current
// 防抖状态 // 防抖状态

View File

@@ -156,10 +156,10 @@ object HotAgentViewModel : ViewModel() {
try { try {
// 预加载头像图片到缓存 // 预加载头像图片到缓存
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue( com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
coil.request.ImageRequest.Builder(context) coil3.request.ImageRequest.Builder(context)
.data(agent.avatar) .data(agent.avatar)
.memoryCachePolicy(coil.request.CachePolicy.ENABLED) .memoryCachePolicy(coil3.request.CachePolicy.ENABLED)
.diskCachePolicy(coil.request.CachePolicy.ENABLED) .diskCachePolicy(coil3.request.CachePolicy.ENABLED)
.build() .build()
) )
preloadedImageIds.add(agent.id) preloadedImageIds.add(agent.id)

View File

@@ -841,20 +841,20 @@ fun Explore() {
if (bannerItem.backgroundImageUrl.isNotEmpty()) { if (bannerItem.backgroundImageUrl.isNotEmpty()) {
// 预加载背景图片 // 预加载背景图片
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue( com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
coil.request.ImageRequest.Builder(context) coil3.request.ImageRequest.Builder(context)
.data(bannerItem.backgroundImageUrl) .data(bannerItem.backgroundImageUrl)
.memoryCachePolicy(coil.request.CachePolicy.ENABLED) .memoryCachePolicy(coil3.request.CachePolicy.ENABLED)
.diskCachePolicy(coil.request.CachePolicy.ENABLED) .diskCachePolicy(coil3.request.CachePolicy.ENABLED)
.build() .build()
) )
} }
if (bannerItem.imageUrl.isNotEmpty()) { if (bannerItem.imageUrl.isNotEmpty()) {
// 预加载头像图片 // 预加载头像图片
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue( com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
coil.request.ImageRequest.Builder(context) coil3.request.ImageRequest.Builder(context)
.data(bannerItem.imageUrl) .data(bannerItem.imageUrl)
.memoryCachePolicy(coil.request.CachePolicy.ENABLED) .memoryCachePolicy(coil3.request.CachePolicy.ENABLED)
.diskCachePolicy(coil.request.CachePolicy.ENABLED) .diskCachePolicy(coil3.request.CachePolicy.ENABLED)
.build() .build()
) )
} }

View File

@@ -59,7 +59,6 @@ fun FullArticleModal(
.height(sheetHeight), .height(sheetHeight),
containerColor = appColors.background, containerColor = appColors.background,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
windowInsets = androidx.compose.foundation.layout.WindowInsets(0)
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier

View File

@@ -154,7 +154,6 @@ fun NewsCommentModal(
), ),
dragHandle = {}, dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
windowInsets = WindowInsets(0)
) { ) {
CommentMenuModal( CommentMenuModal(
onDeleteClick = { onDeleteClick = {

View File

@@ -194,7 +194,6 @@ fun NewsScreen() {
.height(sheetHeight), .height(sheetHeight),
containerColor = AppColors.background, containerColor = AppColors.background,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
windowInsets = androidx.compose.foundation.layout.WindowInsets(0)
) { ) {
NewsCommentModal( NewsCommentModal(
postId = selectedMoment?.id, postId = selectedMoment?.id,

View File

@@ -258,7 +258,6 @@ fun ProfileV3(
sheetState = agentMenuModalState, sheetState = agentMenuModalState,
dragHandle = {}, dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
windowInsets = WindowInsets(0)
) { ) {
AgentMenuModal( AgentMenuModal(
agent = contextAgent, agent = contextAgent,
@@ -535,7 +534,7 @@ fun ProfileV3(
containerColor = Color.Transparent, // 设置容器背景透明 containerColor = Color.Transparent, // 设置容器背景透明
contentColor = Color.Transparent, // 设置内容背景透明 contentColor = Color.Transparent, // 设置内容背景透明
dragHandle = null, // 移除拖拽手柄 dragHandle = null, // 移除拖拽手柄
windowInsets = androidx.compose.foundation.layout.WindowInsets(0) // 移除窗口边距 contentWindowInsets = {androidx.compose.foundation.layout.WindowInsets(0)},
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
@@ -567,7 +566,7 @@ fun ProfileV3(
containerColor = Color.Transparent, containerColor = Color.Transparent,
contentColor = Color.Transparent, contentColor = Color.Transparent,
dragHandle = null, dragHandle = null,
windowInsets = androidx.compose.foundation.layout.WindowInsets(0) contentWindowInsets = { androidx.compose.foundation.layout.WindowInsets(0) }
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier

View File

@@ -114,11 +114,14 @@ fun getFeedItems(): List<FeedItem> {
@Composable @Composable
fun LocationDetailScreen(x: Float, y: Float) { fun LocationDetailScreen(x: Float, y: Float) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val density = LocalDensity.current
val scaffoldState = rememberBottomSheetScaffoldState( val scaffoldState = rememberBottomSheetScaffoldState(
SheetState( bottomSheetState = SheetState(
skipPartiallyExpanded = false, skipPartiallyExpanded = false,
density = LocalDensity.current, initialValue = SheetValue.PartiallyExpanded, initialValue = SheetValue.PartiallyExpanded,
skipHiddenState = true skipHiddenState = true,
positionalThreshold = { 0.5f },
velocityThreshold = { with(density) { 125.dp.toPx() } }
) )
) )
val configuration = LocalConfiguration.current val configuration = LocalConfiguration.current

View File

@@ -22,6 +22,7 @@ import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -30,7 +31,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.rememberAsyncImagePainter import coil3.compose.rememberAsyncImagePainter
import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
@@ -67,7 +68,7 @@ fun NewPostImageGridScreen() {
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon( Icon(
Icons.AutoMirrored.Default.ArrowBack, Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "back", contentDescription = "back",
modifier = Modifier modifier = Modifier
.size(24.dp) .size(24.dp)
@@ -84,7 +85,7 @@ fun NewPostImageGridScreen() {
fontSize = 18.sp, fontSize = 18.sp,
) )
Icon( Icon(
Icons.Default.Delete, Icons.Filled.Delete,
contentDescription = "delete", contentDescription = "delete",
modifier = Modifier modifier = Modifier
.size(24.dp) .size(24.dp)

View File

@@ -173,7 +173,6 @@ fun PostScreen(
sheetState = commentModalState, sheetState = commentModalState,
dragHandle = {}, dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
windowInsets = WindowInsets(0)
) { ) {
CommentMenuModal( CommentMenuModal(
onDeleteClick = { onDeleteClick = {
@@ -262,7 +261,6 @@ fun PostScreen(
), ),
dragHandle = {}, dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
windowInsets = WindowInsets(0)
) { ) {
EditCommentBottomModal(replyComment) { EditCommentBottomModal(replyComment) {
viewModel.viewModelScope.launch { viewModel.viewModelScope.launch {
@@ -849,7 +847,6 @@ fun Header(
), ),
dragHandle = {}, dragHandle = {},
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
windowInsets = WindowInsets(0)
) { ) {
PostMenuModal( PostMenuModal(

View File

@@ -4,14 +4,16 @@ import android.content.ContentValues
import android.content.Context import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.widget.Toast import android.widget.Toast
import coil.request.ImageRequest import androidx.core.graphics.drawable.toBitmap
import coil.request.SuccessResult import coil3.asDrawable
import coil3.request.ImageRequest
import coil3.request.SuccessResult
import coil3.request.allowHardware
import com.aiosman.ravenow.utils.Utils.getImageLoader import com.aiosman.ravenow.utils.Utils.getImageLoader
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -30,8 +32,9 @@ object FileUtil {
.allowHardware(false) // Disable hardware bitmaps. .allowHardware(false) // Disable hardware bitmaps.
.build() .build()
val result = (loader.execute(request) as SuccessResult).drawable val result = loader.execute(request) as? SuccessResult ?: return
val bitmap = (result as BitmapDrawable).bitmap val drawable = result.image.asDrawable(context.resources)
val bitmap = drawable.toBitmap()
val contentValues = ContentValues().apply { val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "image_${System.currentTimeMillis()}.jpg") put(MediaStore.Images.Media.DISPLAY_NAME, "image_${System.currentTimeMillis()}.jpg")

View File

@@ -4,8 +4,9 @@ import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import coil.ImageLoader import coil3.ImageLoader
import coil.request.CachePolicy import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import coil3.request.CachePolicy
import com.aiosman.ravenow.data.api.AuthInterceptor import com.aiosman.ravenow.data.api.AuthInterceptor
import com.aiosman.ravenow.data.api.getSafeOkHttpClient import com.aiosman.ravenow.data.api.getSafeOkHttpClient
import java.io.File import java.io.File
@@ -32,7 +33,15 @@ object Utils {
val okHttpClient = getSafeOkHttpClient(authInterceptor = AuthInterceptor()) val okHttpClient = getSafeOkHttpClient(authInterceptor = AuthInterceptor())
val loader = ImageLoader.Builder(appContext) val loader = ImageLoader.Builder(appContext)
.okHttpClient(okHttpClient) .components {
add(
OkHttpNetworkFetcherFactory(
callFactory = {
okHttpClient
}
)
)
}
.memoryCachePolicy(CachePolicy.ENABLED) .memoryCachePolicy(CachePolicy.ENABLED)
.diskCachePolicy(CachePolicy.ENABLED) .diskCachePolicy(CachePolicy.ENABLED)
.build() .build()

View File

@@ -2,6 +2,7 @@
plugins { plugins {
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false alias(libs.plugins.jetbrains.kotlin.android) apply false
alias(libs.plugins.compose.compiler) apply false
id("com.google.gms.google-services") version "4.4.2" apply false id("com.google.gms.google-services") version "4.4.2" apply false
id("com.google.firebase.crashlytics") version "3.0.2" apply false id("com.google.firebase.crashlytics") version "3.0.2" apply false
id("com.google.firebase.firebase-perf") version "1.4.2" apply false id("com.google.firebase.firebase-perf") version "1.4.2" apply false

View File

@@ -1,48 +1,51 @@
[versions] [versions]
accompanistSystemuicontroller = "0.27.0" accompanistSystemuicontroller = "0.34.0"
agp = "8.4.0" agp = "8.9.0"
animation = "1.7.0-beta05" animation = "1.7.6"
coil = "2.7.0" coil = "3.3.0"
composeImageBlurhash = "3.0.2" composeImageBlurhash = "3.0.2"
converterGson = "2.11.0" converterGson = "2.11.0"
imSdk = "3.8.3.2" imSdk = "3.8.3.2"
imcoreSdk = "3.8.3-patch10" imcoreSdk = "3.8.3-patch10"
coreSplashscreen = "1.0.1" coreSplashscreen = "1.2.0"
credentialsPlayServicesAuth = "1.2.2" credentialsPlayServicesAuth = "1.0.0-alpha05"
eventbus = "3.3.1" eventbus = "3.3.1"
firebaseBom = "33.2.0" firebaseBom = "33.7.0"
gson = "2.12.1" gson = "2.12.1"
imagecropview = "3.0.1" imagecropview = "3.0.1"
jpushGoogle = "5.4.0" jpushGoogle = "5.4.0"
jwtdecode = "2.0.2" jwtdecode = "2.0.2"
kotlin = "1.9.10" kotlin = "2.2.21"
coreKtx = "1.10.1" ksp = "2.2.21-2.0.4"
composeCompiler = "2.2.21"
coreKtx = "1.15.0"
junit = "4.13.2" junit = "4.13.2"
junitVersion = "1.1.5" junitVersion = "1.2.1"
espressoCore = "3.5.1" espressoCore = "3.6.1"
kotlinFaker = "2.0.0-rc.5" kotlinFaker = "2.0.0-rc.11"
lifecycleRuntimeKtx = "2.6.1" lifecycleRuntimeKtx = "2.8.6"
activityCompose = "1.8.0" activityCompose = "1.9.2"
composeBom = "2024.06.00" composeBom = "2025.11.00"
lifecycleRuntimeKtxVersion = "2.6.2" lifecycleRuntimeKtxVersion = "2.8.6"
mapsCompose = "4.3.3" mapsCompose = "6.1.0"
material = "1.6.8" material = "1.7.6"
material3Android = "1.2.1" materialIconsExtended = "1.7.6"
media3Exoplayer = "1.3.1" material3Android = "1.3.1"
navigationCompose = "2.7.7" media3Exoplayer = "1.4.1"
pagingRuntime = "3.3.0" navigationCompose = "2.8.6"
activityKtx = "1.9.0" pagingRuntime = "3.3.6"
lifecycleCommonJvm = "2.8.2" activityKtx = "1.9.2"
places = "3.3.0" lifecycleCommonJvm = "2.8.6"
places = "3.4.0"
googleid = "1.1.1" googleid = "1.1.1"
identityCredential = "20231002" identityCredential = "20231002"
lifecycleProcess = "2.8.4" lifecycleProcess = "2.8.6"
playServicesAuth = "21.4.0" playServicesAuth = "21.4.0"
rendering = "1.17.1" rendering = "1.17.1"
zoomable = "1.6.1" zoomable = "1.6.1"
camerax = "1.3.4" camerax = "1.4.0"
mlkitBarcode = "17.3.0" mlkitBarcode = "17.3.0"
room = "2.6.1" room = "2.8.3"
[libraries] [libraries]
accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanistSystemuicontroller" } accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanistSystemuicontroller" }
@@ -53,6 +56,7 @@ androidx-credentials = { module = "androidx.credentials:credentials", version.re
androidx-credentials-play-services-auth = { module = "androidx.credentials:credentials-play-services-auth", version.ref = "credentialsPlayServicesAuth" } androidx-credentials-play-services-auth = { module = "androidx.credentials:credentials-play-services-auth", version.ref = "credentialsPlayServicesAuth" }
androidx-lifecycle-runtime-ktx-v262 = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtxVersion" } androidx-lifecycle-runtime-ktx-v262 = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtxVersion" }
androidx-material = { module = "androidx.compose.material:material", version.ref = "material" } androidx-material = { module = "androidx.compose.material:material", version.ref = "material" }
androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" } androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" }
androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "media3Exoplayer" } androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "media3Exoplayer" }
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Exoplayer" } androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Exoplayer" }
@@ -62,8 +66,9 @@ androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.r
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" } androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camerax" } androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camerax" }
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "camerax" } androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "camerax" }
coil = { module = "io.coil-kt:coil", version.ref = "coil" } coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" }
compose-image-blurhash = { module = "com.github.orlando-dev-code:compose-image-blurhash", version.ref = "composeImageBlurhash" } compose-image-blurhash = { module = "com.github.orlando-dev-code:compose-image-blurhash", version.ref = "composeImageBlurhash" }
converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" } converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" }
eventbus = { module = "org.greenrobot:eventbus", version.ref = "eventbus" } eventbus = { module = "org.greenrobot:eventbus", version.ref = "eventbus" }
@@ -79,7 +84,7 @@ junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version = "1.9.0" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" } androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
@@ -104,7 +109,7 @@ play-services-auth = { module = "com.google.android.gms:play-services-auth", ver
rendering = { group = "com.google.ar.sceneform", name = "rendering", version.ref = "rendering" } rendering = { group = "com.google.ar.sceneform", name = "rendering", version.ref = "rendering" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "converterGson" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "converterGson" }
zoomable = { module = "net.engawapg.lib:zoomable", version.ref = "zoomable" } zoomable = { module = "net.engawapg.lib:zoomable", version.ref = "zoomable" }
lottie = { module="com.airbnb.android:lottie-compose", version="6.6.10"} lottie = { module="com.airbnb.android:lottie-compose", version="6.7.0"}
mlkit-barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "mlkitBarcode" } mlkit-barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "mlkitBarcode" }
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
@@ -112,3 +117,5 @@ androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref =
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "composeCompiler" }

View File

@@ -1,6 +1,6 @@
#Fri Jun 14 03:23:01 CST 2024 #Fri Jun 14 03:23:01 CST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists