更新部分UI

This commit is contained in:
2024-08-25 21:02:51 +08:00
parent b4004663cd
commit b788ab0dba
7 changed files with 156 additions and 147 deletions

View File

@@ -1,6 +1,7 @@
package com.aiosman.riderpro.data.api package com.aiosman.riderpro.data.api
import android.icu.text.SimpleDateFormat import android.icu.text.SimpleDateFormat
import android.icu.util.TimeZone
import com.aiosman.riderpro.AppStore import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.ConstVars import com.aiosman.riderpro.ConstVars
import okhttp3.Interceptor import okhttp3.Interceptor
@@ -85,9 +86,13 @@ object ApiClient {
} }
fun dateFromApiString(apiString: String): Date { fun dateFromApiString(apiString: String): Date {
val timeFormat = ApiClient.TIME_FORMAT val timeFormat = TIME_FORMAT
val simpleDateFormat = SimpleDateFormat(timeFormat, Locale.getDefault()) val simpleDateFormat = SimpleDateFormat(timeFormat, Locale.getDefault())
simpleDateFormat.timeZone = TimeZone.getTimeZone("UTC")
val date = simpleDateFormat.parse(apiString) val date = simpleDateFormat.parse(apiString)
return date
simpleDateFormat.timeZone = TimeZone.getDefault()
val localDateString = simpleDateFormat.format(date)
return simpleDateFormat.parse(localDateString)
} }
} }

View File

@@ -4,6 +4,7 @@ import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@@ -14,6 +15,8 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
@@ -22,6 +25,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -40,7 +44,9 @@ import com.aiosman.riderpro.ui.index.tabs.street.StreetPage
import com.aiosman.riderpro.ui.message.MessagePage import com.aiosman.riderpro.ui.message.MessagePage
import com.aiosman.riderpro.ui.post.NewPostViewModel import com.aiosman.riderpro.ui.post.NewPostViewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.launch
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun IndexScreen() { fun IndexScreen() {
val model = IndexViewModel val model = IndexViewModel
@@ -51,13 +57,13 @@ fun IndexScreen() {
val item = listOf( val item = listOf(
NavigationItem.Home, NavigationItem.Home,
NavigationItem.Search, NavigationItem.Search,
// NavigationItem.Street,
NavigationItem.Add, NavigationItem.Add,
// NavigationItem.Message,
NavigationItem.Notification, NavigationItem.Notification,
NavigationItem.Profile NavigationItem.Profile
) )
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
val pagerState = rememberPagerState(pageCount = { item.size })
val coroutineScope = rememberCoroutineScope()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
systemUiController.setNavigationBarColor(Color.Transparent) systemUiController.setNavigationBarColor(Color.Transparent)
@@ -77,16 +83,14 @@ fun IndexScreen() {
NavigationBarItem( NavigationBarItem(
selected = isSelected, selected = isSelected,
onClick = { onClick = {
if (it.route === NavigationItem.Add.route) { if (it.route === NavigationItem.Add.route) {
NewPostViewModel.asNewPost() NewPostViewModel.asNewPost()
navController.navigate(NavigationRoute.NewPost.route)
navController.navigate(
NavigationRoute.NewPost.route,
)
return@NavigationBarItem return@NavigationBarItem
} }
coroutineScope.launch {
pagerState.scrollToPage(idx)
}
model.tabIndex = idx model.tabIndex = idx
}, },
colors = NavigationBarItemColors( colors = NavigationBarItemColors(
@@ -108,43 +112,21 @@ fun IndexScreen() {
} }
) )
} }
} }
} }
) { innerPadding -> ) { innerPadding ->
Box( HorizontalPager(
modifier = Modifier state = pagerState,
) { modifier = Modifier.padding(innerPadding),
when (model.tabIndex) { beyondBoundsPageCount = 5,
0 -> Box( userScrollEnabled = false
modifier = Modifier.padding(innerPadding) ) { page ->
) { when (page) {
Home() 0 -> Home()
} 1 -> SearchScreen()
2 -> Add()
1 -> Box( 3 -> Notifications()
modifier = Modifier.padding(innerPadding) 4 -> Profile()
) {
SearchScreen()
}
// 1 -> Street()
2 -> Box(
modifier = Modifier.padding(innerPadding)
) { Add() }
// 3 -> Box(
// modifier = Modifier.padding(innerPadding)
// ) { Video() }
3 -> Box(
modifier = Modifier.padding(innerPadding)
) {
Notifications()
}
4 -> Box(
modifier = Modifier.padding(innerPadding)
) { Profile() }
} }
} }
} }

View File

@@ -90,7 +90,6 @@ fun MomentsList() {
var moments = dataFlow.collectAsLazyPagingItems() var moments = dataFlow.collectAsLazyPagingItems()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
var refreshing by remember { mutableStateOf(false) } var refreshing by remember { mutableStateOf(false) }
moments.loadState
val state = rememberPullRefreshState(refreshing, onRefresh = { val state = rememberPullRefreshState(refreshing, onRefresh = {
model.refreshPager() model.refreshPager()
}) })

View File

@@ -3,40 +3,67 @@ package com.aiosman.riderpro.ui.index.tabs.profile
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.aiosman.riderpro.AppStore import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.entity.AccountProfileEntity
import com.aiosman.riderpro.data.AccountService import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.AccountServiceImpl import com.aiosman.riderpro.data.AccountServiceImpl
import com.aiosman.riderpro.data.MomentService
import com.aiosman.riderpro.data.UserServiceImpl
import com.aiosman.riderpro.entity.AccountProfileEntity
import com.aiosman.riderpro.entity.MomentEntity
import com.aiosman.riderpro.entity.MomentPagingSource import com.aiosman.riderpro.entity.MomentPagingSource
import com.aiosman.riderpro.entity.MomentRemoteDataSource import com.aiosman.riderpro.entity.MomentRemoteDataSource
import com.aiosman.riderpro.entity.MomentServiceImpl import com.aiosman.riderpro.entity.MomentServiceImpl
import com.aiosman.riderpro.data.UserServiceImpl import kotlinx.coroutines.flow.MutableStateFlow
import com.aiosman.riderpro.entity.MomentEntity import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
object MyProfileViewModel { object MyProfileViewModel : ViewModel() {
val service: AccountService = AccountServiceImpl() val accountService: AccountService = AccountServiceImpl()
val momentService: MomentService = MomentServiceImpl()
val userService = UserServiceImpl() val userService = UserServiceImpl()
var profile by mutableStateOf<AccountProfileEntity?>(null) var profile by mutableStateOf<AccountProfileEntity?>(null)
var momentsFlow by mutableStateOf<Flow<PagingData<MomentEntity>>?>(null) private var _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
suspend fun loadProfile() { var momentsFlow = _momentsFlow.asStateFlow()
profile = service.getMyAccountProfile() fun loadProfile(){
momentsFlow = Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
MomentPagingSource(
MomentRemoteDataSource(MomentServiceImpl()),
author = profile?.id ?: 0,
) // momentsFlow = Pager(
// config = PagingConfig(pageSize = 5, enablePlaceholders = false),
// pagingSourceFactory = {
// MomentPagingSource(
// MomentRemoteDataSource(MomentServiceImpl()),
// author = profile?.id ?: 0,
//
// )
// }
// ).flow.cachedIn(viewModelScope).collectLatest {
// MomentViewModel._momentsFlow.value = it
// }
viewModelScope.launch {
profile = accountService.getMyAccountProfile()
val profile = accountService.getMyAccountProfile()
Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
MomentPagingSource(
MomentRemoteDataSource(momentService),
author = profile.id
)
}
).flow.cachedIn(viewModelScope).collectLatest {
_momentsFlow.value = it
} }
).flow }
} }
suspend fun logout() { suspend fun logout() {
service.getMyAccountProfile() accountService.getMyAccountProfile()
AppStore.apply { AppStore.apply {
token = null token = null
rememberMe = false rememberMe = false
@@ -44,10 +71,12 @@ object MyProfileViewModel {
} }
} }
val followerCount get() = profile?.followerCount ?: 0 val followerCount get() = profile?.followerCount ?: 0
val followingCount get() = profile?.followingCount ?: 0 val followingCount get() = profile?.followingCount ?: 0
val bio get() = profile?.bio ?: "" val bio get() = profile?.bio ?: ""
val nickName get() = profile?.nickName ?: "" val nickName get() = profile?.nickName ?: ""
val avatar get() = profile?.avatar val avatar get() = profile?.avatar
} }

View File

@@ -1,5 +1,6 @@
package com.aiosman.riderpro.ui.index.tabs.profile package com.aiosman.riderpro.ui.index.tabs.profile
import android.util.Log
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
@@ -11,6 +12,7 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@@ -19,6 +21,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
@@ -55,6 +58,7 @@ import com.aiosman.riderpro.exp.formatPostTime
import com.aiosman.riderpro.entity.MomentEntity import com.aiosman.riderpro.entity.MomentEntity
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.composables.CustomAsyncImage import com.aiosman.riderpro.ui.composables.CustomAsyncImage
import com.aiosman.riderpro.ui.index.tabs.moment.MomentCard
import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.aiosman.riderpro.ui.post.PostViewModel import com.aiosman.riderpro.ui.post.PostViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -65,19 +69,17 @@ fun ProfilePage() {
val model = MyProfileViewModel val model = MyProfileViewModel
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
Log.d("ProfilePage", "loadProfile")
model.loadProfile() model.loadProfile()
} }
val moments = model.momentsFlow?.collectAsLazyPagingItems() val moments = model.momentsFlow.collectAsLazyPagingItems()
val navController: NavController = LocalNavController.current val navController: NavController = LocalNavController.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
Box {
LazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize(),
.padding(bottom = 16.dp), ) {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top,
) {
item { item {
Box( Box(
modifier = Modifier modifier = Modifier
@@ -132,18 +134,19 @@ fun ProfilePage() {
model.profile?.let { model.profile?.let {
UserInformation(accountProfileEntity = it) UserInformation(accountProfileEntity = it)
} }
RidingStyle() // RidingStyle()
}
moments?.let {
items(it.itemCount) { idx ->
val momentItem = it[idx] ?: return@items
MomentPostUnit(momentItem)
}
} }
items(moments.itemCount) { idx ->
val momentItem = moments[idx] ?: return@items
MomentPostUnit(momentItem)
// MomentCard(momentItem)
} }
} }
} }
@Composable @Composable
@@ -289,12 +292,12 @@ fun UserInformationBasic(modifier: Modifier, accountProfileEntity: AccountProfil
fontSize = 12.sp, fontSize = 12.sp,
color = Color.Gray color = Color.Gray
) )
Text( // Text(
modifier = Modifier.padding(top = 4.dp), // modifier = Modifier.padding(top = 4.dp),
text = "Member since Jun 4.2019", // text = "Member since Jun 4.2019",
fontSize = 12.sp, // fontSize = 12.sp,
color = Color.Gray // color = Color.Gray
) // )
} }
} }
@@ -525,37 +528,30 @@ fun MomentCardTopContent(content: String) {
} }
} }
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable @Composable
fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) { fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) {
val navController = LocalNavController.current val navController = LocalNavController.current
val sharedTransitionScope = LocalSharedTransitionScope.current
val animatedVisibilityScope = LocalAnimatedContentScope.current
val context = LocalContext.current val context = LocalContext.current
with(sharedTransitionScope) { CustomAsyncImage(
CustomAsyncImage( context,
context, imageUrl,
imageUrl, modifier = Modifier
modifier = Modifier .fillMaxSize()
.sharedElement( .aspectRatio(1f)
rememberSharedContentState(key = imageUrl), .padding(16.dp)
animatedVisibilityScope = animatedVisibilityScope .noRippleClickable {
) PostViewModel.preTransit(momentEntity)
.fillMaxSize() navController.navigate(
.padding(16.dp) NavigationRoute.Post.route.replace(
.noRippleClickable { "{id}",
PostViewModel.preTransit(momentEntity) momentEntity.id.toString()
navController.navigate(
NavigationRoute.Post.route.replace(
"{id}",
momentEntity.id.toString()
)
) )
}, )
contentDescription = "", },
contentScale = ContentScale.FillWidth contentDescription = "",
) contentScale = ContentScale.Crop
} )
} }

View File

@@ -171,22 +171,22 @@ fun SignupScreen() {
) { ) {
navController.navigate(NavigationRoute.EmailSignUp.route) navController.navigate(NavigationRoute.EmailSignUp.route)
} }
Spacer(modifier = Modifier.height(16.dp)) // Spacer(modifier = Modifier.height(16.dp))
ActionButton( // ActionButton(
modifier = Modifier // modifier = Modifier
.width(345.dp) // .width(345.dp)
.height(48.dp), // .height(48.dp),
text = "CONTINUE WITH FACEBOOK".uppercase(), // text = "CONTINUE WITH FACEBOOK".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_facebook_bg, // backgroundImage = R.mipmap.rider_pro_signup_facebook_bg,
leading = { // leading = {
Image( // Image(
painter = painterResource(id = R.mipmap.rider_pro_signup_facebook), // painter = painterResource(id = R.mipmap.rider_pro_signup_facebook),
contentDescription = "Facebook", // contentDescription = "Facebook",
modifier = Modifier.size(24.dp) // modifier = Modifier.size(24.dp)
) // )
Spacer(modifier = Modifier.width(8.dp)) // Spacer(modifier = Modifier.width(8.dp))
} // }
) // )
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
ActionButton( ActionButton(
modifier = Modifier modifier = Modifier
@@ -204,28 +204,26 @@ fun SignupScreen() {
text = "CONTINUE WITH GOOGLE".uppercase(), text = "CONTINUE WITH GOOGLE".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_white_bg backgroundImage = R.mipmap.rider_pro_signup_white_bg
) { ) {
// val signInIntent = googleSignInClient.signInIntent
// launcher.launch(signInIntent)
googleLogin() googleLogin()
} }
Spacer(modifier = Modifier.height(16.dp)) // Spacer(modifier = Modifier.height(16.dp))
Box( // Box(
modifier = Modifier // modifier = Modifier
.width(345.dp) // .width(345.dp)
.height(48.dp) // .height(48.dp)
.clip(RoundedCornerShape(8.dp)) // .clip(RoundedCornerShape(8.dp))
.background(Color.Black) // .background(Color.Black)
//
) { // ) {
Text( // Text(
"Sign in with Apple", // "Sign in with Apple",
color = Color.White, // color = Color.White,
modifier = Modifier.align(Alignment.Center), // modifier = Modifier.align(Alignment.Center),
fontSize = 16.sp, // fontSize = 16.sp,
fontWeight = FontWeight.Bold // fontWeight = FontWeight.Bold
) // )
} // }
Spacer(modifier = Modifier.height(40.dp)) Spacer(modifier = Modifier.height(40.dp))
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,

View File

@@ -90,7 +90,7 @@ fun AccountProfile(id:String) {
}, },
) )
} }
RidingStyle() // RidingStyle()
} }
if (items != null) { if (items != null) {
items(items.itemCount) { idx -> items(items.itemCount) { idx ->