diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f604ee9..49afb24 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -80,6 +80,8 @@ dependencies { implementation(libs.androidx.animation) implementation("io.coil-kt:coil-compose:2.7.0") implementation("io.coil-kt:coil:2.7.0") + implementation("com.google.android.gms:play-services-auth:21.2.0") + implementation("io.github.serpro69:kotlin-faker:2.0.0-rc.5") } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/data/AccountService.kt b/app/src/main/java/com/aiosman/riderpro/data/AccountService.kt new file mode 100644 index 0000000..cd08805 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/data/AccountService.kt @@ -0,0 +1,29 @@ +package com.aiosman.riderpro.data + +data class AccountProfile( + val id: Int, + val followerCount: Int, + val followingCount: Int, + val nickName: String, + val avatar: String, + val bio: String, + val country: String, +) + +interface AccountService { + suspend fun getAccountProfile(): AccountProfile +} + +class TestAccountServiceImpl : AccountService { + override suspend fun getAccountProfile(): AccountProfile { + return AccountProfile( + id = 1, + followerCount = 100, + followingCount = 200, + nickName = "Aiosman", + avatar = "https://img.freepik.com/free-photo/white-billboard-template_23-2147726635.jpg?t=st=1722150015~exp=1722153615~hmac=5540620196d7898215d822be26353c87a63d51bbfb2b814e032626e1948a1583&w=740", + bio = "I am a software engineer", + country = "Nigeria" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/data/comment/CommentPagingSource.kt b/app/src/main/java/com/aiosman/riderpro/data/CommentService.kt similarity index 96% rename from app/src/main/java/com/aiosman/riderpro/data/comment/CommentPagingSource.kt rename to app/src/main/java/com/aiosman/riderpro/data/CommentService.kt index 7559842..f332855 100644 --- a/app/src/main/java/com/aiosman/riderpro/data/comment/CommentPagingSource.kt +++ b/app/src/main/java/com/aiosman/riderpro/data/CommentService.kt @@ -1,8 +1,7 @@ -package com.aiosman.riderpro.data.comment +package com.aiosman.riderpro.data import androidx.paging.PagingSource import androidx.paging.PagingState -import com.aiosman.riderpro.data.ListContainer import java.io.IOException import kotlin.random.Random diff --git a/app/src/main/java/com/aiosman/riderpro/data/moment/MomentPagingSource.kt b/app/src/main/java/com/aiosman/riderpro/data/MomentService.kt similarity index 79% rename from app/src/main/java/com/aiosman/riderpro/data/moment/MomentPagingSource.kt rename to app/src/main/java/com/aiosman/riderpro/data/MomentService.kt index 1c0e493..c11f0a4 100644 --- a/app/src/main/java/com/aiosman/riderpro/data/moment/MomentPagingSource.kt +++ b/app/src/main/java/com/aiosman/riderpro/data/MomentService.kt @@ -1,17 +1,15 @@ -package com.aiosman.riderpro.data.moment +package com.aiosman.riderpro.data import androidx.paging.PagingSource import androidx.paging.PagingState import com.aiosman.riderpro.R -import com.aiosman.riderpro.data.ListContainer import com.aiosman.riderpro.model.MomentItem +import com.aiosman.riderpro.test.TestDatabase import java.io.IOException -import kotlin.random.Random class MomentPagingSource( private val remoteDataSource: MomentRemoteDataSource, ) : PagingSource() { - override suspend fun load(params: LoadParams): LoadResult { return try { val currentPage = params.key ?: 1 @@ -46,6 +44,7 @@ class MomentRemoteDataSource( interface MomentService { suspend fun getMoments(pageNumber: Int): ListContainer suspend fun getMomentById(id: Int): MomentItem + suspend fun likeMoment(id: Int) } class TestMomentServiceImpl() : MomentService { @@ -54,23 +53,7 @@ class TestMomentServiceImpl() : MomentService { "https://img.freepik.com/free-photo/minimal-clothing-label-fashion-brands_53876-111053.jpg?w=1060&t=st=1722150122~exp=1722150722~hmac=67f8a2b6abfe3d08714cf0cc0085485c3221e1ba00dda14378b03753dce39153", "https://img.freepik.com/free-photo/marketing-strategy-planning-strategy-concept_53876-42950.jpg" ) - val mockData = (0..300).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, - images = imageList.shuffled().take(3), - ) - } + var mockData = TestDatabase.momentData val testMomentBackend = TestMomentBackend(mockData) override suspend fun getMoments(pageNumber: Int): ListContainer { return testMomentBackend.fetchMomentItems(pageNumber) @@ -79,6 +62,18 @@ class TestMomentServiceImpl() : MomentService { override suspend fun getMomentById(id: Int): MomentItem { return mockData[id] } + + override suspend fun likeMoment(id: Int) { +// mockData = mockData.map { +// if (it.id == id) { +// it.copy(likeCount = it.likeCount + 1) +// } else { +// it +// } +// } +// mockData + } + } class TestMomentBackend( diff --git a/app/src/main/java/com/aiosman/riderpro/data/UserService.kt b/app/src/main/java/com/aiosman/riderpro/data/UserService.kt new file mode 100644 index 0000000..cf4a432 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/data/UserService.kt @@ -0,0 +1,18 @@ +package com.aiosman.riderpro.data + +import com.aiosman.riderpro.test.TestDatabase + +interface UserService { + suspend fun getUserProfile(id:String): AccountProfile +} + +class TestUserServiceImpl : UserService { + override suspend fun getUserProfile(id: String): AccountProfile { + TestDatabase.accountData.forEach { + if (it.id == id.toInt()) { + return it + } + } + return AccountProfile(0, 0, 0, "", "", "", "") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/model/MomentItem.kt b/app/src/main/java/com/aiosman/riderpro/model/MomentItem.kt index 967456a..323b07c 100644 --- a/app/src/main/java/com/aiosman/riderpro/model/MomentItem.kt +++ b/app/src/main/java/com/aiosman/riderpro/model/MomentItem.kt @@ -5,7 +5,7 @@ import com.aiosman.riderpro.R data class MomentItem( val id: Int, - @DrawableRes val avatar: Int, + val avatar: String, val nickname: String, val location: String, val time: String, @@ -16,61 +16,6 @@ data class MomentItem( val commentCount: Int, val shareCount: Int, val favoriteCount: Int, - val images: List = emptyList() -) - -val momentTestItem = MomentItem( - id = 1, - 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) - -val profileMomentItems = listOf( - MomentItem( - id = 1, - avatar = R.drawable.default_avatar, - nickname = "Onyama Limba", - location = "Japan", - time = "2024.06.08 12:23", - followStatus = false, - momentTextContent = "Modifications that are made to make your motorbike more like you", - momentPicture = R.drawable.rider_pro_moment_demo_1, - likeCount = 2345, - commentCount = 12, - shareCount = 33, - favoriteCount = 211), - MomentItem( - id = 2, - avatar = R.drawable.default_avatar, - nickname = "Onyama Limba", - location = "Japan", - time = "2024.03.03 12:31", - followStatus = false, - momentTextContent = "At least 500 units will be made, to meet homologation requirements.", - momentPicture = R.drawable.rider_pro_moment_demo_2, - likeCount = 211, - commentCount = 33, - shareCount = 33, - favoriteCount = 211), - MomentItem( - id = 3, - avatar = R.drawable.default_avatar, - nickname = "Onyama Limba", - location = "Japan", - time = "2024.02.02 11:23", - followStatus = false, - momentTextContent = "The bike is already FIM legal (and soon-to-be MotoAmerica legal as well).", - momentPicture = R.drawable.rider_pro_moment_demo_3, - likeCount = 987, - commentCount = 21, - shareCount = 33, - favoriteCount = 211) + val images: List = emptyList(), + val authorId: Int = 0 ) diff --git a/app/src/main/java/com/aiosman/riderpro/test/TestDatabase.kt b/app/src/main/java/com/aiosman/riderpro/test/TestDatabase.kt new file mode 100644 index 0000000..3db939a --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/test/TestDatabase.kt @@ -0,0 +1,92 @@ +package com.aiosman.riderpro.test + +import com.aiosman.riderpro.R +import com.aiosman.riderpro.data.AccountProfile +import com.aiosman.riderpro.model.MomentItem +import io.github.serpro69.kfaker.faker + +object TestDatabase { + var momentData = emptyList() + var accountData = emptyList() + var imageList = listOf( + "https://img.freepik.com/free-photo/white-billboard-template_23-2147726635.jpg?t=st=1722150015~exp=1722153615~hmac=5540620196d7898215d822be26353c87a63d51bbfb2b814e032626e1948a1583&w=740", + "https://img.freepik.com/free-photo/minimal-clothing-label-fashion-brands_53876-111053.jpg?w=1060&t=st=1722150122~exp=1722150722~hmac=67f8a2b6abfe3d08714cf0cc0085485c3221e1ba00dda14378b03753dce39153", + "https://img.freepik.com/free-photo/marketing-strategy-planning-strategy-concept_53876-42950.jpg", + "https://t4.ftcdn.net/jpg/02/27/00/89/240_F_227008949_5O7yXuEqTwUgs3BGqdcvrNutM5MSxs1t.jpg", + + "https://t4.ftcdn.net/jpg/01/86/86/49/240_F_186864971_NixcoDg1zBjjN7soUNhpEVraI4vdzOFD.jpg", + "https://t3.ftcdn.net/jpg/00/84/01/30/240_F_84013057_fsOdzBgskSFUyWyD6YKjIAdtKdBPiKRD.jpg", + "https://t4.ftcdn.net/jpg/00/93/89/23/240_F_93892312_SNyGGruVaWKpJQiVG314gIQmS4EAghdy.jpg", + "https://t3.ftcdn.net/jpg/02/94/56/58/240_F_294565895_IOqZC2OpcHGEibWF04MPEP09KZaewEl5.jpg", + "https://t3.ftcdn.net/jpg/01/01/66/84/240_F_101668484_FopHBSMBq4t6BlvwI9awPMzUdi501sJ7.jpg", + "https://t3.ftcdn.net/jpg/05/65/11/60/240_F_565116019_oHbZ6Hc8VYCMcZWpexXF7Z5lOWeNNYtD.jpg", + "https://t3.ftcdn.net/jpg/03/52/21/48/240_F_352214843_dQ3JtTJrKyqrh2yd1emYCDPSrzrwqaNK.jpg", + "https://t3.ftcdn.net/jpg/07/22/47/16/240_F_722471661_T25r329RFRxgK88S6oBJ9dUksOC2arLl.jpg", + "https://t3.ftcdn.net/jpg/02/18/11/26/240_F_218112603_jBChzLJGuz8smPZsdFsy17wB0O0QF3Xo.jpg", + "https://t4.ftcdn.net/jpg/04/11/49/07/240_F_411490703_KRvV0aRyxHWYVUO8bGXxuQGo2mHblYnv.jpg", + "https://img.freepik.com/premium-photo/man-wearing-orange-helmet-white-background_466494-5539.jpg?ga=GA1.1.1334458544.1722150011&semt=sph", + "https://img.freepik.com/premium-photo/motorcycle-vehicle-3d-modelling_274824-502.jpg?ga=GA1.1.1334458544.1722150011&semt=sph", + "https://t3.ftcdn.net/jpg/01/68/26/06/240_F_168260687_UfaDjjs6TxcIB6BdsquSeCmYWEFmN1Sh.jpg", + "https://t3.ftcdn.net/jpg/03/48/50/34/240_F_348503435_On7Tt5Eqn7IP9QWYTQL0H1smubU8gvLv.jpg", + "https://t3.ftcdn.net/jpg/02/76/70/70/240_F_276707060_WpP9bwHWv0Wdqqn0pEgtSuIgXUvgkbs7.jpg", + "https://t3.ftcdn.net/jpg/02/65/43/04/240_F_265430460_DIHqnrziar7WL2rmW0qbDO07TbxjlPQo.jpg" + ) + var followList = emptyList>() + + init { + val faker = faker { + this.fakerConfig { + locale = "en" + } + } + accountData = (0..300).toList().mapIndexed { idx, _ -> + AccountProfile( + id = idx, + followerCount = 0, + followingCount = 0, + nickName = faker.name.name(), + avatar = imageList.random(), + bio = "I am a software engineer", + country = faker.address.country() + + ) + } + // make a random follow rel + for (i in 0..10000) { + var person1 = accountData.random() + var persion2 = accountData.random() + followList += Pair(person1.id, persion2.id) + // update followerCount and followingCount + accountData = accountData.map { + if (it.id == person1.id) { + it.copy(followingCount = it.followingCount + 1) + } else if (it.id == persion2.id) { + it.copy(followerCount = it.followerCount + 1) + } else { + it + } + } + + } + + momentData = (0..300).toList().mapIndexed { idx, _ -> + val person = accountData.random() + MomentItem( + id = idx, + avatar = person.avatar, + nickname = person.nickName, + location = person.country, + 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 = faker.random.nextInt(0, 100), + commentCount = faker.random.nextInt(0, 100), + shareCount = faker.random.nextInt(0, 100), + favoriteCount = faker.random.nextInt(0, 100), + images = imageList.shuffled().take(3), + authorId = person.id + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt b/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt index 3ebc8dd..bd652cb 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt @@ -29,10 +29,12 @@ import com.aiosman.riderpro.ui.gallery.ProfileTimelineScreen import com.aiosman.riderpro.ui.index.IndexScreen import com.aiosman.riderpro.ui.like.LikeScreen import com.aiosman.riderpro.ui.location.LocationDetailScreen +import com.aiosman.riderpro.ui.login.LoginPage import com.aiosman.riderpro.ui.message.NotificationsScreen import com.aiosman.riderpro.ui.modification.EditModificationScreen import com.aiosman.riderpro.ui.post.NewPostScreen import com.aiosman.riderpro.ui.post.PostScreen +import com.aiosman.riderpro.ui.profile.AccountProfile sealed class NavigationRoute( val route: String, @@ -50,6 +52,8 @@ sealed class NavigationRoute( data object Followers : NavigationRoute("Followers") data object NewPost : NavigationRoute("NewPost") data object EditModification : NavigationRoute("EditModification") + data object Login : NavigationRoute("Login") + data object AccountProfile : NavigationRoute("AccountProfile/{id}") } @@ -61,7 +65,7 @@ fun NavigationController(navController: NavHostController) { NavHost( navController = navController, - startDestination = NavigationRoute.Index.route, + startDestination = NavigationRoute.Login.route, ) { composable(route = NavigationRoute.Index.route) { CompositionLocalProvider( @@ -134,6 +138,16 @@ fun NavigationController(navController: NavHostController) { EditModificationScreen() } } + composable(route = NavigationRoute.Login.route) { + LoginPage() + + } + composable( + route = NavigationRoute.AccountProfile.route, + arguments = listOf(navArgument("id") { type = NavType.StringType }) + ) { + AccountProfile(it.arguments?.getString("id")!!) + } } diff --git a/app/src/main/java/com/aiosman/riderpro/ui/comment/CommentModal.kt b/app/src/main/java/com/aiosman/riderpro/ui/comment/CommentModal.kt index ee889bd..5337b9a 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/comment/CommentModal.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/comment/CommentModal.kt @@ -41,12 +41,10 @@ import androidx.paging.PagingData import androidx.paging.compose.collectAsLazyPagingItems import com.aiosman.riderpro.ui.post.CommentsSection import com.aiosman.riderpro.R -import com.aiosman.riderpro.data.comment.Comment -import com.aiosman.riderpro.data.comment.CommentPagingSource -import com.aiosman.riderpro.data.comment.CommentRemoteDataSource -import com.aiosman.riderpro.data.comment.TestCommentServiceImpl -import com.aiosman.riderpro.model.MomentItem -import com.aiosman.riderpro.ui.index.tabs.moment.MomentViewModel.momentListPagingSource +import com.aiosman.riderpro.data.Comment +import com.aiosman.riderpro.data.CommentPagingSource +import com.aiosman.riderpro.data.CommentRemoteDataSource +import com.aiosman.riderpro.data.TestCommentServiceImpl import kotlinx.coroutines.flow.Flow diff --git a/app/src/main/java/com/aiosman/riderpro/ui/composables/AnimatedLikeButton.kt b/app/src/main/java/com/aiosman/riderpro/ui/composables/AnimatedLikeButton.kt index 509643c..b8c05b4 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/composables/AnimatedLikeButton.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/composables/AnimatedLikeButton.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.res.painterResource import com.aiosman.riderpro.R +import com.aiosman.riderpro.ui.modifiers.noRippleClickable import kotlinx.coroutines.launch @Composable @@ -50,7 +51,7 @@ fun AnimatedLikeIcon( animationSpec = tween(100) ) } - Box(contentAlignment = Alignment.Center, modifier = Modifier.clickable { + Box(contentAlignment = Alignment.Center, modifier = Modifier.noRippleClickable { liked = !liked onClick?.invoke() // Trigger shake animation diff --git a/app/src/main/java/com/aiosman/riderpro/ui/composables/StatusBarMask.kt b/app/src/main/java/com/aiosman/riderpro/ui/composables/StatusBarMask.kt index 6ed09f7..d286bfe 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/composables/StatusBarMask.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/composables/StatusBarMask.kt @@ -35,6 +35,7 @@ fun StatusBarMask(darkIcons: Boolean = true) { fun StatusBarMaskLayout( modifier: Modifier = Modifier, darkIcons: Boolean = true, + useNavigationBarMask: Boolean = true, maskBoxBackgroundColor: Color = Color.Transparent, content: @Composable ColumnScope.() -> Unit ) { @@ -57,7 +58,7 @@ fun StatusBarMaskLayout( } content() - if (navigationBarPaddings > 24.dp) { + if (navigationBarPaddings > 24.dp && useNavigationBarMask) { Box( modifier = Modifier .height(navigationBarPaddings).fillMaxWidth().background(Color.White) diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt index ccd201e..ab4c8e0 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/Moment.kt @@ -33,6 +33,7 @@ import androidx.compose.runtime.Composable 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 @@ -46,51 +47,43 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.paging.compose.collectAsLazyPagingItems import coil.compose.AsyncImage -import com.aiosman.riderpro.LocalAnimatedContentScope import com.aiosman.riderpro.LocalNavController -import com.aiosman.riderpro.LocalSharedTransitionScope import com.aiosman.riderpro.R import com.aiosman.riderpro.model.MomentItem +import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.comment.CommentModalContent import com.aiosman.riderpro.ui.composables.AnimatedCounter import com.aiosman.riderpro.ui.composables.AnimatedLikeIcon +import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.google.accompanist.systemuicontroller.rememberSystemUiController - -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 - ) -} +import kotlinx.coroutines.launch @OptIn(ExperimentalSharedTransitionApi::class) @Composable fun MomentsList() { val model = MomentViewModel - val moments = model.momentsFlow.collectAsLazyPagingItems() + var dataFlow = model.momentsFlow + var moments = dataFlow.collectAsLazyPagingItems() + val scope = rememberCoroutineScope() + LazyColumn { items(moments.itemCount) { idx -> val momentItem = moments[idx] ?: return@items - MomentCard(momentItem = momentItem) + MomentCard(momentItem = momentItem, onLikeClick = { + scope.launch { + model.likeMoment(momentItem.id) + moments.refresh() + } + }) } } } -@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun MomentCard( momentItem: MomentItem, + onLikeClick: () -> Unit ) { val navController = LocalNavController.current Column( @@ -100,18 +93,17 @@ fun MomentCard( Column( modifier = Modifier .fillMaxWidth() - .clickable { + .noRippleClickable { navController.navigate("Post/${momentItem.id}") } ) { MomentContentGroup(momentItem = momentItem) } - val momentOperateBtnBoxModifier = Modifier .fillMaxHeight() .weight(1f) ModificationListHeader() - MomentBottomOperateRowGroup(momentOperateBtnBoxModifier, momentItem = momentItem) + MomentBottomOperateRowGroup(momentOperateBtnBoxModifier, momentItem = momentItem, onLikeClick = onLikeClick) } } @@ -213,14 +205,19 @@ fun MomentPostTime(time: String) { @Composable fun MomentTopRowGroup(momentItem: MomentItem) { + val navController = LocalNavController.current Row( modifier = Modifier .height(40.dp) .padding(top = 0.dp, bottom = 0.dp, start = 24.dp, end = 24.dp) ) { - Image( - painter = painterResource(id = momentItem.avatar), - contentDescription = "" + AsyncImage( + momentItem.avatar, + contentDescription = "", + modifier = Modifier.size(40.dp).noRippleClickable { + navController.navigate(NavigationRoute.AccountProfile.route.replace("{id}", momentItem.authorId.toString())) + }, + contentScale = ContentScale.Crop ) Column( modifier = Modifier @@ -254,8 +251,6 @@ fun MomentTopRowGroup(momentItem: MomentItem) { fun MomentContentGroup( momentItem: MomentItem, ) { -// val sharedTransitionScope = LocalSharedTransitionScope.current -// val animatedContentScope = LocalAnimatedContentScope.current val displayImageUrl = momentItem.images.firstOrNull() Text( text = momentItem.momentTextContent, @@ -312,7 +307,11 @@ fun MomentOperateBtn(count: String, content: @Composable () -> Unit) { @OptIn(ExperimentalMaterial3Api::class) @Composable -fun MomentBottomOperateRowGroup(modifier: Modifier, momentItem: MomentItem) { +fun MomentBottomOperateRowGroup( + modifier: Modifier, + onLikeClick: () -> Unit = {}, + momentItem: MomentItem +) { var systemUiController = rememberSystemUiController() var showCommentModal by remember { mutableStateOf(false) } if (showCommentModal) { @@ -340,10 +339,7 @@ fun MomentBottomOperateRowGroup(modifier: Modifier, momentItem: MomentItem) { ) { MomentOperateBtn(count = momentItem.likeCount.toString()) { AnimatedLikeIcon(modifier = Modifier.size(24.dp)) { - MomentViewModel.updateById( - momentItem.id, - momentItem.copy(likeCount = momentItem.likeCount + 1) - ) + onLikeClick() } } } @@ -356,19 +352,19 @@ fun MomentBottomOperateRowGroup(modifier: Modifier, momentItem: MomentItem) { }, contentAlignment = Alignment.Center ) { - MomentOperateBtn(icon = R.drawable.rider_pro_moment_comment, count = "43") + MomentOperateBtn(icon = R.drawable.rider_pro_moment_comment, count = momentItem.commentCount.toString()) } Box( modifier = modifier, contentAlignment = Alignment.Center ) { - MomentOperateBtn(icon = R.drawable.rider_pro_share, count = "33") + MomentOperateBtn(icon = R.drawable.rider_pro_share, count = momentItem.shareCount.toString()) } Box( modifier = modifier, contentAlignment = Alignment.Center ) { - MomentOperateBtn(icon = R.drawable.rider_pro_favoriate, count = "211") + MomentOperateBtn(icon = R.drawable.rider_pro_favoriate, count = momentItem.favoriteCount.toString()) } } } diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt index 6a55040..f2f89d5 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/moment/MomentViewModel.kt @@ -8,52 +8,32 @@ import androidx.lifecycle.ViewModel import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData -import androidx.paging.cachedIn import com.aiosman.riderpro.R -import com.aiosman.riderpro.data.moment.MomentPagingSource -import com.aiosman.riderpro.data.moment.MomentRemoteDataSource -import com.aiosman.riderpro.data.moment.TestMomentServiceImpl +import com.aiosman.riderpro.data.MomentPagingSource +import com.aiosman.riderpro.data.MomentRemoteDataSource +import com.aiosman.riderpro.data.MomentService +import com.aiosman.riderpro.data.TestMomentServiceImpl import com.aiosman.riderpro.model.MomentItem import kotlinx.coroutines.flow.Flow -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 MomentViewModel : ViewModel() { - var momentList by mutableStateOf(DATA) - - fun updateById(id: Int, momentItem: MomentItem) { - momentList = momentList.map { - if (it.id == id) { - momentItem - } else { - it - } - }.toMutableStateList() - } - + val momentService: MomentService = TestMomentServiceImpl() var momentListPagingSource = MomentPagingSource( - MomentRemoteDataSource(TestMomentServiceImpl()) - + MomentRemoteDataSource(momentService) ) - - val momentsFlow: Flow> = Pager( + var momentsFlow: Flow> = Pager( config = PagingConfig(pageSize = 5, enablePlaceholders = false), - pagingSourceFactory = { momentListPagingSource } + pagingSourceFactory = { + MomentPagingSource( + MomentRemoteDataSource(momentService) + ) + } ).flow + suspend fun likeMoment(id: Int) { + momentService.likeMoment(id) + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/MyProfileViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/MyProfileViewModel.kt new file mode 100644 index 0000000..2c6648d --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/MyProfileViewModel.kt @@ -0,0 +1,39 @@ +package com.aiosman.riderpro.ui.index.tabs.profile + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.aiosman.riderpro.data.AccountProfile +import com.aiosman.riderpro.data.AccountService +import com.aiosman.riderpro.data.TestAccountServiceImpl +import com.aiosman.riderpro.data.MomentPagingSource +import com.aiosman.riderpro.data.MomentRemoteDataSource +import com.aiosman.riderpro.data.TestMomentServiceImpl +import com.aiosman.riderpro.model.MomentItem +import kotlinx.coroutines.flow.Flow + +object MyProfileViewModel { + val service: AccountService = TestAccountServiceImpl() + var profile by mutableStateOf(null) + suspend fun loadProfile() { + profile = service.getAccountProfile() + } + var momentListPagingSource = MomentPagingSource( + MomentRemoteDataSource(TestMomentServiceImpl()) + + ) + + val momentsFlow: Flow> = Pager( + config = PagingConfig(pageSize = 5, enablePlaceholders = false), + pagingSourceFactory = { momentListPagingSource } + ).flow + val followerCount get() = profile?.followerCount ?: 0 + val followingCount get() = profile?.followingCount ?: 0 + val bio get() = profile?.bio ?: "" + val nickName get() = profile?.nickName ?: "" + val avatar get() = profile?.avatar + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/Profile.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/Profile.kt index 2d98d88..e2699ba 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/Profile.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/Profile.kt @@ -16,46 +16,66 @@ 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.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll 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 import androidx.compose.ui.draw.shadow 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.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.paging.compose.collectAsLazyPagingItems +import coil.compose.AsyncImage import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.R +import com.aiosman.riderpro.data.AccountProfile import com.aiosman.riderpro.model.MomentItem -import com.aiosman.riderpro.model.profileMomentItems @Composable -fun ProfilePage(){ - Column ( +fun ProfilePage() { + val model = MyProfileViewModel + LaunchedEffect(Unit) { + model.loadProfile() + } + val profile = model.momentsFlow.collectAsLazyPagingItems() + LazyColumn( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .padding(bottom = 16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top, - ){ - CarGroup() - UserInformation() - RidingStyle() - UserMoment() + ) { + item { + CarGroup() + model.profile?.let { + UserInformation(accountProfile = it) + } + + RidingStyle() + } + items(profile.itemCount) { idx -> + val momentItem = profile[idx] ?: return@items + MomentPostUnit(momentItem) + } } } @Composable -fun CarGroup(){ +fun CarGroup() { Column( modifier = Modifier .fillMaxWidth() @@ -68,144 +88,271 @@ fun CarGroup(){ } @Composable -fun CarTopInformation(){ - Row{ - Text(text = "BMW", color = Color.Black, fontSize = 12.sp, style = TextStyle(fontWeight = FontWeight.Bold)) - Text(modifier = Modifier.padding(start = 4.dp), text = "/", color = Color.Gray, fontSize = 12.sp) - Text(modifier = Modifier.padding(start = 4.dp), text = "M1000RR", color = Color.Gray, fontSize = 12.sp) +fun CarTopInformation() { + Row { + Text( + text = "BMW", + color = Color.Black, + fontSize = 12.sp, + style = TextStyle(fontWeight = FontWeight.Bold) + ) + Text( + modifier = Modifier.padding(start = 4.dp), + text = "/", + color = Color.Gray, + fontSize = 12.sp + ) + Text( + modifier = Modifier.padding(start = 4.dp), + text = "M1000RR", + color = Color.Gray, + fontSize = 12.sp + ) } } @Composable -fun CarTopPicture(){ +fun CarTopPicture() { Image( modifier = Modifier .size(width = 336.dp, height = 224.dp) .padding(top = 42.dp), - painter = painterResource(id = R.drawable.default_profile_moto), contentDescription = "") + painter = painterResource(id = R.drawable.default_profile_moto), contentDescription = "" + ) } @Composable -fun UserInformation(){ +fun UserInformation(isSelf: Boolean = true,accountProfile: AccountProfile) { Column( modifier = Modifier .fillMaxWidth() .padding(top = 8.dp, start = 33.dp, end = 33.dp), - horizontalAlignment = Alignment.CenterHorizontally){ - Row (modifier = Modifier.fillMaxWidth()){ + horizontalAlignment = Alignment.CenterHorizontally + ) { + Row(modifier = Modifier.fillMaxWidth()) { val userInfoModifier = Modifier.weight(1f) - UserInformationFollowers(userInfoModifier) - UserInformationBasic(userInfoModifier) - UserInformationFollowing(userInfoModifier) + UserInformationFollowers(userInfoModifier,accountProfile) + UserInformationBasic(userInfoModifier,accountProfile) + UserInformationFollowing(userInfoModifier,accountProfile) } UserInformationSlogan() - CommunicationOperatorGroup() + CommunicationOperatorGroup(isSelf = isSelf) } } @Composable -fun UserInformationFollowers(modifier: Modifier){ +fun UserInformationFollowers(modifier: Modifier,accountProfile: AccountProfile) { Column(modifier = modifier.padding(top = 31.dp)) { - Text(modifier = Modifier.padding(bottom = 5.dp),text = "183", fontSize = 24.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) + Text( + modifier = Modifier.padding(bottom = 5.dp), + text = accountProfile.followerCount.toString(), + fontSize = 24.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold) + ) Spacer( modifier = Modifier .size(width = 88.83.dp, height = 1.dp) .border(width = 1.dp, color = Color.Gray) .padding(top = 5.dp, bottom = 5.dp) ) - Text(modifier = Modifier.padding(top = 5.dp),text = "FOLLOWERS", fontSize = 12.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) + Text( + modifier = Modifier.padding(top = 5.dp), + text = "FOLLOWERS", + fontSize = 12.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold) + ) } } @Composable -fun UserInformationBasic(modifier: Modifier){ +fun UserInformationBasic(modifier: Modifier,accountProfile: AccountProfile) { Column( - horizontalAlignment = Alignment.CenterHorizontally) { - Box(modifier = Modifier.size(width = 112.dp, height = 112.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier.size(width = 112.dp, height = 112.dp), contentAlignment = Alignment.Center - ){ + ) { Image( modifier = Modifier.fillMaxSize(), - painter = painterResource(id = R.drawable.avatar_bold), contentDescription = "") - Image( + painter = painterResource(id = R.drawable.avatar_bold), contentDescription = "" + ) + AsyncImage( + accountProfile.avatar, modifier = Modifier .size(width = 88.dp, height = 88.dp) .clip( RoundedCornerShape(88.dp) ), - painter = painterResource(id = R.drawable.default_avatar), contentDescription = "") + contentDescription = "", + contentScale = ContentScale.Crop + ) } - Text(modifier = Modifier.padding(top = 8.dp), text = "Atom", fontSize = 32.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) - Text(modifier = Modifier.padding(top = 4.dp), text = "America", fontSize = 12.sp, color = Color.Gray) - Text(modifier = Modifier.padding(top = 4.dp), text = "Member since Jun 4.2019", fontSize = 12.sp, color = Color.Gray) + Text( + modifier = Modifier.widthIn(max =220.dp).padding(top = 8.dp), + text = accountProfile.nickName, + fontSize = 32.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold), + textAlign = TextAlign.Center + ) + Text( + modifier = Modifier.padding(top = 4.dp), + text = accountProfile.country, + fontSize = 12.sp, + color = Color.Gray + ) + Text( + modifier = Modifier.padding(top = 4.dp), + text = "Member since Jun 4.2019", + fontSize = 12.sp, + color = Color.Gray + ) } } @Composable -fun UserInformationFollowing(modifier: Modifier){ - Column(modifier = modifier.padding(top = 6.dp), - horizontalAlignment = Alignment.End) { - Text(modifier = Modifier.padding(bottom = 5.dp), text = "306", fontSize = 24.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) +fun UserInformationFollowing(modifier: Modifier,accountProfile: AccountProfile) { + Column( + modifier = modifier.padding(top = 6.dp), + horizontalAlignment = Alignment.End + ) { + Text( + modifier = Modifier.padding(bottom = 5.dp), + text = accountProfile.followingCount.toString(), + fontSize = 24.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold) + ) Box( modifier = Modifier .size(width = 88.83.dp, height = 1.dp) .border(width = 1.dp, color = Color.Gray) ) - Text(modifier = Modifier.padding(top = 5.dp),text = "FOLLOWING", fontSize = 12.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) + Text( + modifier = Modifier.padding(top = 5.dp), + text = "FOLLOWING", + fontSize = 12.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold) + ) } } @Composable -fun UserInformationSlogan(){ - Text(modifier = Modifier.padding(top = 23.dp),text = "Ridering shooting fishing not much more", fontSize = 13.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) +fun UserInformationSlogan() { + val model = MyProfileViewModel + Text( + modifier = Modifier.padding(top = 23.dp), + text = model.bio, + fontSize = 13.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold) + ) } @Composable -fun CommunicationOperatorGroup(){ +fun CommunicationOperatorGroup(isSelf: Boolean = true) { val navController = LocalNavController.current - Row (modifier = Modifier - .fillMaxWidth() - .padding(top = 16.dp), horizontalArrangement = Arrangement.Center){ - Box(modifier = Modifier.size(width = 142.dp, height = 40.dp), - contentAlignment = Alignment.Center){ - Image(modifier = Modifier.fillMaxSize(), painter = painterResource(id = R.drawable.rider_pro_profile_follow), contentDescription = "") - Text(text = "FOLLOW", fontSize = 16.sp, color = Color.White, style = TextStyle(fontWeight = FontWeight.Bold)) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), horizontalArrangement = Arrangement.Center + ) { + Box( + modifier = Modifier.size(width = 142.dp, height = 40.dp), + contentAlignment = Alignment.Center + ) { + Image( + modifier = Modifier.fillMaxSize(), + painter = painterResource(id = R.drawable.rider_pro_profile_follow), + contentDescription = "" + ) + Text( + text = "FOLLOW", + fontSize = 16.sp, + color = Color.White, + style = TextStyle(fontWeight = FontWeight.Bold) + ) } - Box(modifier = Modifier - .size(width = 142.dp, height = 40.dp) - .padding(start = 6.dp).clickable { - navController.navigate("MyMessage") - }, - contentAlignment = Alignment.Center){ - Image(modifier = Modifier.fillMaxSize(),painter = painterResource(id = R.drawable.rider_pro_profile_message), contentDescription = "") - Text(text = "MESSAGE", fontSize = 16.sp, color = Color.White, style = TextStyle(fontWeight = FontWeight.Bold)) - } - Box(modifier = Modifier.size(width = 142.dp, height = 40.dp).clickable { - navController.navigate("ProfileTimeline") - }, - contentAlignment = Alignment.Center){ - Image(modifier = Modifier.fillMaxSize(), painter = painterResource(id = R.drawable.rider_pro_profile_follow), contentDescription = "") - Text(text = "GALLERY", fontSize = 16.sp, color = Color.White, style = TextStyle(fontWeight = FontWeight.Bold)) + if (isSelf) { + Box( + modifier = Modifier + .size(width = 142.dp, height = 40.dp) + .padding(start = 6.dp) + .clickable { + navController.navigate("MyMessage") + }, + contentAlignment = Alignment.Center + ) { + Image( + modifier = Modifier.fillMaxSize(), + painter = painterResource(id = R.drawable.rider_pro_profile_message), + contentDescription = "" + ) + Text( + text = "MESSAGE", + fontSize = 16.sp, + color = Color.White, + style = TextStyle(fontWeight = FontWeight.Bold) + ) + } + Box( + modifier = Modifier + .size(width = 142.dp, height = 40.dp) + .clickable { + navController.navigate("ProfileTimeline") + }, + contentAlignment = Alignment.Center + ) { + Image( + modifier = Modifier.fillMaxSize(), + painter = painterResource(id = R.drawable.rider_pro_profile_follow), + contentDescription = "" + ) + Text( + text = "GALLERY", + fontSize = 16.sp, + color = Color.White, + style = TextStyle(fontWeight = FontWeight.Bold) + ) + } } + } } @OptIn(ExperimentalLayoutApi::class) @Composable -fun RidingStyle(){ - Column(modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp, top = 40.dp, end = 24.dp), - horizontalAlignment = Alignment.Start) { - Text(text = "RIDING STYLES", fontSize = 18.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) - Image(modifier = Modifier - .padding(top = 4.dp) - .height(8.dp),painter = painterResource(id = R.drawable.rider_pro_profile_line), contentDescription = "") - FlowRow (modifier = Modifier +fun RidingStyle() { + Column( + modifier = Modifier .fillMaxWidth() - .padding(top = 24.dp)){ + .padding(start = 24.dp, top = 40.dp, end = 24.dp), + horizontalAlignment = Alignment.Start + ) { + Text( + text = "RIDING STYLES", + fontSize = 18.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold) + ) + Image( + modifier = Modifier + .padding(top = 4.dp) + .height(8.dp), + painter = painterResource(id = R.drawable.rider_pro_profile_line), + contentDescription = "" + ) + FlowRow( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp) + ) { RidingStyleItem(styleContent = "Cruiser") RidingStyleItem(styleContent = "Bobber") RidingStyleItem(styleContent = "Cafe") @@ -219,100 +366,150 @@ fun RidingStyle(){ } @Composable -fun RidingStyleItem(styleContent: String){ - Box(modifier = Modifier.padding(bottom = 8.dp, end = 8.dp), - contentAlignment = Alignment.Center) { - Image(modifier = Modifier.shadow( - ambientColor = Color.Gray, - spotColor = Color(0f,0f,0f,0.2f), - elevation = 20.dp, - ), painter = painterResource(id = R.drawable.rider_pro_style_wrapper), contentDescription = "") - Text(modifier = Modifier.padding(start = 5.dp, end = 5.dp), text = styleContent, fontSize = 12.sp, color = Color.Gray, style = TextStyle(fontWeight = FontWeight.Bold)) +fun RidingStyleItem(styleContent: String) { + Box( + modifier = Modifier.padding(bottom = 8.dp, end = 8.dp), + contentAlignment = Alignment.Center + ) { + Image( + modifier = Modifier.shadow( + ambientColor = Color.Gray, + spotColor = Color(0f, 0f, 0f, 0.2f), + elevation = 20.dp, + ), + painter = painterResource(id = R.drawable.rider_pro_style_wrapper), + contentDescription = "" + ) + Text( + modifier = Modifier.padding(start = 5.dp, end = 5.dp), + text = styleContent, + fontSize = 12.sp, + color = Color.Gray, + style = TextStyle(fontWeight = FontWeight.Bold) + ) } } @Composable -fun UserMoment(){ - profileMomentItems.forEach( - action = { MomentPostUnit(it) } +fun UserMoment(scope: LazyListScope) { + + +// LazyColumn( +// modifier = Modifier +// .fillMaxWidth() +// .weight(1f) +// ){ +// +// +// } +} + +@Composable +fun MomentPostUnit(momentItem: MomentItem) { + TimeGroup(momentItem.time) + MomentCard( + momentItem.momentTextContent, + momentItem.momentPicture, + momentItem.likeCount.toString(), + momentItem.commentCount.toString() ) } @Composable -fun MomentPostUnit(momentItem: MomentItem){ - TimeGroup(momentItem.time) - MomentCard(momentItem.momentTextContent, - momentItem.momentPicture, - momentItem.likeCount.toString(), - momentItem.commentCount.toString()) -} - -@Composable -fun TimeGroup(time: String = "2024.06.08 12:23"){ - Row(modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp, top = 40.dp, end = 24.dp), +fun TimeGroup(time: String = "2024.06.08 12:23") { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 24.dp, top = 40.dp, end = 24.dp), horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically){ + verticalAlignment = Alignment.CenterVertically + ) { Image( modifier = Modifier.padding(end = 12.dp), - painter = painterResource(id = R.drawable.rider_pro_moment_time_flag), contentDescription = "") - Text(text = time,fontSize = 22.sp, color = Color.Black, style = TextStyle(fontWeight = FontWeight.Bold)) + painter = painterResource(id = R.drawable.rider_pro_moment_time_flag), + contentDescription = "" + ) + Text( + text = time, + fontSize = 22.sp, + color = Color.Black, + style = TextStyle(fontWeight = FontWeight.Bold) + ) } } @Composable -fun MomentCard(content: String,@DrawableRes picture: Int, like: String, comment: String){ - Column(modifier = Modifier - .fillMaxWidth() - .padding(start = 48.dp, top = 18.dp, end = 24.dp) - .border(width = 1.dp, color = Color(0f,0f,0f,0.1f), shape = RoundedCornerShape(6.dp)) - ){ +fun MomentCard(content: String, @DrawableRes picture: Int, like: String, comment: String) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 48.dp, top = 18.dp, end = 24.dp) + .border(width = 1.dp, color = Color(0f, 0f, 0f, 0.1f), shape = RoundedCornerShape(6.dp)) + ) { MomentCardTopContent(content) MomentCardPicture(picture) - MomentCardOperation(like,comment) + MomentCardOperation(like, comment) } } @Composable -fun MomentCardTopContent(content: String){ - Row(modifier = Modifier - .fillMaxWidth(), +fun MomentCardTopContent(content: String) { + Row( + modifier = Modifier + .fillMaxWidth(), horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically){ + verticalAlignment = Alignment.CenterVertically + ) { Text( modifier = Modifier.padding(16.dp), - text = content,fontSize = 16.sp, color = Color.Black) + text = content, fontSize = 16.sp, color = Color.Black + ) } } @Composable -fun MomentCardPicture(@DrawableRes drawable: Int){ - Image(modifier = Modifier - .fillMaxSize() - .padding(16.dp), painter = painterResource(id = drawable), contentDescription = "") +fun MomentCardPicture(@DrawableRes drawable: Int) { + Image( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), painter = painterResource(id = drawable), contentDescription = "" + ) } @Composable -fun MomentCardOperation(like: String, comment: String){ - Row(modifier = Modifier - .fillMaxWidth() - .height(56.dp), +fun MomentCardOperation(like: String, comment: String) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(56.dp), horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically){ + verticalAlignment = Alignment.CenterVertically + ) { Spacer(modifier = Modifier.weight(1f)) - MomentCardOperationItem(drawable = R.drawable.rider_pro_like, number = like, modifier = Modifier.weight(1f)) - MomentCardOperationItem(drawable = R.drawable.rider_pro_moment_comment, number = comment, modifier = Modifier.weight(1f)) + MomentCardOperationItem( + drawable = R.drawable.rider_pro_like, + number = like, + modifier = Modifier.weight(1f) + ) + MomentCardOperationItem( + drawable = R.drawable.rider_pro_moment_comment, + number = comment, + modifier = Modifier.weight(1f) + ) } } @Composable -fun MomentCardOperationItem(@DrawableRes drawable: Int, number: String, modifier: Modifier){ - Row(modifier = modifier, - verticalAlignment = Alignment.CenterVertically){ - Image(modifier = Modifier.padding(start = 16.dp, end = 8.dp), - painter = painterResource(id = drawable), contentDescription = "") +fun MomentCardOperationItem(@DrawableRes drawable: Int, number: String, modifier: Modifier) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier.padding(start = 16.dp, end = 8.dp), + painter = painterResource(id = drawable), contentDescription = "" + ) Text(text = number) } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/login/login.kt b/app/src/main/java/com/aiosman/riderpro/ui/login/login.kt new file mode 100644 index 0000000..c9fc403 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/login/login.kt @@ -0,0 +1,41 @@ +package com.aiosman.riderpro.ui.login + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ElevatedButton +import androidx.compose.material3.Scaffold +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.unit.dp +import androidx.compose.ui.unit.sp +import com.aiosman.riderpro.LocalNavController +import com.aiosman.riderpro.ui.NavigationRoute + +@Composable +fun LoginPage() { + val navController = LocalNavController.current + LaunchedEffect(Unit) { + navController.navigate(NavigationRoute.Index.route) + } + Scaffold { paddingValues -> + Column( + modifier = Modifier.padding(paddingValues).padding(horizontal = 16.dp).fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Login", fontSize = 24.sp) + ElevatedButton( + onClick = { /*TODO*/ }, + modifier = Modifier.fillMaxWidth() + ) { + Text("Login with Google") + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt b/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt index a83ed72..3a7ca36 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/post/Post.kt @@ -19,10 +19,10 @@ 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.wrapContentHeight import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState @@ -64,18 +64,15 @@ import androidx.paging.PagingData import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import coil.compose.AsyncImage -import com.aiosman.riderpro.LocalAnimatedContentScope import com.aiosman.riderpro.LocalNavController -import com.aiosman.riderpro.LocalSharedTransitionScope import com.aiosman.riderpro.R -import com.aiosman.riderpro.data.comment.Comment -import com.aiosman.riderpro.data.comment.CommentPagingSource -import com.aiosman.riderpro.data.comment.CommentRemoteDataSource -import com.aiosman.riderpro.data.comment.TestCommentServiceImpl -import com.aiosman.riderpro.data.moment.MomentService -import com.aiosman.riderpro.data.moment.TestMomentServiceImpl +import com.aiosman.riderpro.data.Comment +import com.aiosman.riderpro.data.CommentPagingSource +import com.aiosman.riderpro.data.CommentRemoteDataSource +import com.aiosman.riderpro.data.TestCommentServiceImpl +import com.aiosman.riderpro.data.MomentService +import com.aiosman.riderpro.data.TestMomentServiceImpl import com.aiosman.riderpro.model.MomentItem -import com.aiosman.riderpro.ui.comment.CommentModalContent import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder import com.aiosman.riderpro.ui.composables.EditCommentBottomModal @@ -122,7 +119,11 @@ fun PostScreen( Column(modifier = Modifier.animateContentSize()) { AnimatedVisibility(visible = showCollapseContent) { // collapse content - Column { + Column( + modifier = Modifier + .fillMaxWidth() + + ) { Box( modifier = Modifier .fillMaxWidth() @@ -267,19 +268,26 @@ fun PostDetails( postId: String, momentItem: MomentItem? ) { - momentItem?.let { - Column(modifier = Modifier.padding(16.dp)) { - Text( - text = momentItem.momentTextContent, - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - ) - Text(text = "12-11 发布") - Spacer(modifier = Modifier.height(8.dp)) - Text(text = "共231条评论") + Column( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + .wrapContentHeight() + ) { + + Text( + text = momentItem?.momentTextContent ?:"", + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + ) + Text(text = "12-11 发布") + Spacer(modifier = Modifier.height(8.dp)) + Text(text = "共231条评论") + } - } + + } diff --git a/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfile.kt b/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfile.kt new file mode 100644 index 0000000..3a27a7e --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfile.kt @@ -0,0 +1,84 @@ +package com.aiosman.riderpro.ui.profile + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.unit.dp +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import androidx.paging.compose.collectAsLazyPagingItems +import com.aiosman.riderpro.data.AccountProfile +import com.aiosman.riderpro.data.MomentPagingSource +import com.aiosman.riderpro.data.MomentRemoteDataSource +import com.aiosman.riderpro.data.TestMomentServiceImpl +import com.aiosman.riderpro.data.TestUserServiceImpl +import com.aiosman.riderpro.data.UserService +import com.aiosman.riderpro.model.MomentItem +import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout +import com.aiosman.riderpro.ui.index.tabs.profile.CarGroup +import com.aiosman.riderpro.ui.index.tabs.profile.MomentPostUnit +import com.aiosman.riderpro.ui.index.tabs.profile.RidingStyle +import com.aiosman.riderpro.ui.index.tabs.profile.UserInformation +import com.google.accompanist.systemuicontroller.rememberSystemUiController +import kotlinx.coroutines.flow.Flow + +@Composable +fun AccountProfile(id:String) { +// val model = MyProfileViewModel + val userService: UserService = TestUserServiceImpl() + var userProfile by remember { mutableStateOf(null) } + var momentListPagingSource = MomentPagingSource( + MomentRemoteDataSource(TestMomentServiceImpl()) + ) + val momentsFlow: Flow> = Pager( + config = PagingConfig(pageSize = 5, enablePlaceholders = false), + pagingSourceFactory = { momentListPagingSource } + ).flow + + LaunchedEffect(Unit) { + userProfile = userService.getUserProfile(id) + } + val items = momentsFlow.collectAsLazyPagingItems() + val systemUiController = rememberSystemUiController() + LaunchedEffect(Unit) { + systemUiController.setNavigationBarColor( + color = androidx.compose.ui.graphics.Color.Transparent + ) + } + StatusBarMaskLayout( + modifier = Modifier.fillMaxSize(), + useNavigationBarMask = false + ) { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(bottom = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top, + ) { + item { + CarGroup() + userProfile?.let { + UserInformation(isSelf = false, accountProfile = it) + + } + RidingStyle() + } + items(items.itemCount) { idx -> + val momentItem = items[idx] ?: return@items + MomentPostUnit(momentItem) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfileViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfileViewModel.kt new file mode 100644 index 0000000..d151d5d --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfileViewModel.kt @@ -0,0 +1,4 @@ +package com.aiosman.riderpro.ui.profile + +object AccountProfileViewModel { +} \ No newline at end of file