From f357e12f7c6549767288ae1aba1e20612c9974f5 Mon Sep 17 00:00:00 2001 From: AllenTom Date: Fri, 6 Sep 2024 16:16:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=88=91=E7=9A=84=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E4=B8=8B=E6=8B=89=E5=88=B7=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增个人主页为空时的文案 发布动态后自动刷新个人主页 --- .../ui/index/tabs/moment/MomentViewModel.kt | 16 +- .../index/tabs/profile/MyProfileViewModel.kt | 10 +- .../riderpro/ui/index/tabs/profile/Profile.kt | 281 +++++++++--------- .../riderpro/ui/post/NewPostViewModel.kt | 3 + app/src/main/res/values-zh/strings.xml | 5 + app/src/main/res/values/strings.xml | 5 + 6 files changed, 163 insertions(+), 157 deletions(-) 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 e78c180..a7ebd75 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 @@ -30,21 +30,7 @@ object MomentViewModel : ViewModel() { val accountService: AccountService = AccountServiceImpl() var existsException = mutableStateOf(false) init { - viewModelScope.launch { - // 获取当前用户信息 - val profile = accountService.getMyAccountProfile() - Pager( - config = PagingConfig(pageSize = 5, enablePlaceholders = false), - pagingSourceFactory = { - MomentPagingSource( - MomentRemoteDataSource(momentService), - timelineId = profile.id - ) - } - ).flow.cachedIn(viewModelScope).collectLatest { - _momentsFlow.value = it - } - } + refreshPager() } fun refreshPager() { viewModelScope.launch { 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 288886b..de97358 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 @@ -5,6 +5,7 @@ import android.net.Uri import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -32,14 +33,18 @@ import kotlinx.coroutines.launch object MyProfileViewModel : ViewModel() { val accountService: AccountService = AccountServiceImpl() val momentService: MomentService = MomentServiceImpl() - val userService = UserServiceImpl() var profile by mutableStateOf(null) private var _momentsFlow = MutableStateFlow>(PagingData.empty()) var momentsFlow = _momentsFlow.asStateFlow() - fun loadProfile() { + var refreshing by mutableStateOf(false) + fun loadProfile(pullRefresh: Boolean = false) { viewModelScope.launch { + if (pullRefresh){ + refreshing = true + } profile = accountService.getMyAccountProfile() val profile = accountService.getMyAccountProfile() + refreshing = false Pager( config = PagingConfig(pageSize = 5, enablePlaceholders = false), pagingSourceFactory = { @@ -51,6 +56,7 @@ object MyProfileViewModel : ViewModel() { ).flow.cachedIn(viewModelScope).collectLatest { _momentsFlow.value = it } + } } 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 ee133d1..d33c19b 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 @@ -2,16 +2,12 @@ package com.aiosman.riderpro.ui.index.tabs.profile import android.app.Activity import android.content.Intent -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.DrawableRes -import androidx.compose.animation.ExperimentalSharedTransitionApi -import androidx.compose.animation.core.Animatable import androidx.compose.foundation.Canvas import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -22,7 +18,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -33,13 +28,14 @@ import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width 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.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -71,23 +67,19 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController import androidx.paging.compose.collectAsLazyPagingItems -import com.aiosman.riderpro.LocalAnimatedContentScope import com.aiosman.riderpro.LocalNavController -import com.aiosman.riderpro.LocalSharedTransitionScope import com.aiosman.riderpro.R import com.aiosman.riderpro.entity.AccountProfileEntity -import com.aiosman.riderpro.exp.formatPostTime import com.aiosman.riderpro.entity.MomentEntity import com.aiosman.riderpro.exp.formatPostTime2 import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.composables.CustomAsyncImage -import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout -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 +@OptIn(ExperimentalMaterialApi::class) @Composable fun ProfilePage() { val model = MyProfileViewModel @@ -98,6 +90,9 @@ fun ProfilePage() { val moments = model.momentsFlow.collectAsLazyPagingItems() val navController: NavController = LocalNavController.current val scope = rememberCoroutineScope() + val state = rememberPullRefreshState(model.refreshing, onRefresh = { + model.loadProfile(pullRefresh = true) + }) val context = LocalContext.current val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues() val pickBannerImageLauncher = rememberLauncherForActivityResult( @@ -110,7 +105,7 @@ fun ProfilePage() { } } } - LazyColumn( + Box( modifier = Modifier .fillMaxSize() .background(Color(0xFFF5F5F5)) @@ -120,148 +115,154 @@ fun ProfilePage() { .toDp() + 48.dp da }) + .pullRefresh(state) ) { - item { - Box( - modifier = Modifier - .fillMaxWidth() - - ) { + LazyColumn( + modifier = Modifier.fillMaxSize() + ) { + item { Box( modifier = Modifier .fillMaxWidth() - .height(400.dp) - .noRippleClickable { - Intent(Intent.ACTION_PICK).apply { - type = "image/*" - pickBannerImageLauncher.launch(this) + + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(400.dp) + .noRippleClickable { + Intent(Intent.ACTION_PICK).apply { + type = "image/*" + pickBannerImageLauncher.launch(this) + } } - } - ) { - val banner = model.profile?.banner - - if (banner != null) { - CustomAsyncImage( - LocalContext.current, - banner, - modifier = Modifier - .fillMaxSize(), - contentDescription = "", - contentScale = ContentScale.Crop - ) - } else { - Image( - painter = painterResource(id = R.drawable.rider_pro_moment_demo_2), - modifier = Modifier - .fillMaxSize(), - contentDescription = "", - contentScale = ContentScale.Crop - ) - } - } - - - Box( - modifier = Modifier - .align(Alignment.TopEnd) - .padding( - top = statusBarPaddingValues.calculateTopPadding(), - start = 16.dp, - end = 16.dp - ) - ) { - Icon( - painter = painterResource(id = R.drawable.rider_pro_more_horizon), - contentDescription = "", - modifier = Modifier.noRippleClickable { - expanded = true - }, - tint = Color.White - ) - MaterialTheme( - shapes = MaterialTheme.shapes.copy( - extraSmall = RoundedCornerShape( - 16.dp - ) - ) ) { - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - modifier = Modifier - .width(250.dp) - .background(Color.White) - ) { - Box( + val banner = model.profile?.banner + + if (banner != null) { + CustomAsyncImage( + LocalContext.current, + banner, modifier = Modifier - .padding(vertical = 14.dp, horizontal = 24.dp) - .noRippleClickable { - expanded = false - scope.launch { - model.logout() - navController.navigate(NavigationRoute.Login.route) { - popUpTo(NavigationRoute.Index.route) { - inclusive = true + .fillMaxSize(), + contentDescription = "", + contentScale = ContentScale.Crop + ) + } else { + Image( + painter = painterResource(id = R.drawable.rider_pro_moment_demo_2), + modifier = Modifier + .fillMaxSize(), + contentDescription = "", + contentScale = ContentScale.Crop + ) + } + } + + + Box( + modifier = Modifier + .align(Alignment.TopEnd) + .padding( + top = statusBarPaddingValues.calculateTopPadding(), + start = 16.dp, + end = 16.dp + ) + ) { + Icon( + painter = painterResource(id = R.drawable.rider_pro_more_horizon), + contentDescription = "", + modifier = Modifier.noRippleClickable { + expanded = true + }, + tint = Color.White + ) + MaterialTheme( + shapes = MaterialTheme.shapes.copy( + extraSmall = RoundedCornerShape( + 16.dp + ) + ) + ) { + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier + .width(250.dp) + .background(Color.White) + ) { + Box( + modifier = Modifier + .padding(vertical = 14.dp, horizontal = 24.dp) + .noRippleClickable { + expanded = false + scope.launch { + model.logout() + navController.navigate(NavigationRoute.Login.route) { + popUpTo(NavigationRoute.Index.route) { + inclusive = true + } } } - } - }) { - Row { - Text("Logout", fontWeight = FontWeight.W500) - Spacer(modifier = Modifier.weight(1f)) - Icon( - painter = painterResource(id = R.mipmap.rider_pro_logout), - contentDescription = "", - modifier = Modifier.size(24.dp) - ) + }) { + Row { + Text(stringResource(R.string.logout), fontWeight = FontWeight.W500) + Spacer(modifier = Modifier.weight(1f)) + Icon( + painter = painterResource(id = R.mipmap.rider_pro_logout), + contentDescription = "", + modifier = Modifier.size(24.dp) + ) + } } - } - Box( - modifier = Modifier - .padding(vertical = 14.dp, horizontal = 24.dp) - .noRippleClickable { - expanded = false - scope.launch { - navController.navigate(NavigationRoute.ChangePasswordScreen.route) - } - }) { - Row { - Text("Change password", fontWeight = FontWeight.W500) - Spacer(modifier = Modifier.weight(1f)) - Icon( - painter = painterResource(id = R.mipmap.rider_pro_change_password), - contentDescription = "", - modifier = Modifier.size(24.dp) - ) + Box( + modifier = Modifier + .padding(vertical = 14.dp, horizontal = 24.dp) + .noRippleClickable { + expanded = false + scope.launch { + navController.navigate(NavigationRoute.ChangePasswordScreen.route) + } + }) { + Row { + Text(stringResource(R.string.change_password), fontWeight = FontWeight.W500) + Spacer(modifier = Modifier.weight(1f)) + Icon( + painter = painterResource(id = R.mipmap.rider_pro_change_password), + contentDescription = "", + modifier = Modifier.size(24.dp) + ) + } } } } } } + Spacer(modifier = Modifier.height(32.dp)) + model.profile?.let { + UserInformation( + accountProfileEntity = it, + onEditProfileClick = { + navController.navigate(NavigationRoute.AccountEdit.route) + } + ) + } + if (moments.itemCount == 0) { + EmptyMomentPostUnit() + } } - Spacer(modifier = Modifier.height(32.dp)) - model.profile?.let { - UserInformation( - accountProfileEntity = it, - onEditProfileClick = { - navController.navigate(NavigationRoute.AccountEdit.route) - } - ) - } - if (moments.itemCount == 0) { - EmptyMomentPostUnit() - } - } - items(moments.itemCount) { idx -> - val momentItem = moments[idx] ?: return@items - MomentPostUnit(momentItem) - } - item { - Spacer(modifier = Modifier.height(48.dp)) - } + items(moments.itemCount) { idx -> + val momentItem = moments[idx] ?: return@items + MomentPostUnit(momentItem) + } + item { + Spacer(modifier = Modifier.height(48.dp)) + } + } + PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter)) } @@ -541,7 +542,7 @@ fun CommunicationOperatorGroup( contentDescription = "" ) Text( - text = "Edit profile", + text = stringResource(R.string.edit_profile), fontSize = 14.sp, color = Color.Black, fontWeight = FontWeight.Bold, @@ -619,7 +620,7 @@ fun RidingStyleItem(styleContent: String) { @Composable fun EmptyMomentPostUnit() { - TimeGroup("You haven't left any tracks yet") + TimeGroup(stringResource(R.string.empty_my_post_title)) ProfileEmptyMomentCard() } @@ -660,7 +661,7 @@ fun ProfileEmptyMomentCard( columnHeight = coordinates.size.height } ) { - Text("Post a moment now", fontSize = 16.sp) + Text(stringResource(R.string.empty_my_post_content), fontSize = 16.sp) Spacer(modifier = Modifier.height(24.dp)) Box( modifier = Modifier diff --git a/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt index 324b60b..d2d517b 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/post/NewPostViewModel.kt @@ -11,6 +11,7 @@ import com.aiosman.riderpro.data.MomentService import com.aiosman.riderpro.entity.MomentServiceImpl import com.aiosman.riderpro.data.UploadImage import com.aiosman.riderpro.entity.MomentEntity +import com.aiosman.riderpro.ui.index.tabs.profile.MyProfileViewModel import com.aiosman.riderpro.ui.modification.Modification import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -75,6 +76,8 @@ object NewPostViewModel : ViewModel() { index += 1 } momentService.createMoment(textContent, 1, uploadImageList, relPostId) + // 刷新个人动态 + MyProfileViewModel.loadProfile() } suspend fun init() { diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 77876d2..2ec5dac 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -45,4 +45,9 @@ 服务端未知错误 为了为您提供更个性化的服务,请允许我们向您推送相关信息。 "为了提供更好的服务,请您在注册前仔细阅读并同意《用户协议》。 " + 还没有发布任何动态 + 发布一个动态吧 + 编辑个人资料 + 登出 + 变更密码 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9ccd14a..92c9bb4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,4 +44,9 @@ Unknown error To provide you with a more personalized experience, please allow us to send you relevant notifications. To provide you with the best service, please read and agree to our User Agreement before registering. + You haven\'t left any tracks yet + Post a moment now + Edit profile + Logout + Change password \ No newline at end of file