修正动态页面错误
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求通知权限
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user