diff --git a/app/src/main/java/com/aiosman/riderpro/LocationDetail.kt b/app/src/main/java/com/aiosman/riderpro/LocationDetail.kt index b33c38a..428a94c 100644 --- a/app/src/main/java/com/aiosman/riderpro/LocationDetail.kt +++ b/app/src/main/java/com/aiosman/riderpro/LocationDetail.kt @@ -290,9 +290,10 @@ fun LocationDetail() { Image( painter = painterResource(id = item.resId), contentDescription = "Feed", - modifier = Modifier - .fillMaxWidth() - .clip(MaterialTheme.shapes.medium), + modifier = Modifier.fillMaxWidth() + .clip(MaterialTheme.shapes.medium).clickable { + navController.navigate("Post") + }, contentScale = ContentScale.FillWidth ) Spacer(modifier = Modifier.height(8.dp)) diff --git a/app/src/main/java/com/aiosman/riderpro/MainActivity.kt b/app/src/main/java/com/aiosman/riderpro/MainActivity.kt index 15d66ff..b3214b4 100644 --- a/app/src/main/java/com/aiosman/riderpro/MainActivity.kt +++ b/app/src/main/java/com/aiosman/riderpro/MainActivity.kt @@ -95,6 +95,12 @@ fun NavigationController(navController: NavHostController) { composable(route="OfficialPhoto") { OfficialGalleryPage() } + composable(route="OfficialPhotographer") { + OfficialPhotographer() + } + composable(route="Post") { + PostPage() + } } } diff --git a/app/src/main/java/com/aiosman/riderpro/OfficialGallery.kt b/app/src/main/java/com/aiosman/riderpro/OfficialGallery.kt index 39d27f3..d82b282 100644 --- a/app/src/main/java/com/aiosman/riderpro/OfficialGallery.kt +++ b/app/src/main/java/com/aiosman/riderpro/OfficialGallery.kt @@ -2,6 +2,7 @@ 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.layout.Box import androidx.compose.foundation.layout.Column @@ -145,6 +146,7 @@ fun ImageGrid() { @Composable fun PhotographerCard(name: String, imageRes: Int) { + val navController = LocalNavController.current Box( modifier = Modifier .fillMaxSize() @@ -168,7 +170,10 @@ fun PhotographerCard(name: String, imageRes: Int) { Row( modifier = Modifier .fillMaxWidth() - .padding(8.dp), + .padding(8.dp) + .clickable { + navController.navigate("OfficialPhotographer") + }, verticalAlignment = Alignment.CenterVertically ) { Image( diff --git a/app/src/main/java/com/aiosman/riderpro/OfficialPhotographer.kt b/app/src/main/java/com/aiosman/riderpro/OfficialPhotographer.kt new file mode 100644 index 0000000..fc1cb95 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/OfficialPhotographer.kt @@ -0,0 +1,279 @@ +package com.aiosman.riderpro + +import android.util.Log +import androidx.compose.foundation.Image +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.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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.layout.ContentScale +import androidx.compose.ui.platform.LocalConfiguration +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 + +data class ArtWork( + val id: Int, + val resId: Int, +) + +fun GenerateMockArtWorks(): List { + val pickupImage = listOf( + R.drawable.default_avatar, + R.drawable.default_moment_img, + R.drawable.rider_pro_moment_demo_1, + R.drawable.rider_pro_moment_demo_2, + R.drawable.rider_pro_moment_demo_3, + ) + return List(30) { + ArtWork( + id = it, + resId = pickupImage.random() + ) + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Preview +@Composable +fun OfficialPhotographer() { + val lazyListState = rememberLazyListState() + var artWorks by remember { mutableStateOf>(emptyList()) } + LaunchedEffect(Unit) { + artWorks = GenerateMockArtWorks() + } + // Observe the scroll state and calculate opacity + val alpha by remember { + derivedStateOf { + // Example calculation: Adjust the range and formula as needed + val alp = minOf(1f, lazyListState.firstVisibleItemScrollOffset / 900f) + Log.d("alpha", "alpha: $alp") + alp + } + } + Scaffold { paddingValues -> + + Box( + modifier = Modifier + .background(Color.Black) + .padding(paddingValues) + + ) { + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = lazyListState + ) { + item { + Box( + modifier = Modifier + .height(400.dp) + .fillMaxWidth() + ) { + Image( + painter = painterResource(id = R.drawable.default_moment_img), + contentDescription = "Logo", + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxSize() + ) + // top bar + + // on bottom of box + Box( + modifier = Modifier + .fillMaxWidth() + .height(120.dp) + .background( + brush = Brush.verticalGradient( + colors = listOf( + Color.Black.copy(alpha = 1f), + Color.Black.copy(alpha = 1f), + Color.Black.copy(alpha = 0f), + ), + startY = Float.POSITIVE_INFINITY, + endY = 0f + ) + ) + .padding(16.dp) + .align(alignment = androidx.compose.ui.Alignment.BottomCenter) + + ) { + Column( + modifier = Modifier.fillMaxSize(), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.default_avatar), + contentDescription = "", + modifier = Modifier + .size(32.dp) + .clip(CircleShape) // Clip the image to a circle + ) + Spacer(modifier = Modifier.width(8.dp)) + // name + Text("Onyama Limba", color = Color.White, fontSize = 14.sp) + Spacer(modifier = Modifier.width(8.dp)) + // round box + Box( + modifier = Modifier + .background(Color.Red, CircleShape) + .padding(horizontal = 8.dp, vertical = 4.dp) + ) { + // certification + Text("摄影师", color = Color.White, fontSize = 12.sp) + } + Spacer(modifier = Modifier.weight(1f)) + IconButton( + onClick = { /*TODO*/ }, + modifier = Modifier.size(32.dp) + ) { + Icon( + imageVector = Icons.Filled.Favorite, + contentDescription = null, + tint = Color.White + ) + } + Spacer(modifier = Modifier.width(4.dp)) + Text("123", color = Color.White) + Spacer(modifier = Modifier.width(8.dp)) + IconButton( + onClick = {}, + modifier = Modifier.size(32.dp) + ) { + Image( + painter = painterResource(id = R.drawable.rider_pro_eye), + contentDescription = "", + modifier = Modifier + .size(24.dp) + ) + } + Spacer(modifier = Modifier.width(4.dp)) + Text("123", color = Color.White) + + } + Box( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + // description + Text( + "摄影师 Diego Morata 的作品", + color = Color.White, + modifier = Modifier.align(Alignment.Center) + ) + } + } + + // circle avatar + + } + + } + val screenWidth = LocalConfiguration.current.screenWidthDp.dp + val imageSize = + (screenWidth - (4.dp * 4)) / 3 // Subtracting total padding and divi + val itemWidth = screenWidth / 3 - 4.dp * 2 + FlowRow( + modifier = Modifier.padding(4.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalArrangement = Arrangement.spacedBy(4.dp), + maxItemsInEachRow = 3 + ) { + for (artWork in artWorks) { + Box( + modifier = Modifier + .width(itemWidth) + .aspectRatio(1f) + .background(Color.Gray) + ) { + Image( + painter = painterResource(id = artWork.resId), + contentDescription = "", + contentScale = ContentScale.Crop, + modifier = Modifier + .width(imageSize) + .aspectRatio(1f) + ) + } + } + + } + } + } + Box( + modifier = Modifier + .fillMaxWidth() + .height(64.dp) + .background(Color.Black.copy(alpha = alpha)) + .padding(horizontal = 16.dp) + ) { + Row( + modifier = Modifier.fillMaxSize(), + verticalAlignment = androidx.compose.ui.Alignment.CenterVertically, + ) { + Image( + painter = painterResource(id = R.drawable.rider_pro_nav_back), + colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(Color.White), + contentDescription = "", + modifier = Modifier + .size(32.dp) + .clip(CircleShape) // Clip the image to a circle + ) + if (alpha == 1f) { + Spacer(modifier = Modifier.width(8.dp)) + Image( + painter = painterResource(id = R.drawable.default_avatar), + contentDescription = "", + modifier = Modifier + .size(32.dp) + .clip(CircleShape) // Clip the image to a circle + + ) + Spacer(modifier = Modifier.width(8.dp)) + Text("Onyama Limba", color = Color.White) + } + } + + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/Post.kt b/app/src/main/java/com/aiosman/riderpro/Post.kt new file mode 100644 index 0000000..320ecb9 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/Post.kt @@ -0,0 +1,320 @@ +package com.aiosman.riderpro + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +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.Row +import androidx.compose.foundation.layout.Spacer +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 +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material.icons.filled.Star +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +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.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 + +fun makeMockImages(): List { + return listOf( + PostImage(R.drawable.default_moment_img, "Image 1"), + PostImage(R.drawable.default_avatar, "Image 2"), + PostImage(R.drawable.rider_pro_moment_demo_1, "Image 3") + ) +} +@Preview +@Composable +fun PostPage() { + Scaffold( + modifier = Modifier.fillMaxSize(), + bottomBar = { + BottomNavigationBar() + } + ) { it + Column( + modifier = Modifier.fillMaxSize() + ) { + Header() + Box( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(1f) + ){ + PostImageView(makeMockImages()) + } + + PostDetails() + Box( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ){ + CommentsSection() + + } + + } + } + +} + +@Composable +fun Header() { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.rider_pro_nav_back), // Replace with your image resource + contentDescription = "Back", + modifier = Modifier + .size(32.dp) + + ) + Spacer(modifier = Modifier.width(8.dp)) + Image( + painter = painterResource(id = R.drawable.default_avatar), // Replace with your image resource + contentDescription = "Profile Picture", + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = "Diego Morata", fontWeight = FontWeight.Bold) + Box(modifier = Modifier + .height(20.dp).wrapContentWidth() + .padding(start = 6.dp), + contentAlignment = Alignment.Center){ + Image(modifier = Modifier.height(18.dp),painter = painterResource(id = R.drawable.follow_bg), contentDescription = "") + Text(text = "FOLLOW", fontSize = 12.sp, color = Color.White, style = TextStyle(fontWeight = FontWeight.Bold)) + } + } +} +data class PostImage( + val imgRes: Int, + val description: String +) +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun PostImageView(images: List) { + 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)) + .padding(4.dp) + + + ) + Spacer(modifier = Modifier.width(8.dp)) + } + } + } +} + +@Composable +fun PostDetails() { + Column(modifier = Modifier.padding(16.dp)) { + Text(text = "这里太适合骑行了", fontSize = 16.sp, fontWeight = FontWeight.Bold) + Text(text = "12-11 发布") + Spacer(modifier = Modifier.height(8.dp)) + Text(text = "共231条评论") + } +} +fun MakeMockComments(): List { + return listOf( + Comment( + name = "Diego Morata", + comment = "这里太适合骑行了", + date = "3 days ago", + likes = 200, + replies = listOf( + Comment( + name = "Diego Morata", + comment = "这里太适合骑行了", + date = "3 days ago", + likes = 200, + replies = emptyList() + ), + Comment( + name = "Diego Morata", + comment = "这里太适合骑行了", + date = "3 days ago", + likes = 200, + replies = emptyList() + ) + ) + ), + Comment( + name = "Diego Morata", + comment = "这里太适合骑行了", + date = "3 days ago", + likes = 200, + replies = emptyList() + ), + Comment( + name = "Diego Morata", + comment = "这里太适合骑行了", + date = "3 days ago", + likes = 200, + replies = emptyList() + ) + ) +} + +@Composable +fun CommentsSection() { + val items = MakeMockComments() + LazyColumn (modifier = Modifier + .padding(16.dp) + .fillMaxHeight()) { + items(items) {comment -> + CommentItem(comment) + } + } +} +data class Comment( + val name: String, + val comment: String, + val date: String, + val likes: Int, + val replies: List +) + + +@Composable +fun CommentItem(comment: Comment) { + Column { + Row(modifier = Modifier.padding(vertical = 8.dp)) { + Image( + painter = painterResource(id = R.drawable.default_avatar), // Replace with your image resource + contentDescription = "Comment Profile Picture", + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + ) + Spacer(modifier = Modifier.width(8.dp)) + Column { + Text(text = comment.name, fontWeight = FontWeight.Bold) + Text(text = comment.comment) + Text(text = comment.date, fontSize = 12.sp, color = Color.Gray) + } + Spacer(modifier = Modifier.weight(1f)) + Column(horizontalAlignment = Alignment.CenterHorizontally) { + IconButton(onClick = { /*TODO*/ }) { + Icon(Icons.Filled.Favorite, contentDescription = "Like") + } + Text(text = comment.likes.toString()) + } + } + Spacer(modifier = Modifier.height(8.dp)) + Column( + modifier = Modifier.padding(start = 16.dp) + ) { + comment.replies.forEach { reply -> + CommentItem(reply) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BottomNavigationBar() { + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp).background(Color.White) + ) { + // grey round box + Box( + modifier = Modifier + .padding(8.dp) + .clip(RoundedCornerShape(16.dp)) + .background(Color.Gray.copy(alpha = 0.1f)) + .weight(1f) + .height(31.dp) + .padding(8.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon(Icons.Filled.Edit, contentDescription = "Send") + Spacer(modifier = Modifier.width(8.dp)) + Text(text = "说点什么", fontSize = 12.sp) + } + } + + IconButton( + onClick = { /*TODO*/ }) { + Icon(Icons.Filled.Favorite, contentDescription = "Send") + } + Text(text = "2077") + IconButton( + onClick = { /*TODO*/ }) { + Icon(Icons.Filled.Star, contentDescription = "Send") + } + Text(text = "2077") + IconButton( + onClick = { /*TODO*/ }) { + Icon(Icons.Filled.CheckCircle, contentDescription = "Send") + } + Text(text = "2077") + + } +} \ No newline at end of file