From e936f9cb777c18ba5d187e8cfa4e341ab4c88bb1 Mon Sep 17 00:00:00 2001 From: AllenTom Date: Fri, 6 Sep 2024 01:55:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=85=B3=E6=B3=A8=E5=92=8C?= =?UTF-8?q?=E7=B2=89=E4=B8=9D=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增关注和粉丝列表页面 - 新增关注和粉丝列表ViewModel - 更新UserService以支持获取关注和粉丝列表 - 更新RiderProAPI以支持获取关注和粉丝列表 - 更新Profile页面以支持跳转到关注和粉丝列表页面 - 更新Navi以支持关注和粉丝列表页面导航 - 更新UserInformationFollowers和UserInformationFollowing以支持跳转到关注和粉丝列表页面 - 更新MyProfileViewModel 以支持更新用户资料横幅 --- .../com/aiosman/riderpro/data/UserService.kt | 20 ++++- .../aiosman/riderpro/data/api/RiderProAPI.kt | 3 + .../java/com/aiosman/riderpro/entity/User.kt | 8 +- .../main/java/com/aiosman/riderpro/ui/Navi.kt | 30 ++++++- .../riderpro/ui/follower/FollowerList.kt | 57 ++++++++++++ .../ui/follower/FollowerListViewModel.kt | 63 +++++++++++++ ...iewModel.kt => FollowerNoticeViewModel.kt} | 2 +- .../riderpro/ui/follower/FollowerPage.kt | 31 ++++--- .../riderpro/ui/follower/FollowingList.kt | 57 ++++++++++++ .../ui/follower/FollowingListViewModel.kt | 63 +++++++++++++ .../index/tabs/profile/MyProfileViewModel.kt | 35 +++++++- .../riderpro/ui/index/tabs/profile/Profile.kt | 89 ++++++++++++++----- 12 files changed, 412 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerList.kt create mode 100644 app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerListViewModel.kt rename app/src/main/java/com/aiosman/riderpro/ui/follower/{FollowerViewModel.kt => FollowerNoticeViewModel.kt} (98%) create mode 100644 app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingList.kt create mode 100644 app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingListViewModel.kt diff --git a/app/src/main/java/com/aiosman/riderpro/data/UserService.kt b/app/src/main/java/com/aiosman/riderpro/data/UserService.kt index 6452ffd..96313c4 100644 --- a/app/src/main/java/com/aiosman/riderpro/data/UserService.kt +++ b/app/src/main/java/com/aiosman/riderpro/data/UserService.kt @@ -36,12 +36,16 @@ interface UserService { * @param pageSize 分页大小 * @param page 页码 * @param nickname 昵称搜索 + * @param followerId 粉丝ID,账号粉丝 + * @param followingId 关注ID,账号关注 * @return 用户列表 */ suspend fun getUsers( pageSize: Int = 20, page: Int = 1, - nickname: String? = null + nickname: String? = null, + followerId: Int? = null, + followingId: Int? = null ): ListContainer } @@ -66,15 +70,23 @@ class UserServiceImpl : UserService { override suspend fun getUsers( pageSize: Int, page: Int, - nickname: String? + nickname: String?, + followerId: Int?, + followingId: Int? ): ListContainer { - val resp = ApiClient.api.getUsers(page, pageSize, nickname) + val resp = ApiClient.api.getUsers( + page = page, + pageSize = pageSize, + search = nickname, + followerId = followerId, + followingId = followingId + ) val body = resp.body() ?: throw ServiceException("Failed to get account") return ListContainer( list = body.list.map { it.toAccountProfileEntity() }, page = body.page, total = body.total, - pageSize = body.pageSize + pageSize = body.pageSize, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt b/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt index d1f4eb8..5e45366 100644 --- a/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt +++ b/app/src/main/java/com/aiosman/riderpro/data/api/RiderProAPI.kt @@ -85,6 +85,7 @@ data class RegisterMessageChannelRequestBody( @SerializedName("identifier") val identifier: String, ) + interface RiderProAPI { @POST("register") suspend fun register(@Body body: RegisterRequestBody): Response @@ -243,6 +244,8 @@ interface RiderProAPI { @Query("page") page: Int = 1, @Query("pageSize") pageSize: Int = 20, @Query("nickname") search: String? = null, + @Query("followerId") followerId: Int? = null, + @Query("followingId") followingId: Int? = null, ): Response> @POST("register/google") diff --git a/app/src/main/java/com/aiosman/riderpro/entity/User.kt b/app/src/main/java/com/aiosman/riderpro/entity/User.kt index e7859e7..e344f6c 100644 --- a/app/src/main/java/com/aiosman/riderpro/entity/User.kt +++ b/app/src/main/java/com/aiosman/riderpro/entity/User.kt @@ -10,14 +10,18 @@ import java.io.IOException */ class AccountPagingSource( private val userService: UserService, - private val nickname: String? = null + private val nickname: String? = null, + private val followerId: Int? = null, + private val followingId: Int? = null ) : PagingSource() { override suspend fun load(params: LoadParams): LoadResult { return try { val currentPage = params.key ?: 1 val users = userService.getUsers( page = currentPage, - nickname = nickname + nickname = nickname, + followerId = followerId, + followingId = followingId ) LoadResult.Page( data = users.list, diff --git a/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt b/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt index 9ba68a7..d810085 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/Navi.kt @@ -27,11 +27,12 @@ import androidx.navigation.navArgument import com.aiosman.riderpro.LocalAnimatedContentScope import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.LocalSharedTransitionScope -import com.aiosman.riderpro.ui.account.AccountEditScreen import com.aiosman.riderpro.ui.account.AccountEditScreen2 import com.aiosman.riderpro.ui.comment.CommentsScreen import com.aiosman.riderpro.ui.favourite.FavouriteScreen -import com.aiosman.riderpro.ui.follower.FollowerScreen +import com.aiosman.riderpro.ui.follower.FollowerListScreen +import com.aiosman.riderpro.ui.follower.FollowerNotificationScreen +import com.aiosman.riderpro.ui.follower.FollowingListScreen import com.aiosman.riderpro.ui.gallery.OfficialGalleryScreen import com.aiosman.riderpro.ui.gallery.OfficialPhotographerScreen import com.aiosman.riderpro.ui.gallery.ProfileTimelineScreen @@ -77,6 +78,8 @@ sealed class NavigationRoute( data object FavouritesScreen : NavigationRoute("FavouritesScreen") data object NewPostImageGrid : NavigationRoute("NewPostImageGrid") data object Search : NavigationRoute("Search") + data object FollowerList : NavigationRoute("FollowerList/{id}") + data object FollowingList : NavigationRoute("FollowingList/{id}") } @@ -158,7 +161,7 @@ fun NavigationController( LikeScreen() } composable(route = NavigationRoute.Followers.route) { - FollowerScreen() + FollowerNotificationScreen() } composable( route = NavigationRoute.NewPost.route, @@ -228,6 +231,27 @@ fun NavigationController( SearchScreen() } } + composable( + route = NavigationRoute.FollowerList.route, + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { + CompositionLocalProvider( + LocalAnimatedContentScope provides this, + ) { + FollowerListScreen(it.arguments?.getInt("id")!!) + } + } + composable( + route = NavigationRoute.FollowingList.route, + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { + CompositionLocalProvider( + LocalAnimatedContentScope provides this, + ) { + FollowingListScreen(it.arguments?.getInt("id")!!) + } + } + } diff --git a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerList.kt b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerList.kt new file mode 100644 index 0000000..7efa5c1 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerList.kt @@ -0,0 +1,57 @@ +package com.aiosman.riderpro.ui.follower + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +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.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.paging.compose.collectAsLazyPagingItems +import com.aiosman.riderpro.R +import com.aiosman.riderpro.ui.comment.NoticeScreenHeader +import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout +import kotlinx.coroutines.launch + +@Composable +fun FollowerListScreen(userId: Int) { + val model = FollowerListViewModel + val scope = rememberCoroutineScope() + LaunchedEffect(Unit) { + model.loadData(userId) + } + StatusBarMaskLayout( + modifier = Modifier.padding(horizontal = 16.dp) + ) { + var dataFlow = model.usersFlow + var users = dataFlow.collectAsLazyPagingItems() + Box( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + NoticeScreenHeader(stringResource(R.string.followers_upper), moreIcon = false) + } + LazyColumn( + modifier = Modifier.weight(1f) + ) { + items(users.itemCount) { index -> + users[index]?.let { user -> + FollowItem( + avatar = user.avatar, + nickname = user.nickName, + userId = user.id, + isFollowing = user.isFollowing + ) { + scope.launch { + model.followUser(user.id) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerListViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerListViewModel.kt new file mode 100644 index 0000000..46f9a0a --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerListViewModel.kt @@ -0,0 +1,63 @@ +package com.aiosman.riderpro.ui.follower + +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 androidx.paging.map +import com.aiosman.riderpro.data.UserServiceImpl +import com.aiosman.riderpro.entity.AccountPagingSource +import com.aiosman.riderpro.entity.AccountProfileEntity +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +object FollowerListViewModel : ViewModel() { + private val userService = UserServiceImpl() + private val _usersFlow = MutableStateFlow>(PagingData.empty()) + val usersFlow = _usersFlow.asStateFlow() + private var userId by mutableStateOf(null) + fun loadData(id: Int) { + if (userId == id) { + return + } + userId = id + viewModelScope.launch { + Pager( + config = PagingConfig(pageSize = 5, enablePlaceholders = false), + pagingSourceFactory = { + AccountPagingSource( + userService, + followerId = id + ) + } + ).flow.cachedIn(viewModelScope).collectLatest { + _usersFlow.value = it + } + } + } + + private fun updateIsFollow(id: Int) { + val currentPagingData = usersFlow.value + val updatedPagingData = currentPagingData.map { user -> + if (user.id == id) { + user.copy(isFollowing = true) + } else { + user + } + } + _usersFlow.value = updatedPagingData + } + + suspend fun followUser(userId: Int) { + userService.followUser(userId.toString()) + updateIsFollow(userId) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerNoticeViewModel.kt similarity index 98% rename from app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerViewModel.kt rename to app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerNoticeViewModel.kt index af2c506..ef252e9 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerViewModel.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerNoticeViewModel.kt @@ -24,7 +24,7 @@ import kotlinx.coroutines.launch /** * 关注消息列表的 ViewModel */ -object FollowerViewModel : ViewModel() { +object FollowerNoticeViewModel : ViewModel() { private val accountService: AccountService = AccountServiceImpl() private val userService: UserService = UserServiceImpl() private val _followerItemsFlow = diff --git a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerPage.kt b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerPage.kt index f9b4a3c..f226af5 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerPage.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowerPage.kt @@ -22,13 +22,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.paging.compose.collectAsLazyPagingItems import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.R -import com.aiosman.riderpro.data.AccountFollow import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout import com.aiosman.riderpro.ui.comment.NoticeScreenHeader @@ -40,19 +38,18 @@ import kotlinx.coroutines.launch * 关注消息列表 */ @Composable -fun FollowerScreen() { +fun FollowerNotificationScreen() { val scope = rememberCoroutineScope() StatusBarMaskLayout( modifier = Modifier.padding(horizontal = 16.dp) ) { - val model = FollowerViewModel + val model = FollowerNoticeViewModel var dataFlow = model.followerItemsFlow var followers = dataFlow.collectAsLazyPagingItems() Box( modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp) ) { NoticeScreenHeader(stringResource(R.string.followers_upper), moreIcon = false) - } LaunchedEffect(Unit) { model.updateNotice() @@ -62,7 +59,12 @@ fun FollowerScreen() { ) { items(followers.itemCount) { index -> followers[index]?.let { follower -> - FollowerItem(follower) { + FollowItem( + avatar = follower.avatar, + nickname = follower.nickname, + userId = follower.userId, + isFollowing = follower.isFollowing + ) { scope.launch { model.followUser(follower.userId) } @@ -75,8 +77,11 @@ fun FollowerScreen() { @Composable -fun FollowerItem( - item: AccountFollow, +fun FollowItem( + avatar: String, + nickname: String, + userId: Int, + isFollowing: Boolean, onFollow: () -> Unit = {} ) { val context = LocalContext.current @@ -90,15 +95,15 @@ fun FollowerItem( ) { CustomAsyncImage( context = context, - imageUrl = item.avatar, - contentDescription = item.nickname, + imageUrl = avatar, + contentDescription = nickname, modifier = Modifier .size(40.dp) .noRippleClickable { navController.navigate( NavigationRoute.AccountProfile.route.replace( "{id}", - item.userId.toString() + userId.toString() ) ) } @@ -107,9 +112,9 @@ fun FollowerItem( Column( modifier = Modifier.weight(1f) ) { - Text(item.nickname, fontWeight = FontWeight.Bold, fontSize = 16.sp) + Text(nickname, fontWeight = FontWeight.Bold, fontSize = 16.sp) } - if (!item.isFollowing) { + if (!isFollowing) { Box( modifier = Modifier.noRippleClickable { onFollow() diff --git a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingList.kt b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingList.kt new file mode 100644 index 0000000..e5ce050 --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingList.kt @@ -0,0 +1,57 @@ +package com.aiosman.riderpro.ui.follower + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +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.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.paging.compose.collectAsLazyPagingItems +import com.aiosman.riderpro.R +import com.aiosman.riderpro.ui.comment.NoticeScreenHeader +import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout +import kotlinx.coroutines.launch + +@Composable +fun FollowingListScreen(userId: Int) { + val model = FollowerListViewModel + val scope = rememberCoroutineScope() + LaunchedEffect(Unit) { + model.loadData(userId) + } + StatusBarMaskLayout( + modifier = Modifier.padding(horizontal = 16.dp) + ) { + var dataFlow = model.usersFlow + var users = dataFlow.collectAsLazyPagingItems() + Box( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + NoticeScreenHeader(stringResource(R.string.following_upper), moreIcon = false) + } + LazyColumn( + modifier = Modifier.weight(1f) + ) { + items(users.itemCount) { index -> + users[index]?.let { user -> + FollowItem( + avatar = user.avatar, + nickname = user.nickName, + userId = user.id, + isFollowing = user.isFollowing + ) { + scope.launch { + model.followUser(user.id) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingListViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingListViewModel.kt new file mode 100644 index 0000000..6cc2f8e --- /dev/null +++ b/app/src/main/java/com/aiosman/riderpro/ui/follower/FollowingListViewModel.kt @@ -0,0 +1,63 @@ +package com.aiosman.riderpro.ui.follower + +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 androidx.paging.map +import com.aiosman.riderpro.data.UserServiceImpl +import com.aiosman.riderpro.entity.AccountPagingSource +import com.aiosman.riderpro.entity.AccountProfileEntity +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +object FollowingListViewModel : ViewModel() { + private val userService = UserServiceImpl() + private val _usersFlow = MutableStateFlow>(PagingData.empty()) + val usersFlow = _usersFlow.asStateFlow() + private var userId by mutableStateOf(null) + fun loadData(id: Int) { + if (userId == id) { + return + } + userId = id + viewModelScope.launch { + Pager( + config = PagingConfig(pageSize = 5, enablePlaceholders = false), + pagingSourceFactory = { + AccountPagingSource( + userService, + followerId = id + ) + } + ).flow.cachedIn(viewModelScope).collectLatest { + _usersFlow.value = it + } + } + } + + private fun updateIsFollow(id: Int) { + val currentPagingData = usersFlow.value + val updatedPagingData = currentPagingData.map { user -> + if (user.id == id) { + user.copy(isFollowing = true) + } else { + user + } + } + _usersFlow.value = updatedPagingData + } + + suspend fun followUser(userId: Int) { + userService.followUser(userId.toString()) + updateIsFollow(userId) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/MyProfileViewModel.kt b/app/src/main/java/com/aiosman/riderpro/ui/index/tabs/profile/MyProfileViewModel.kt index 0143ea9..288886b 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 @@ -1,5 +1,8 @@ package com.aiosman.riderpro.ui.index.tabs.profile +import android.content.Context +import android.net.Uri +import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -13,12 +16,14 @@ import com.aiosman.riderpro.AppStore import com.aiosman.riderpro.data.AccountService import com.aiosman.riderpro.data.AccountServiceImpl import com.aiosman.riderpro.data.MomentService +import com.aiosman.riderpro.data.UploadImage 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.ui.post.NewPostViewModel.uriToFile import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest @@ -31,7 +36,7 @@ object MyProfileViewModel : ViewModel() { var profile by mutableStateOf(null) private var _momentsFlow = MutableStateFlow>(PagingData.empty()) var momentsFlow = _momentsFlow.asStateFlow() - fun loadProfile(){ + fun loadProfile() { viewModelScope.launch { profile = accountService.getMyAccountProfile() val profile = accountService.getMyAccountProfile() @@ -59,6 +64,34 @@ object MyProfileViewModel : ViewModel() { } + fun updateUserProfileBanner(bannerImageUrl: Uri?, context: Context) { + viewModelScope.launch { + var newBanner = bannerImageUrl?.let { + val cursor = context.contentResolver.query(it, null, null, null, null) + var newBanner: UploadImage? = null + cursor?.use { cur -> + if (cur.moveToFirst()) { + val displayName = cur.getString(cur.getColumnIndex("_display_name")) + val extension = displayName.substringAfterLast(".") + Log.d("NewPost", "File name: $displayName, extension: $extension") + // read as file + val file = uriToFile(context, it) + Log.d("NewPost", "File size: ${file.length()}") + newBanner = UploadImage(file, displayName, it.toString(), extension) + } + } + newBanner + } + accountService.updateProfile( + banner = newBanner, + avatar = null, + nickName = null, + bio = null + ) + profile = accountService.getMyAccountProfile() + } + } + val followerCount get() = profile?.followerCount ?: 0 val followingCount get() = profile?.followingCount ?: 0 val bio get() = profile?.bio ?: "" 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 cff2269..a65f28f 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,6 +1,10 @@ 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 @@ -92,7 +96,18 @@ fun ProfilePage() { val moments = model.momentsFlow.collectAsLazyPagingItems() val navController: NavController = LocalNavController.current val scope = rememberCoroutineScope() + val context = LocalContext.current val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues() + val pickBannerImageLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val uri = result.data?.data + uri?.let { + model.updateUserProfileBanner(it, context = context) + } + } + } LazyColumn( modifier = Modifier .fillMaxSize() @@ -110,28 +125,40 @@ fun ProfilePage() { .fillMaxWidth() ) { - val banner = model.profile?.banner - if (banner != null) { - CustomAsyncImage( - LocalContext.current, - banner, - modifier = Modifier - .fillMaxWidth() - .height(400.dp), - contentDescription = "", - contentScale = ContentScale.Crop - ) - } else { - Image( - painter = painterResource(id = R.drawable.rider_pro_moment_demo_2), - modifier = Modifier - .fillMaxWidth() - .height(400.dp), - contentDescription = "", - contentScale = ContentScale.Crop - ) + 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) @@ -313,9 +340,19 @@ fun UserInformation( @Composable fun UserInformationFollowers(modifier: Modifier, accountProfileEntity: AccountProfileEntity) { + val navController = LocalNavController.current Column(modifier = modifier.padding(top = 31.dp)) { Text( - modifier = Modifier.padding(bottom = 5.dp), + modifier = Modifier + .padding(bottom = 5.dp) + .noRippleClickable { + navController.navigate( + NavigationRoute.FollowerList.route.replace( + "{id}", + accountProfileEntity.id.toString() + ) + ) + }, text = accountProfileEntity.followerCount.toString(), fontSize = 24.sp, color = Color.Black, @@ -391,12 +428,20 @@ fun UserInformationBasic(modifier: Modifier, accountProfileEntity: AccountProfil @Composable fun UserInformationFollowing(modifier: Modifier, accountProfileEntity: AccountProfileEntity) { + val navController = LocalNavController.current Column( modifier = modifier.padding(top = 6.dp), horizontalAlignment = Alignment.End ) { Text( - modifier = Modifier.padding(bottom = 5.dp), + modifier = Modifier.padding(bottom = 5.dp).noRippleClickable { + navController.navigate( + NavigationRoute.FollowingList.route.replace( + "{id}", + accountProfileEntity.id.toString() + ) + ) + }, text = accountProfileEntity.followingCount.toString(), fontSize = 24.sp, color = Color.Black,