添加业务逻辑

This commit is contained in:
2024-07-29 00:01:09 +08:00
parent cdc0f6e38d
commit d23c5f5c7e
19 changed files with 764 additions and 321 deletions

View File

@@ -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")
}

View File

@@ -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"
)
}
}

View File

@@ -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

View File

@@ -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<Int, MomentItem>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentItem> {
return try {
val currentPage = params.key ?: 1
@@ -46,6 +44,7 @@ class MomentRemoteDataSource(
interface MomentService {
suspend fun getMoments(pageNumber: Int): ListContainer<MomentItem>
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<MomentItem> {
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(

View File

@@ -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, "", "", "", "")
}
}

View File

@@ -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<String> = 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<String> = emptyList(),
val authorId: Int = 0
)

View File

@@ -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<MomentItem>()
var accountData = emptyList<AccountProfile>()
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<Pair<Int, Int>>()
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
)
}
}
}

View File

@@ -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")!!)
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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())
}
}
}

View File

@@ -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<PagingData<MomentItem>> = Pager(
var momentsFlow: Flow<PagingData<MomentItem>> = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = { momentListPagingSource }
pagingSourceFactory = {
MomentPagingSource(
MomentRemoteDataSource(momentService)
)
}
).flow
suspend fun likeMoment(id: Int) {
momentService.likeMoment(id)
}
}

View File

@@ -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<AccountProfile?>(null)
suspend fun loadProfile() {
profile = service.getAccountProfile()
}
var momentListPagingSource = MomentPagingSource(
MomentRemoteDataSource(TestMomentServiceImpl())
)
val momentsFlow: Flow<PagingData<MomentItem>> = 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
}

View File

@@ -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,
){
) {
item {
CarGroup()
UserInformation()
model.profile?.let {
UserInformation(accountProfile = it)
}
RidingStyle()
UserMoment()
}
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
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))
.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
if (isSelf) {
Box(
modifier = Modifier
.size(width = 142.dp, height = 40.dp)
.padding(start = 6.dp).clickable {
.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))
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 {
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))
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
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
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
.height(8.dp),
painter = painterResource(id = R.drawable.rider_pro_profile_line),
contentDescription = ""
)
FlowRow(
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp)){
.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(
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),
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))
),
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
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
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))
){
.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
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
fun MomentCardPicture(@DrawableRes drawable: Int) {
Image(
modifier = Modifier
.fillMaxSize()
.padding(16.dp), painter = painterResource(id = drawable), contentDescription = "")
.padding(16.dp), painter = painterResource(id = drawable), contentDescription = ""
)
}
@Composable
fun MomentCardOperation(like: String, comment: String){
Row(modifier = Modifier
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)
}
}

View File

@@ -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")
}
}
}
}

View File

@@ -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)) {
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.wrapContentHeight()
) {
Text(
text = momentItem.momentTextContent,
text = momentItem?.momentTextContent ?:"",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
)
Text(text = "12-11 发布")
Spacer(modifier = Modifier.height(8.dp))
Text(text = "共231条评论")
}
}
}

View File

@@ -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<AccountProfile?>(null) }
var momentListPagingSource = MomentPagingSource(
MomentRemoteDataSource(TestMomentServiceImpl())
)
val momentsFlow: Flow<PagingData<MomentItem>> = 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)
}
}
}
}

View File

@@ -0,0 +1,4 @@
package com.aiosman.riderpro.ui.profile
object AccountProfileViewModel {
}