修正动态页面错误

This commit is contained in:
2024-10-27 11:31:27 +08:00
parent be18a60b2b
commit 5b3d663a73
5 changed files with 267 additions and 66 deletions

View File

@@ -48,7 +48,6 @@ class MainActivity : ComponentActivity() {
private lateinit var analytics: FirebaseAnalytics
private val scope = CoroutineScope(Dispatchers.Main)
val context = this
private val apkInstallReceiver = ApkInstallReceiver()
// 请求通知权限
private val requestPermissionLauncher = registerForActivityResult(
@@ -184,11 +183,6 @@ class MainActivity : ComponentActivity() {
}
}
override fun onDestroy() {
super.onDestroy()
// 取消注册广播接收器
unregisterReceiver(apkInstallReceiver)
}
/**
* 请求通知权限

View File

@@ -146,10 +146,19 @@ fun NavigationController(
navArgument("highlightCommentId") { type = NavType.IntType },
navArgument("initImagePagerIndex") { type = NavType.IntType }
),
enterTransition = {
fadeIn(animationSpec = tween(durationMillis = 200))
},
exitTransition = {
fadeOut(animationSpec = tween(durationMillis = 200))
},
popEnterTransition = {
fadeIn(animationSpec = tween(durationMillis = 200))
},
popExitTransition = {
fadeOut(animationSpec = tween(durationMillis = 200))
}
) { backStackEntry ->
CompositionLocalProvider(
LocalAnimatedContentScope provides this,
) {
val id = backStackEntry.arguments?.getString("id")
val highlightCommentId =
backStackEntry.arguments?.getInt("highlightCommentId")?.let {
@@ -162,7 +171,7 @@ fun NavigationController(
initImagePagerIndex = initIndex
)
}
}
composable(route = NavigationRoute.ModificationList.route,
enterTransition = {
fadeIn(animationSpec = tween(durationMillis = 0))
@@ -290,11 +299,9 @@ fun NavigationController(
AccountEditScreen2()
}
composable(route = NavigationRoute.ImageViewer.route) {
CompositionLocalProvider(
LocalAnimatedContentScope provides this,
) {
ImageViewer()
}
}
composable(route = NavigationRoute.ChangePasswordScreen.route) {
ChangePasswordScreen()

View File

@@ -1,8 +1,9 @@
package com.aiosman.riderpro.ui.imageviewer
import androidx.lifecycle.ViewModel
import com.aiosman.riderpro.entity.MomentImageEntity
object ImageViewerViewModel {
object ImageViewerViewModel:ViewModel() {
var imageList = mutableListOf<MomentImageEntity>()
var initialIndex = 0
fun asNew(images: List<MomentImageEntity>, index: Int = 0) {

View File

@@ -1,6 +1,5 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -14,7 +13,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape

View File

@@ -1,17 +1,21 @@
package com.aiosman.riderpro.ui.post
import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.rememberSplineBasedDecay
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -19,20 +23,25 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerDefaults
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.ModalBottomSheet
@@ -40,8 +49,10 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -49,9 +60,11 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
@@ -67,6 +80,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
@@ -74,10 +88,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.aiosman.riderpro.AppState
import com.aiosman.riderpro.LocalAnimatedContentScope
import com.aiosman.riderpro.LocalAppTheme
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.LocalSharedTransitionScope
import com.aiosman.riderpro.R
import com.aiosman.riderpro.entity.CommentEntity
import com.aiosman.riderpro.entity.MomentEntity
@@ -94,9 +106,11 @@ import com.aiosman.riderpro.ui.composables.CustomClickableText
import com.aiosman.riderpro.ui.composables.EditCommentBottomModal
import com.aiosman.riderpro.ui.composables.FollowButton
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.aiosman.riderpro.utils.FileUtil.saveImageToGallery
import kotlinx.coroutines.launch
import net.engawapg.lib.zoomable.rememberZoomState
import net.engawapg.lib.zoomable.zoomable
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -109,6 +123,7 @@ fun PostScreen(
key = "PostViewModel_$id",
factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
Log.d("PostViewModel", "Create PostViewModel with id: $id")
return PostViewModel(id) as T
}
}
@@ -730,49 +745,219 @@ fun Header(
}
}
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun ImageViewerDialog(
images: List<MomentImageEntity>,
initialPage: Int,
onDismiss: () -> Unit
) {
val scope = rememberCoroutineScope()
val context = LocalContext.current
val pagerState = rememberPagerState(pageCount = { images.size }, initialPage = initialPage)
val navigationBarPaddings =
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 16.dp
val showRawImageStates = remember { mutableStateListOf(*Array(images.size) { false }) }
var isDownloading by remember { mutableStateOf(false) }
BasicAlertDialog(
onDismissRequest = {
onDismiss()
},
modifier = Modifier.fillMaxWidth(),
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true,
usePlatformDefaultWidth = false,
)
@OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class)
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.Black),
horizontalAlignment = Alignment.CenterHorizontally
) {
HorizontalPager(
state = pagerState,
modifier = Modifier
.fillMaxWidth()
.weight(0.8f),
) { page ->
val zoomState = rememberZoomState()
CustomAsyncImage(
context,
if (showRawImageStates[page]) images[page].url else images[page].thumbnail,
contentDescription = null,
modifier = Modifier
.fillMaxSize()
.zoomable(
zoomState = zoomState,
onTap = {
onDismiss()
}
),
contentScale = ContentScale.Fit,
)
}
Box(modifier = Modifier.padding(top = 10.dp, bottom = 10.dp)) {
if (images.size > 1) {
Box(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color(0xff333333).copy(alpha = 0.6f))
.padding(vertical = 4.dp, horizontal = 24.dp)
) {
androidx.compose.material.Text(
text = "${pagerState.currentPage + 1}/${images.size}",
color = Color.White,
)
}
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.weight(0.2f)
.background(
Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black
),
)
)
.padding(start = 16.dp, end = 16.dp, bottom = navigationBarPaddings),
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 72.dp, end = 72.dp)
.padding(top = 16.dp),
horizontalArrangement = Arrangement.Center
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.noRippleClickable {
if (isDownloading) {
return@noRippleClickable
}
isDownloading = true
scope.launch {
saveImageToGallery(context, images[pagerState.currentPage].url)
isDownloading = false
}
}
) {
if (isDownloading) {
CircularProgressIndicator(
modifier = Modifier.size(32.dp),
color = Color.White
)
} else {
androidx.compose.material.Icon(
painter = painterResource(id = R.drawable.rider_pro_download_icon),
contentDescription = "",
modifier = Modifier.size(32.dp),
tint = Color.White
)
}
Spacer(modifier = Modifier.height(4.dp))
androidx.compose.material.Text(
stringResource(R.string.download),
color = Color.White
)
}
if (!showRawImageStates[pagerState.currentPage]) {
Spacer(modifier = Modifier.weight(1f))
}
if (!showRawImageStates[pagerState.currentPage]) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.noRippleClickable {
showRawImageStates[pagerState.currentPage] = true
}
) {
androidx.compose.material.Icon(
painter = painterResource(id = R.drawable.rider_pro_original_raw),
contentDescription = "",
modifier = Modifier.size(32.dp),
tint = Color.White
)
Spacer(modifier = Modifier.height(4.dp))
androidx.compose.material.Text(
stringResource(R.string.original),
color = Color.White
)
}
}
}
}
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PostImageView(
images: List<MomentImageEntity>,
initialPage: Int? = 0
) {
val pagerState = rememberPagerState(pageCount = { images.size }, initialPage = initialPage ?: 0)
val navController = LocalNavController.current
val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedVisibilityScope = LocalAnimatedContentScope.current
val context = LocalContext.current
Column {
var isImageViewerDialog by remember { mutableStateOf(false) }
DisposableEffect(Unit) {
onDispose {
isImageViewerDialog = false
}
}
if (isImageViewerDialog) {
ImageViewerDialog(
images = images,
initialPage = pagerState.currentPage
) {
isImageViewerDialog = false
}
}
Column(
modifier = Modifier
) {
HorizontalPager(
state = pagerState,
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.pointerInput(Unit) {
detectTapGestures(
onTap = {
isImageViewerDialog = true
}
)
}
.background(Color.Gray.copy(alpha = 0.1f)),
flingBehavior = PagerDefaults.flingBehavior(state = pagerState,
snapAnimationSpec = spring(
dampingRatio = Spring.DampingRatioNoBouncy,
stiffness = Spring.StiffnessMedium,
))
) { page ->
val image = images[page]
with(sharedTransitionScope) {
CustomAsyncImage(
context,
image.thumbnail,
contentDescription = "Image",
contentScale = ContentScale.Crop,
modifier = Modifier
.sharedElement(
rememberSharedContentState(key = image),
animatedVisibilityScope = animatedVisibilityScope
)
.fillMaxSize()
.noRippleClickable {
ImageViewerViewModel.asNew(images, page)
navController.navigate(
NavigationRoute.ImageViewer.route
)
}
)
}
}
// Indicator container
Row(
@@ -804,6 +989,7 @@ fun PostImageView(
}
@Composable
fun PostDetails(
momentEntity: MomentEntity?
@@ -884,7 +1070,12 @@ fun CommentItem(
}
) {}
) {
Text(text = commentEntity.name, fontWeight = FontWeight.W600, fontSize = 14.sp, color = AppColors.text)
Text(
text = commentEntity.name,
fontWeight = FontWeight.W600,
fontSize = 14.sp,
color = AppColors.text
)
Row {
if (isChild) {
val annotatedText = buildAnnotatedString {
@@ -988,7 +1179,11 @@ fun CommentItem(
},
modifier = Modifier.size(20.dp)
)
Text(text = commentEntity.likes.toString(), fontSize = 12.sp, color = AppColors.text)
Text(
text = commentEntity.likes.toString(),
fontSize = 12.sp,
color = AppColors.text
)
}
}
Spacer(modifier = Modifier.height(8.dp))
@@ -1102,7 +1297,7 @@ fun PostBottomBar(
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(text = momentEntity?.likeCount.toString(),color = AppColors.text)
Text(text = momentEntity?.likeCount.toString(), color = AppColors.text)
Spacer(modifier = Modifier.width(16.dp))
AnimatedFavouriteIcon(
isFavourite = momentEntity?.isFavorite == true,
@@ -1110,7 +1305,7 @@ fun PostBottomBar(
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(text = momentEntity?.favoriteCount.toString(),color = AppColors.text)
Text(text = momentEntity?.favoriteCount.toString(), color = AppColors.text)
}
BottomNavigationPlaceholder(
@@ -1244,14 +1439,20 @@ fun CommentMenuModal(
.background(AppColors.background)
.padding(vertical = 24.dp, horizontal = 20.dp)
) {
Text(stringResource(R.string.comment), fontSize = 18.sp, fontWeight = FontWeight.Bold, color = AppColors.text)
Text(
stringResource(R.string.comment),
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = AppColors.text
)
Spacer(modifier = Modifier.height(24.dp))
commentEntity?.let {
Column(
modifier = Modifier
.clip(RoundedCornerShape(8.dp))
.background(
AppColors.nonActive)
AppColors.nonActive
)
.padding(8.dp)
) {