From b788ab0dbad50699f7b1f8088962927e8d972037 Mon Sep 17 00:00:00 2001 From: AllenTom Date: Sun, 25 Aug 2024 21:02:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=83=A8=E5=88=86UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aiosman/riderpro/data/api/ApiClient.kt | 9 +- .../com/aiosman/riderpro/ui/index/Index.kt | 66 +++++-------- .../riderpro/ui/index/tabs/moment/Moment.kt | 1 - .../index/tabs/profile/MyProfileViewModel.kt | 65 +++++++++---- .../riderpro/ui/index/tabs/profile/Profile.kt | 92 +++++++++---------- .../com/aiosman/riderpro/ui/login/signup.kt | 68 +++++++------- .../riderpro/ui/profile/AccountProfile.kt | 2 +- 7 files changed, 156 insertions(+), 147 deletions(-) diff --git a/app/src/main/java/com/aiosman/riderpro/data/api/ApiClient.kt b/app/src/main/java/com/aiosman/riderpro/data/api/ApiClient.kt index 0487442..fef6181 100644 --- a/app/src/main/java/com/aiosman/riderpro/data/api/ApiClient.kt +++ b/app/src/main/java/com/aiosman/riderpro/data/api/ApiClient.kt @@ -1,6 +1,7 @@ package com.aiosman.riderpro.data.api import android.icu.text.SimpleDateFormat +import android.icu.util.TimeZone import com.aiosman.riderpro.AppStore import com.aiosman.riderpro.ConstVars import okhttp3.Interceptor @@ -85,9 +86,13 @@ object ApiClient { } fun dateFromApiString(apiString: String): Date { - val timeFormat = ApiClient.TIME_FORMAT + val timeFormat = TIME_FORMAT val simpleDateFormat = SimpleDateFormat(timeFormat, Locale.getDefault()) + simpleDateFormat.timeZone = TimeZone.getTimeZone("UTC") val date = simpleDateFormat.parse(apiString) - return date + + simpleDateFormat.timeZone = TimeZone.getDefault() + val localDateString = simpleDateFormat.format(date) + return simpleDateFormat.parse(localDateString) } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/Index.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/Index.kt index 8ac02ae..a1c9491 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/index/Index.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/index/Index.kt @@ -4,6 +4,7 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.tween import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement 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.padding 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.NavigationBar import androidx.compose.material3.NavigationBarItem @@ -22,6 +25,7 @@ import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier 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.post.NewPostViewModel import com.google.accompanist.systemuicontroller.rememberSystemUiController +import kotlinx.coroutines.launch +@OptIn(ExperimentalFoundationApi::class) @Composable fun IndexScreen() { val model = IndexViewModel @@ -51,13 +57,13 @@ fun IndexScreen() { val item = listOf( NavigationItem.Home, NavigationItem.Search, -// NavigationItem.Street, NavigationItem.Add, -// NavigationItem.Message, NavigationItem.Notification, NavigationItem.Profile ) val systemUiController = rememberSystemUiController() + val pagerState = rememberPagerState(pageCount = { item.size }) + val coroutineScope = rememberCoroutineScope() LaunchedEffect(Unit) { systemUiController.setNavigationBarColor(Color.Transparent) @@ -77,16 +83,14 @@ fun IndexScreen() { NavigationBarItem( selected = isSelected, onClick = { - if (it.route === NavigationItem.Add.route) { NewPostViewModel.asNewPost() - - navController.navigate( - NavigationRoute.NewPost.route, - - ) + navController.navigate(NavigationRoute.NewPost.route) return@NavigationBarItem } + coroutineScope.launch { + pagerState.scrollToPage(idx) + } model.tabIndex = idx }, colors = NavigationBarItemColors( @@ -108,43 +112,21 @@ fun IndexScreen() { } ) } - } } ) { innerPadding -> - Box( - modifier = Modifier - ) { - when (model.tabIndex) { - 0 -> Box( - modifier = Modifier.padding(innerPadding) - ) { - Home() - } - - 1 -> Box( - modifier = Modifier.padding(innerPadding) - ) { - 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() } + HorizontalPager( + state = pagerState, + modifier = Modifier.padding(innerPadding), + beyondBoundsPageCount = 5, + userScrollEnabled = false + ) { page -> + when (page) { + 0 -> Home() + 1 -> SearchScreen() + 2 -> Add() + 3 -> Notifications() + 4 -> Profile() } } } 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 e0bf6b6..a265f53 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 @@ -90,7 +90,6 @@ fun MomentsList() { var moments = dataFlow.collectAsLazyPagingItems() val scope = rememberCoroutineScope() var refreshing by remember { mutableStateOf(false) } - moments.loadState val state = rememberPullRefreshState(refreshing, onRefresh = { model.refreshPager() }) 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 index 8dc845f..666f7f5 100644 --- 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 @@ -3,40 +3,67 @@ 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.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData +import androidx.paging.cachedIn import com.aiosman.riderpro.AppStore -import com.aiosman.riderpro.entity.AccountProfileEntity import com.aiosman.riderpro.data.AccountService 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.MomentRemoteDataSource import com.aiosman.riderpro.entity.MomentServiceImpl -import com.aiosman.riderpro.data.UserServiceImpl -import com.aiosman.riderpro.entity.MomentEntity -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch -object MyProfileViewModel { - val service: AccountService = AccountServiceImpl() +object MyProfileViewModel : ViewModel() { + val accountService: AccountService = AccountServiceImpl() + val momentService: MomentService = MomentServiceImpl() val userService = UserServiceImpl() var profile by mutableStateOf(null) - var momentsFlow by mutableStateOf>?>(null) - suspend fun loadProfile() { - profile = service.getMyAccountProfile() - momentsFlow = Pager( - config = PagingConfig(pageSize = 5, enablePlaceholders = false), - pagingSourceFactory = { - MomentPagingSource( - MomentRemoteDataSource(MomentServiceImpl()), - author = profile?.id ?: 0, + private var _momentsFlow = MutableStateFlow>(PagingData.empty()) + var momentsFlow = _momentsFlow.asStateFlow() + fun loadProfile(){ - ) +// 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() { - service.getMyAccountProfile() + accountService.getMyAccountProfile() AppStore.apply { token = null rememberMe = false @@ -44,10 +71,12 @@ object MyProfileViewModel { } } + 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 dee1f3f..11fdbd9 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 @@ -1,5 +1,6 @@ package com.aiosman.riderpro.ui.index.tabs.profile +import android.util.Log import androidx.annotation.DrawableRes import androidx.compose.animation.ExperimentalSharedTransitionApi 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.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -19,6 +21,7 @@ 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.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.DropdownMenu 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.ui.NavigationRoute 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.post.PostViewModel import kotlinx.coroutines.launch @@ -65,19 +69,17 @@ fun ProfilePage() { val model = MyProfileViewModel var expanded by remember { mutableStateOf(false) } LaunchedEffect(Unit) { + Log.d("ProfilePage", "loadProfile") model.loadProfile() } - val moments = model.momentsFlow?.collectAsLazyPagingItems() + val moments = model.momentsFlow.collectAsLazyPagingItems() val navController: NavController = LocalNavController.current val scope = rememberCoroutineScope() - Box { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(bottom = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Top, - ) { + + LazyColumn( + modifier = Modifier + .fillMaxSize(), + ) { item { Box( modifier = Modifier @@ -132,18 +134,19 @@ fun ProfilePage() { model.profile?.let { UserInformation(accountProfileEntity = it) } - RidingStyle() - } - moments?.let { - items(it.itemCount) { idx -> - val momentItem = it[idx] ?: return@items - MomentPostUnit(momentItem) - } +// RidingStyle() } + items(moments.itemCount) { idx -> + val momentItem = moments[idx] ?: return@items + MomentPostUnit(momentItem) +// MomentCard(momentItem) } + + } + } @Composable @@ -289,12 +292,12 @@ fun UserInformationBasic(modifier: Modifier, accountProfileEntity: AccountProfil 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.padding(top = 4.dp), +// text = "Member since Jun 4.2019", +// fontSize = 12.sp, +// color = Color.Gray +// ) } } @@ -525,37 +528,30 @@ fun MomentCardTopContent(content: String) { } } -@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) { val navController = LocalNavController.current - val sharedTransitionScope = LocalSharedTransitionScope.current - val animatedVisibilityScope = LocalAnimatedContentScope.current val context = LocalContext.current - with(sharedTransitionScope) { - CustomAsyncImage( - context, - imageUrl, - modifier = Modifier - .sharedElement( - rememberSharedContentState(key = imageUrl), - animatedVisibilityScope = animatedVisibilityScope - ) - .fillMaxSize() - .padding(16.dp) - .noRippleClickable { - PostViewModel.preTransit(momentEntity) - navController.navigate( - NavigationRoute.Post.route.replace( - "{id}", - momentEntity.id.toString() - ) + CustomAsyncImage( + context, + imageUrl, + modifier = Modifier + .fillMaxSize() + .aspectRatio(1f) + .padding(16.dp) + .noRippleClickable { + PostViewModel.preTransit(momentEntity) + navController.navigate( + NavigationRoute.Post.route.replace( + "{id}", + momentEntity.id.toString() ) - }, - contentDescription = "", - contentScale = ContentScale.FillWidth - ) - } + ) + }, + contentDescription = "", + contentScale = ContentScale.Crop + ) + } diff --git a/app/src/main/java/com/aiosman/riderpro/ui/login/signup.kt b/app/src/main/java/com/aiosman/riderpro/ui/login/signup.kt index 2efacb5..ba1d299 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/login/signup.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/login/signup.kt @@ -171,22 +171,22 @@ fun SignupScreen() { ) { navController.navigate(NavigationRoute.EmailSignUp.route) } - Spacer(modifier = Modifier.height(16.dp)) - ActionButton( - modifier = Modifier - .width(345.dp) - .height(48.dp), - text = "CONTINUE WITH FACEBOOK".uppercase(), - backgroundImage = R.mipmap.rider_pro_signup_facebook_bg, - leading = { - Image( - painter = painterResource(id = R.mipmap.rider_pro_signup_facebook), - contentDescription = "Facebook", - modifier = Modifier.size(24.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - } - ) +// Spacer(modifier = Modifier.height(16.dp)) +// ActionButton( +// modifier = Modifier +// .width(345.dp) +// .height(48.dp), +// text = "CONTINUE WITH FACEBOOK".uppercase(), +// backgroundImage = R.mipmap.rider_pro_signup_facebook_bg, +// leading = { +// Image( +// painter = painterResource(id = R.mipmap.rider_pro_signup_facebook), +// contentDescription = "Facebook", +// modifier = Modifier.size(24.dp) +// ) +// Spacer(modifier = Modifier.width(8.dp)) +// } +// ) Spacer(modifier = Modifier.height(16.dp)) ActionButton( modifier = Modifier @@ -204,28 +204,26 @@ fun SignupScreen() { text = "CONTINUE WITH GOOGLE".uppercase(), backgroundImage = R.mipmap.rider_pro_signup_white_bg ) { -// val signInIntent = googleSignInClient.signInIntent -// launcher.launch(signInIntent) googleLogin() } - Spacer(modifier = Modifier.height(16.dp)) - Box( - modifier = Modifier - .width(345.dp) - .height(48.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color.Black) - - ) { - Text( - "Sign in with Apple", - color = Color.White, - modifier = Modifier.align(Alignment.Center), - fontSize = 16.sp, - fontWeight = FontWeight.Bold - ) - } +// Spacer(modifier = Modifier.height(16.dp)) +// Box( +// modifier = Modifier +// .width(345.dp) +// .height(48.dp) +// .clip(RoundedCornerShape(8.dp)) +// .background(Color.Black) +// +// ) { +// Text( +// "Sign in with Apple", +// color = Color.White, +// modifier = Modifier.align(Alignment.Center), +// fontSize = 16.sp, +// fontWeight = FontWeight.Bold +// ) +// } Spacer(modifier = Modifier.height(40.dp)) Row( verticalAlignment = Alignment.CenterVertically, 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 index cbb3e59..3b4c741 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfile.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/profile/AccountProfile.kt @@ -90,7 +90,7 @@ fun AccountProfile(id:String) { }, ) } - RidingStyle() +// RidingStyle() } if (items != null) { items(items.itemCount) { idx ->