diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b7548e2..1659d8f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -76,5 +76,8 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - implementation ("com.google.android.libraries.places:places:3.3.0") + implementation (libs.places) + implementation(libs.androidx.animation) + + } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/CommentModal.kt b/app/src/main/java/com/aiosman/riderpro/CommentModal.kt index fc917bc..ac3ee6c 100644 --- a/app/src/main/java/com/aiosman/riderpro/CommentModal.kt +++ b/app/src/main/java/com/aiosman/riderpro/CommentModal.kt @@ -13,12 +13,12 @@ import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -39,13 +39,18 @@ import androidx.compose.ui.unit.sp @Preview @Composable -fun CommentModalContent() { +fun CommentModalContent(onDismiss: () -> Unit = {}) { val insets = WindowInsets val imePadding = insets.ime.getBottom(density = LocalDensity.current) var bottomPadding by remember { mutableStateOf(0.dp) } LaunchedEffect(imePadding) { bottomPadding = imePadding.dp } + DisposableEffect(Unit) { + onDispose { + onDismiss() + } + } Column( modifier = Modifier.height(500.dp) @@ -92,8 +97,6 @@ fun CommentModalContent() { Box( modifier = Modifier .fillMaxWidth() - - .weight(1f) .clip(RoundedCornerShape(20.dp)) .background(Color(0xffe5e5e5)) diff --git a/app/src/main/java/com/aiosman/riderpro/CommentsScreen.kt b/app/src/main/java/com/aiosman/riderpro/CommentsScreen.kt index 8297ae9..3b294cd 100644 --- a/app/src/main/java/com/aiosman/riderpro/CommentsScreen.kt +++ b/app/src/main/java/com/aiosman/riderpro/CommentsScreen.kt @@ -3,24 +3,22 @@ package com.aiosman.riderpro import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight @@ -70,7 +68,10 @@ fun NoticeScreenHeader( Image( painter = painterResource(id = R.drawable.rider_pro_nav_back), contentDescription = title, - modifier = Modifier.size(16.dp).clickable { + modifier = Modifier.size(16.dp).clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { nav.popBackStack() } ) diff --git a/app/src/main/java/com/aiosman/riderpro/Gallery.kt b/app/src/main/java/com/aiosman/riderpro/Gallery.kt index 8f6aa3e..0b80ff8 100644 --- a/app/src/main/java/com/aiosman/riderpro/Gallery.kt +++ b/app/src/main/java/com/aiosman/riderpro/Gallery.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -30,16 +31,20 @@ import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.google.accompanist.systemuicontroller.rememberSystemUiController import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @@ -47,11 +52,15 @@ import kotlinx.coroutines.launch fun GalleryPage() { val pagerState = rememberPagerState(pageCount = { 2 }) val scope = rememberCoroutineScope() + val systemUiController = rememberSystemUiController() fun switchToPage(page: Int) { scope.launch { pagerState.animateScrollToPage(page) } } + LaunchedEffect(Unit) { + systemUiController.setNavigationBarColor(Color.Transparent) + } Scaffold( topBar = { TopAppBar( @@ -148,6 +157,26 @@ fun DashedVerticalLine(modifier: Modifier = Modifier) { } } } +@Composable +fun DashedLine() { + Canvas(modifier = Modifier + .width(1.dp) // 控制线条的宽度 + .fillMaxHeight()) { // 填满父容器的高度 + + val canvasWidth = size.width + val canvasHeight = size.height + + // 创建一个PathEffect来定义如何绘制线段 + val pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f) + + drawLine( + color = Color.Gray, // 线条颜色 + start = Offset(x = canvasWidth / 2, y = 0f), // 起始点 + end = Offset(x = canvasWidth / 2, y = canvasHeight), // 终点 + pathEffect = pathEffect // 应用虚线效果 + ) + } +} @Preview @Composable fun TimelineItem() { @@ -172,12 +201,13 @@ fun TimelineItem() { Text("12", fontSize = 22.sp, fontWeight = androidx.compose.ui.text.font.FontWeight.Bold) Text("7月", fontSize = 20.sp,fontWeight = androidx.compose.ui.text.font.FontWeight.Bold) // add vertical dash line - Box( - modifier = Modifier - .height(120.dp) - .width(3.dp) - .background(Color.Gray) - ) +// Box( +// modifier = Modifier +// .height(120.dp) +// .width(3.dp) +// .background(Color.Gray) +// ) + DashedLine() } Column { Row( diff --git a/app/src/main/java/com/aiosman/riderpro/HomeViewModel.kt b/app/src/main/java/com/aiosman/riderpro/HomeViewModel.kt new file mode 100644 index 0000000..f94ab49 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/HomeViewModel.kt @@ -0,0 +1,24 @@ +package com.aiosman.riderpro + +import androidx.lifecycle.ViewModel + +private val DATA = (0..60).toList().mapIndexed { idx, _ -> + MomentItem( + id = idx, + avatar = R.drawable.default_avatar, + nickname = "Onyama Limba", + location = "Japan", + time = "2023.02.02 11:23", + followStatus = false, + momentTextContent = "By strongarming Ducati into giving him the factory seat.Marquez effectively …", + momentPicture = R.drawable.default_moment_img, + likeCount = 21, + commentCount = 43, + shareCount = 33, + favoriteCount = 211 + ) +} + +object HomeViewModel : ViewModel() { + val momentList = DATA +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/MainActivity.kt b/app/src/main/java/com/aiosman/riderpro/MainActivity.kt index e4638e9..2ef423c 100644 --- a/app/src/main/java/com/aiosman/riderpro/MainActivity.kt +++ b/app/src/main/java/com/aiosman/riderpro/MainActivity.kt @@ -5,16 +5,16 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.animation.AnimatedContentScope +import androidx.compose.animation.ExperimentalSharedTransitionApi +import androidx.compose.animation.SharedTransitionLayout +import androidx.compose.animation.SharedTransitionScope import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height @@ -22,27 +22,17 @@ import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.PagerState -import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.Icon import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItemColors import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface -import androidx.compose.material3.Tab -import androidx.compose.material3.TabRow -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -50,20 +40,19 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.view.WindowCompat -import androidx.navigation.NavGraph -import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController +import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument import com.aiosman.riderpro.ui.theme.RiderProTheme import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.android.libraries.places.api.Places -import kotlinx.coroutines.launch - class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) @@ -81,38 +70,32 @@ val LocalNavController = compositionLocalOf { error("NavController not provided") } +@OptIn(ExperimentalSharedTransitionApi::class) +val LocalSharedTransitionScope = compositionLocalOf { + error("SharedTransitionScope not provided") +} + +val LocalAnimatedContentScope = compositionLocalOf { + error("AnimatedContentScope not provided") +} + +@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun NavigationController(navController: NavHostController) { val navigationBarHeight = with(LocalDensity.current) { WindowInsets.navigationBars.getBottom(this).toDp() } + NavHost( navController = navController, startDestination = "Index", ) { - // 带底部导航栏的路由: -// listOf( -// NavigationItem.Home, -// NavigationItem.Street, -// NavigationItem.Add, -// NavigationItem.Message, -// NavigationItem.Profile -// ).forEach { item -> -// composable(route = item.route) { -// ScaffoldWithNavigationBar(navController) { -// when (item) { -// NavigationItem.Home -> Home() -// NavigationItem.Street -> Street() -// NavigationItem.Add -> Add() -// NavigationItem.Message -> Video() -// NavigationItem.Profile -> Profile() -// else -> {} // 由于过滤,这里不会发生 -// } -// } -// } -// } composable(route = "Index") { - ScaffoldWithNavigationBar2() + CompositionLocalProvider( + LocalAnimatedContentScope provides this, + ) { + ScaffoldWithNavigationBar2() + } } composable(route = "ProfileTimeline") { GalleryPage() @@ -130,26 +113,30 @@ fun NavigationController(navController: NavHostController) { composable(route = "OfficialPhotographer") { OfficialPhotographer() } - composable(route = "Post") { - - PostPage() - + composable( + route = "Post/{id}", + arguments = listOf(navArgument("id") { type = NavType.StringType }) + ) { backStackEntry -> + CompositionLocalProvider( + LocalAnimatedContentScope provides this, + ) { + val id = backStackEntry.arguments?.getString("id") + PostPage( + id!! + ) + } } composable(route = "ModificationList") { ModificationListScreen() } composable(route = "MyMessage") { - NotificationsScreen() - } composable(route = "Comments") { CommentsScreen() } composable(route = "Likes") { - LikePage() - } composable(route = "Followers") { FollowerPage() @@ -165,14 +152,22 @@ fun NavigationController(navController: NavHostController) { } } } + + } +@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun Navigation() { val navController = rememberNavController() - CompositionLocalProvider(LocalNavController provides navController) { - Box { - NavigationController(navController = navController) + SharedTransitionLayout { + CompositionLocalProvider( + LocalNavController provides navController, + LocalSharedTransitionScope provides this@SharedTransitionLayout, + ) { + Box { + NavigationController(navController = navController) + } } } } @@ -271,9 +266,9 @@ fun ScaffoldWithNavigationBar( } } +@OptIn(ExperimentalSharedTransitionApi::class) @Composable -fun ScaffoldWithNavigationBar2( -) { +fun ScaffoldWithNavigationBar2() { val model = IndexViewModel val navigationBarHeight = with(LocalDensity.current) { WindowInsets.navigationBars.getBottom(this).toDp() @@ -344,7 +339,10 @@ fun ScaffoldWithNavigationBar2( when (model.tabIndex) { 0 -> Box( modifier = Modifier.padding(innerPadding) - ) { Home() } + ) { + Home() + } + 1 -> Street() 2 -> Box( modifier = Modifier.padding(innerPadding) diff --git a/app/src/main/java/com/aiosman/riderpro/MessageList.kt b/app/src/main/java/com/aiosman/riderpro/MessageList.kt index b5b46aa..b53cfc6 100644 --- a/app/src/main/java/com/aiosman/riderpro/MessageList.kt +++ b/app/src/main/java/com/aiosman/riderpro/MessageList.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -32,12 +33,17 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.google.accompanist.systemuicontroller.rememberSystemUiController @Preview(showBackground = true) @Composable fun NotificationsScreen() { val navController = LocalNavController.current + val systemUiController = rememberSystemUiController() + LaunchedEffect(Unit) { + systemUiController.setNavigationBarColor(Color.Transparent) + } StatusBarMaskLayout(darkIcons = true) { Column( modifier = Modifier.fillMaxWidth().weight(1f) diff --git a/app/src/main/java/com/aiosman/riderpro/ModificationList.kt b/app/src/main/java/com/aiosman/riderpro/ModificationList.kt index 3da4f7f..af4378e 100644 --- a/app/src/main/java/com/aiosman/riderpro/ModificationList.kt +++ b/app/src/main/java/com/aiosman/riderpro/ModificationList.kt @@ -1,8 +1,6 @@ import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -10,32 +8,27 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.aiosman.riderpro.BottomNavigationPlaceholder -import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.NoticeScreenHeader -import com.aiosman.riderpro.R -import com.aiosman.riderpro.StatusBarMask import com.aiosman.riderpro.StatusBarMaskLayout - +import com.google.accompanist.systemuicontroller.rememberSystemUiController @Preview @Composable fun ModificationListScreen() { - val navController = LocalNavController.current + val systemUiController = rememberSystemUiController() + LaunchedEffect(Unit) { + systemUiController.setNavigationBarColor(Color.Transparent) + } val modifications = getModifications() StatusBarMaskLayout { Column( diff --git a/app/src/main/java/com/aiosman/riderpro/MomentItem.kt b/app/src/main/java/com/aiosman/riderpro/MomentItem.kt index 75bdc50..d363d8f 100644 --- a/app/src/main/java/com/aiosman/riderpro/MomentItem.kt +++ b/app/src/main/java/com/aiosman/riderpro/MomentItem.kt @@ -46,7 +46,7 @@ val profileMomentItems = listOf( shareCount = 33, favoriteCount = 211), MomentItem( - id = 1, + id = 2, avatar = R.drawable.default_avatar, nickname = "Onyama Limba", location = "Japan", @@ -59,7 +59,7 @@ val profileMomentItems = listOf( shareCount = 33, favoriteCount = 211), MomentItem( - id = 1, + id = 3, avatar = R.drawable.default_avatar, nickname = "Onyama Limba", location = "Japan", diff --git a/app/src/main/java/com/aiosman/riderpro/NewPost.kt b/app/src/main/java/com/aiosman/riderpro/NewPost.kt index f3832c1..f01f07f 100644 --- a/app/src/main/java/com/aiosman/riderpro/NewPost.kt +++ b/app/src/main/java/com/aiosman/riderpro/NewPost.kt @@ -7,6 +7,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -37,7 +38,6 @@ import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight @@ -86,7 +86,10 @@ fun NewPostTopBar() { Image( painter = painterResource(id = R.drawable.rider_pro_close), contentDescription = "Back", - modifier = Modifier.size(24.dp).clickable { + modifier = Modifier.size(24.dp).clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { navController.popBackStack() } ) @@ -172,7 +175,10 @@ fun AddImageGrid() { .drawBehind { drawRoundRect(color = Color(0xFF999999), style = stroke) } - .clickable { + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { Intent(Intent.ACTION_PICK).apply { type = "image/*" pickImageLauncher.launch(this) @@ -228,7 +234,10 @@ fun AdditionalPostItem() { modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp, horizontal = 24.dp) - .clickable { + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { onSelectLocationClick() } ) { @@ -258,7 +267,10 @@ fun AdditionalPostItem() { modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp, horizontal = 24.dp) - .clickable { + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { navController.navigate("EditModification") } ) { @@ -311,7 +323,10 @@ fun SelectedLocation( contentDescription = "Next", modifier = Modifier .size(24.dp) - .clickable { + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { onRemoveLocation() } ) diff --git a/app/src/main/java/com/aiosman/riderpro/PagingSimple.kt b/app/src/main/java/com/aiosman/riderpro/PagingSimple.kt index a81a00b..f3cbe71 100644 --- a/app/src/main/java/com/aiosman/riderpro/PagingSimple.kt +++ b/app/src/main/java/com/aiosman/riderpro/PagingSimple.kt @@ -1,11 +1,11 @@ package com.aiosman.riderpro import androidx.annotation.DrawableRes +import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -26,7 +25,6 @@ import androidx.compose.material.icons.filled.Build import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState @@ -39,67 +37,89 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.PlatformTextStyle import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.LineHeightStyle import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp -import androidx.paging.LoadState -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.compose.collectAsLazyPagingItems +import com.google.accompanist.systemuicontroller.rememberSystemUiController -private val DATA = (0..60).toList().map { momentTestItem } +private val DATA = (0..60).toList().mapIndexed { idx, _ -> + MomentItem( + id = idx, + avatar = R.drawable.default_avatar, + nickname = "Onyama Limba", + location = "Japan", + time = "2023.02.02 11:23", + followStatus = false, + momentTextContent = "By strongarming Ducati into giving him the factory seat.Marquez effectively …", + momentPicture = R.drawable.default_moment_img, + likeCount = 21, + commentCount = 43, + shareCount = 33, + favoriteCount = 211 + ) +} +@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun PagingBackendSample() { - val myBackend = remember { TestBackend(DATA) } - val pager = remember { - Pager( - PagingConfig( - pageSize = myBackend.DataBatchSize, - enablePlaceholders = true, - maxSize = 200 - ) - ) { - myBackend.getAllData() - } - } - val lazyPagingItems = pager.flow.collectAsLazyPagingItems() + +// val myBackend = remember { TestBackend(DATA) } +// val pager = remember { +// Pager( +// PagingConfig( +// pageSize = myBackend.DataBatchSize, +// enablePlaceholders = true, +// maxSize = 200 +// ) +// ) { +// myBackend.getAllData() +// } +// } + val model = HomeViewModel +// val lazyPagingItems = model.pager.collectAsLazyPagingItems() LazyColumn { - if (lazyPagingItems.loadState.refresh == LoadState.Loading) { - item { - MomentListLoading() - } - } - items(count = lazyPagingItems.itemCount) { index -> - val item = lazyPagingItems[index] +// if (lazyPagingItems.loadState.refresh == LoadState.Loading) { +// item { +// MomentListLoading() +// } +// } + items(count = model.momentList.size) { index -> + val item = model.momentList.getOrNull(index) if (item != null) { MomentCard(item) } } - if (lazyPagingItems.loadState.append == LoadState.Loading) { - item { - MomentListLoading() - } - } +// if (lazyPagingItems.loadState.append == LoadState.Loading) { +// item { +// MomentListLoading() +// } +// } } } +@OptIn(ExperimentalSharedTransitionApi::class) @Composable -fun MomentCard(momentItem: MomentItem) { +fun MomentCard( + momentItem: MomentItem, +) { + val navController = LocalNavController.current Column( modifier = Modifier.fillMaxWidth() ) { MomentTopRowGroup(momentItem = momentItem) - MomentContentGroup(momentItem = momentItem) + Column( + modifier = Modifier + .fillMaxWidth() + .clickable { + navController.navigate("Post/${momentItem.id}") + } + ) { + MomentContentGroup(momentItem = momentItem) + } + val momentOperateBtnBoxModifier = Modifier .fillMaxHeight() .weight(1f) @@ -121,7 +141,10 @@ fun ModificationListHeader() { .fillMaxWidth() .background(Color(0xFFF8F8F8)) .padding(4.dp) - .clickable { + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { navController.navigate("ModificationList") } ) { @@ -239,21 +262,37 @@ fun MomentTopRowGroup(momentItem: MomentItem) { } } +@OptIn(ExperimentalSharedTransitionApi::class) @Composable -fun MomentContentGroup(momentItem: MomentItem) { - Text( - text = momentItem.momentTextContent, - modifier = Modifier - .fillMaxWidth() - .padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp), - fontSize = 16.sp - ) - Image( - modifier = Modifier - .fillMaxWidth(), - painter = painterResource(id = momentItem.momentPicture), - contentDescription = "" - ) +fun MomentContentGroup( + momentItem: MomentItem, +) { + val sharedTransitionScope = LocalSharedTransitionScope.current + val animatedContentScope = LocalAnimatedContentScope.current + with(sharedTransitionScope) { + Text( + text = momentItem.momentTextContent, + modifier = Modifier + .sharedElement( + sharedTransitionScope.rememberSharedContentState(key = "text-${momentItem.id}"), + animatedVisibilityScope = animatedContentScope + ) + .fillMaxWidth() + .padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp), + fontSize = 16.sp + ) + Image( + modifier = Modifier + .sharedElement( + sharedTransitionScope.rememberSharedContentState(key = "image-${momentItem.id}"), + animatedVisibilityScope = animatedContentScope + ) + .fillMaxWidth(), + painter = painterResource(id = momentItem.momentPicture), + contentDescription = "" + ) + } + } @Composable @@ -276,6 +315,7 @@ fun MomentOperateBtn(@DrawableRes icon: Int, count: String) { @OptIn(ExperimentalMaterial3Api::class) @Composable fun MomentBottomOperateRowGroup(modifier: Modifier) { + var systemUiController = rememberSystemUiController() var showCommentModal by remember { mutableStateOf(false) } if (showCommentModal) { ModalBottomSheet( @@ -285,7 +325,10 @@ fun MomentBottomOperateRowGroup(modifier: Modifier) { skipPartiallyExpanded = true ) ) { - CommentModalContent() + systemUiController.setNavigationBarColor(Color(0xfff7f7f7)) + CommentModalContent() { + systemUiController.setNavigationBarColor(Color.Black) + } } } Row( @@ -300,7 +343,10 @@ fun MomentBottomOperateRowGroup(modifier: Modifier) { MomentOperateBtn(icon = R.drawable.rider_pro_like, count = "21") } Box( - modifier = modifier.clickable { + modifier = modifier.clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { showCommentModal = true }, contentAlignment = Alignment.Center diff --git a/app/src/main/java/com/aiosman/riderpro/Post.kt b/app/src/main/java/com/aiosman/riderpro/Post.kt index 4528aa9..f60ca66 100644 --- a/app/src/main/java/com/aiosman/riderpro/Post.kt +++ b/app/src/main/java/com/aiosman/riderpro/Post.kt @@ -1,6 +1,7 @@ package com.aiosman.riderpro import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.animateContentSize import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image @@ -39,7 +40,6 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -54,7 +54,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch @@ -67,12 +66,14 @@ fun makeMockImages(): List { ) } -@Preview + +@OptIn(ExperimentalSharedTransitionApi::class) @Composable -fun PostPage() { +fun PostPage( + id: String, +) { var showCollapseContent by remember { mutableStateOf(true) } val scrollState = rememberLazyListState() - StatusBarMaskLayout { Scaffold( modifier = Modifier.fillMaxSize(), @@ -91,9 +92,15 @@ fun PostPage() { .aspectRatio(1f) ) { - PostImageView(makeMockImages()) + PostImageView( + id, + makeMockImages(), + ) + } - PostDetails() + PostDetails( + id, + ) } } } @@ -109,6 +116,7 @@ fun PostPage() { } } } + } @Composable @@ -163,62 +171,85 @@ data class PostImage( val description: String ) -@OptIn(ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class) @Composable -fun PostImageView(images: List) { +fun PostImageView( + postId: String, + images: List, +) { + val sharedTransitionScope = LocalSharedTransitionScope.current + val animatedContentScope = LocalAnimatedContentScope.current val pagerState = rememberPagerState(pageCount = { images.size }) - Column { - HorizontalPager( - state = pagerState, - modifier = Modifier - .weight(1f) - .fillMaxWidth() - ) { page -> - Image( - painter = painterResource(id = images[page].imgRes), - contentDescription = images[page].description, - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxSize() - ) - } - - // Indicator container - Row( - modifier = Modifier - .padding(8.dp) - .fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - images.forEachIndexed { index, _ -> - Box( - modifier = Modifier - .size(8.dp) - .clip(CircleShape) - - .background( - if (pagerState.currentPage == index) Color.Red else Color.Gray.copy( - alpha = 0.5f - ) + with(sharedTransitionScope) { + Column { + HorizontalPager( + state = pagerState, + modifier = Modifier + .weight(1f) + .fillMaxWidth() + ) { page -> + Image( + painter = painterResource(id = images[page].imgRes), + contentDescription = images[page].description, + contentScale = ContentScale.Crop, + modifier = Modifier.Companion + .sharedElement( + sharedTransitionScope.rememberSharedContentState(key = "image-$postId"), + animatedVisibilityScope = animatedContentScope ) - .padding(4.dp) - - + .fillMaxSize() ) - Spacer(modifier = Modifier.width(8.dp)) + } + + // Indicator container + Row( + modifier = Modifier + .padding(8.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + images.forEachIndexed { index, _ -> + Box( + modifier = Modifier + .size(8.dp) + .clip(CircleShape) + + .background( + if (pagerState.currentPage == index) Color.Red else Color.Gray.copy( + alpha = 0.5f + ) + ) + .padding(4.dp) + + + ) + Spacer(modifier = Modifier.width(8.dp)) + } } } } } +@OptIn(ExperimentalSharedTransitionApi::class) @Composable -fun PostDetails() { +fun PostDetails( + postId: String, +) { + val sharedTransitionScope = LocalSharedTransitionScope.current + val animatedContentScope = LocalAnimatedContentScope.current + with(sharedTransitionScope) { Column(modifier = Modifier.padding(16.dp)) { - Text(text = "这里太适合骑行了", fontSize = 16.sp, fontWeight = FontWeight.Bold) + + Text(text = "By strongarming Ducati into giving him the factory seat.Marquez effectively …", fontSize = 16.sp, fontWeight = FontWeight.Bold, modifier = Modifier.Companion.sharedElement( + sharedTransitionScope.rememberSharedContentState(key = "text-$postId"), + animatedVisibilityScope = animatedContentScope + )) Text(text = "12-11 发布") Spacer(modifier = Modifier.height(8.dp)) Text(text = "共231条评论") } } +} fun MakeMockComments(): List { return listOf( @@ -374,7 +405,10 @@ fun MakeMockComments(): List { } @Composable -fun CommentsSection(scrollState: LazyListState = rememberLazyListState(), onWillCollapse: (Boolean) -> Unit) { +fun CommentsSection( + scrollState: LazyListState = rememberLazyListState(), + onWillCollapse: (Boolean) -> Unit +) { val items = MakeMockComments() LazyColumn( state = scrollState, modifier = Modifier diff --git a/app/src/main/java/com/aiosman/riderpro/ShortViewCompose.kt b/app/src/main/java/com/aiosman/riderpro/ShortViewCompose.kt index 25f34d4..e1c5f83 100644 --- a/app/src/main/java/com/aiosman/riderpro/ShortViewCompose.kt +++ b/app/src/main/java/com/aiosman/riderpro/ShortViewCompose.kt @@ -1,6 +1,5 @@ package com.aiosman.riderpro -import android.app.Activity import android.net.Uri import android.view.Gravity import android.view.ViewGroup @@ -15,24 +14,28 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -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.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material3.Icon import androidx.compose.material3.Text -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +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.Color -import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner @@ -53,7 +56,6 @@ import androidx.media3.common.util.Util import androidx.media3.datasource.DataSource import androidx.media3.datasource.DefaultDataSourceFactory import androidx.media3.exoplayer.ExoPlayer -import androidx.media3.exoplayer.SimpleExoPlayer import androidx.media3.exoplayer.source.ProgressiveMediaSource import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.PlayerView @@ -174,7 +176,7 @@ fun VideoPlayer( hideController() useController = false player = exoPlayer - resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL // 或 RESIZE_MODE_ZOOM + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT // 或 RESIZE_MODE_ZOOM layoutParams = FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, diff --git a/app/src/main/java/com/aiosman/riderpro/SimpleUtils.kt b/app/src/main/java/com/aiosman/riderpro/SimpleUtils.kt index cf3aa83..f037a13 100644 --- a/app/src/main/java/com/aiosman/riderpro/SimpleUtils.kt +++ b/app/src/main/java/com/aiosman/riderpro/SimpleUtils.kt @@ -2,10 +2,10 @@ package com.aiosman.riderpro import androidx.paging.PagingSource import androidx.paging.PagingState -import kotlin.math.ceil import kotlinx.coroutines.delay +import kotlin.math.ceil -internal class TestBackend( +class TestBackend( private val backendDataList: List, private val loadDelay: Long = 500, ) { @@ -24,7 +24,7 @@ internal class TestBackend( } fun getAllData() = TestPagingSource(this, loadDelay) } -internal class TestPagingSource( +class TestPagingSource( private val backend: TestBackend, private val loadDelay: Long, ) : PagingSource() { diff --git a/app/src/main/java/com/aiosman/riderpro/Street.kt b/app/src/main/java/com/aiosman/riderpro/Street.kt index 2ae5053..adbbd61 100644 --- a/app/src/main/java/com/aiosman/riderpro/Street.kt +++ b/app/src/main/java/com/aiosman/riderpro/Street.kt @@ -6,6 +6,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -19,7 +20,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField -import androidx.compose.material3.Button import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -142,7 +142,10 @@ fun StreetPage() { contentDescription = "", modifier = Modifier .align(Alignment.BottomStart) - .padding(start = 16.dp, bottom = 16.dp + navigationBarHeight) .clickable { + .padding(start = 16.dp, bottom = 16.dp + navigationBarHeight) .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { currentLocation?.let { cameraPositionState.position = CameraPosition.fromLatLngZoom(it, cameraPositionState.position.zoom) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0f219f1..65c1bc5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] accompanistSystemuicontroller = "0.27.0" agp = "8.4.0" +animation = "1.7.0-beta05" kotlin = "1.9.0" coreKtx = "1.10.1" junit = "4.13.2" @@ -8,7 +9,7 @@ junitVersion = "1.1.5" espressoCore = "3.5.1" lifecycleRuntimeKtx = "2.6.1" activityCompose = "1.8.0" -composeBom = "2023.08.00" +composeBom = "2024.06.00" mapsCompose = "4.3.3" material3Android = "1.2.1" media3Exoplayer = "1.3.1" @@ -16,9 +17,11 @@ navigationCompose = "2.7.7" pagingRuntime = "3.3.0" activityKtx = "1.9.0" lifecycleCommonJvm = "2.8.2" +places = "3.3.0" [libraries] accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanistSystemuicontroller" } +androidx-animation = { module = "androidx.compose.animation:animation", version.ref = "animation" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" } androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "media3Exoplayer" } @@ -43,7 +46,7 @@ androidx-material3-android = { group = "androidx.compose.material3", name = "mat maps-compose = { module = "com.google.maps.android:maps-compose", version.ref = "mapsCompose" } androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityKtx" } androidx-lifecycle-common-jvm = { group = "androidx.lifecycle", name = "lifecycle-common-jvm", version.ref = "lifecycleCommonJvm" } - +places = { module = "com.google.android.libraries.places:places", version.ref = "places" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }