更新
This commit is contained in:
@@ -21,6 +21,7 @@ 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.comment.CommentsScreen
|
||||
import com.aiosman.riderpro.ui.follower.FollowerScreen
|
||||
import com.aiosman.riderpro.ui.gallery.OfficialGalleryScreen
|
||||
@@ -60,11 +61,15 @@ sealed class NavigationRoute(
|
||||
data object SignUp : NavigationRoute("SignUp")
|
||||
data object UserAuth : NavigationRoute("UserAuth")
|
||||
data object EmailSignUp : NavigationRoute("EmailSignUp")
|
||||
data object AccountEdit : NavigationRoute("AccountEditScreen")
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun NavigationController(navController: NavHostController,startDestination: String = NavigationRoute.Login.route) {
|
||||
fun NavigationController(
|
||||
navController: NavHostController,
|
||||
startDestination: String = NavigationRoute.Login.route
|
||||
) {
|
||||
val navigationBarHeight = with(LocalDensity.current) {
|
||||
WindowInsets.navigationBars.getBottom(this).toDp()
|
||||
}
|
||||
@@ -163,6 +168,9 @@ fun NavigationController(navController: NavHostController,startDestination: Stri
|
||||
composable(route = NavigationRoute.EmailSignUp.route) {
|
||||
EmailSignupScreen()
|
||||
}
|
||||
composable(route = NavigationRoute.AccountEdit.route) {
|
||||
AccountEditScreen()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,7 +186,10 @@ fun Navigation(startDestination: String = NavigationRoute.Login.route) {
|
||||
LocalSharedTransitionScope provides this@SharedTransitionLayout,
|
||||
) {
|
||||
Box {
|
||||
NavigationController(navController = navController,startDestination = startDestination)
|
||||
NavigationController(
|
||||
navController = navController,
|
||||
startDestination = startDestination
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
166
app/src/main/java/com/aiosman/riderpro/ui/account/edit.kt
Normal file
166
app/src/main/java/com/aiosman/riderpro/ui/account/edit.kt
Normal file
@@ -0,0 +1,166 @@
|
||||
package com.aiosman.riderpro.ui.account
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TopAppBar
|
||||
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.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.aiosman.riderpro.data.AccountProfile
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.TestAccountServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AccountEditScreen() {
|
||||
|
||||
val userService: UserService = TestUserServiceImpl()
|
||||
val accountService: AccountService = TestAccountServiceImpl()
|
||||
var name by remember { mutableStateOf("") }
|
||||
var bio by remember { mutableStateOf("") }
|
||||
var profile by remember {
|
||||
mutableStateOf<AccountProfile?>(
|
||||
null
|
||||
)
|
||||
}
|
||||
val scope = rememberCoroutineScope()
|
||||
suspend fun reloadProfile() {
|
||||
|
||||
accountService.getMyAccountProfile().let {
|
||||
profile = it
|
||||
name = it.nickName
|
||||
bio = it.bio
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun updateUserAvatar(uri: String) {
|
||||
scope.launch {
|
||||
accountService.updateAvatar(uri)
|
||||
reloadProfile()
|
||||
}
|
||||
|
||||
}
|
||||
fun updateUserProfile() {
|
||||
scope.launch {
|
||||
accountService.updateProfile(name, bio)
|
||||
reloadProfile()
|
||||
}
|
||||
}
|
||||
|
||||
val pickImageLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val uri = result.data?.data
|
||||
uri?.let {
|
||||
updateUserAvatar(it.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
reloadProfile()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("Edit") },
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
updateUserProfile()
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Check,
|
||||
contentDescription = "Save"
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
padding ->
|
||||
profile?.let {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding).padding(horizontal = 24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
AsyncImage(
|
||||
it.avatar,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(100.dp)
|
||||
.noRippleClickable {
|
||||
Intent(Intent.ACTION_PICK).apply {
|
||||
type = "image/*"
|
||||
pickImageLauncher.launch(this)
|
||||
}
|
||||
},
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
TextField(
|
||||
value = name,
|
||||
onValueChange = {
|
||||
name = it
|
||||
},
|
||||
label = {
|
||||
Text("Name")
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
TextField(
|
||||
value = bio,
|
||||
onValueChange = {
|
||||
bio = it
|
||||
},
|
||||
label = {
|
||||
Text("Bio")
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.aiosman.riderpro.ui.composables
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.aiosman.riderpro.model.MomentItem
|
||||
import com.aiosman.riderpro.ui.index.tabs.moment.MomentTopRowGroup
|
||||
|
||||
@Composable
|
||||
fun RelPostCard(
|
||||
momentItem: MomentItem,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val image = momentItem.images.firstOrNull()
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
MomentTopRowGroup(momentItem = momentItem)
|
||||
Box(
|
||||
modifier=Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
image?.let {
|
||||
AsyncImage(
|
||||
image,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(100.dp),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,9 @@ 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.composables.RelPostCard
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -68,7 +70,6 @@ import kotlinx.coroutines.launch
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun MomentsList() {
|
||||
|
||||
val model = MomentViewModel
|
||||
var dataFlow = model.momentsFlow
|
||||
var moments = dataFlow.collectAsLazyPagingItems()
|
||||
@@ -110,7 +111,6 @@ fun MomentsList() {
|
||||
}
|
||||
PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -141,7 +141,12 @@ fun MomentCard(
|
||||
momentOperateBtnBoxModifier,
|
||||
momentItem = momentItem,
|
||||
onLikeClick = onLikeClick,
|
||||
onAddComment = onAddComment
|
||||
onAddComment = onAddComment,
|
||||
onShareClick = {
|
||||
NewPostViewModel.asNewPost()
|
||||
NewPostViewModel.relPostId = momentItem.id
|
||||
navController.navigate(NavigationRoute.NewPost.route)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -305,15 +310,19 @@ fun MomentContentGroup(
|
||||
.padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
displayImageUrl?.let {
|
||||
AsyncImage(
|
||||
it,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f),
|
||||
contentScale = ContentScale.Crop,
|
||||
contentDescription = ""
|
||||
)
|
||||
if (momentItem.relMoment != null) {
|
||||
RelPostCard(momentItem = momentItem.relMoment!!, modifier = Modifier.background(Color(0xFFF8F8F8)))
|
||||
}else{
|
||||
displayImageUrl?.let {
|
||||
AsyncImage(
|
||||
it,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f),
|
||||
contentScale = ContentScale.Crop,
|
||||
contentDescription = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -357,6 +366,7 @@ fun MomentBottomOperateRowGroup(
|
||||
modifier: Modifier,
|
||||
onLikeClick: () -> Unit = {},
|
||||
onAddComment: () -> Unit = {},
|
||||
onShareClick: () -> Unit = {},
|
||||
momentItem: MomentItem
|
||||
) {
|
||||
var systemUiController = rememberSystemUiController()
|
||||
@@ -411,7 +421,9 @@ fun MomentBottomOperateRowGroup(
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = modifier,
|
||||
modifier = modifier.noRippleClickable {
|
||||
onShareClick()
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
MomentOperateBtn(
|
||||
|
||||
@@ -106,6 +106,13 @@ fun ProfilePage() {
|
||||
}, text = {
|
||||
Text("Logout")
|
||||
})
|
||||
DropdownMenuItem(onClick = {
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
||||
}
|
||||
}, text = {
|
||||
Text("Edit")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.riderpro.AppStore
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.TestAccountServiceImpl
|
||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
@@ -52,12 +54,12 @@ fun UserAuthScreen() {
|
||||
var email by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var rememberMe by remember { mutableStateOf(false) }
|
||||
var userService: UserService = TestUserServiceImpl()
|
||||
var accountService: AccountService = TestAccountServiceImpl()
|
||||
val scope = rememberCoroutineScope()
|
||||
val navController = LocalNavController.current
|
||||
fun onLogin() {
|
||||
scope.launch {
|
||||
val authResp = userService.loginUserWithPassword(email, password)
|
||||
val authResp = accountService.loginUserWithPassword(email, password)
|
||||
if (authResp.token != null) {
|
||||
AppStore.apply {
|
||||
token = authResp.token
|
||||
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
@@ -34,6 +35,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathEffect
|
||||
@@ -48,6 +50,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import coil.compose.AsyncImage
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.ui.composables.RelPostCard
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
@@ -62,6 +65,7 @@ fun NewPostScreen() {
|
||||
val navController = LocalNavController.current
|
||||
LaunchedEffect(Unit) {
|
||||
systemUiController.setNavigationBarColor(color = Color.Transparent)
|
||||
model.init()
|
||||
}
|
||||
StatusBarMaskLayout(
|
||||
darkIcons = true,
|
||||
@@ -79,6 +83,23 @@ fun NewPostScreen() {
|
||||
NewPostTextField("Share your adventure…", NewPostViewModel.textContent) {
|
||||
NewPostViewModel.textContent = it
|
||||
}
|
||||
Column (
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp)
|
||||
) {
|
||||
model.relMoment?.let {
|
||||
Text("Share with")
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Box(
|
||||
modifier = Modifier.clip(RoundedCornerShape(8.dp)).background(color = Color(0xFFEEEEEE)).padding(24.dp)
|
||||
) {
|
||||
RelPostCard(
|
||||
momentItem = it,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddImageGrid()
|
||||
AdditionalPostItem()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.aiosman.riderpro.data.MomentService
|
||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||
import com.aiosman.riderpro.model.MomentItem
|
||||
import com.aiosman.riderpro.ui.modification.Modification
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -18,17 +19,29 @@ object NewPostViewModel : ViewModel() {
|
||||
var searchPlaceAddressResult by mutableStateOf<SearchPlaceAddressResult?>(null)
|
||||
var modificationList by mutableStateOf<List<Modification>>(listOf())
|
||||
var imageUriList by mutableStateOf(listOf<String>())
|
||||
var relPostId by mutableStateOf<Int?>(null)
|
||||
var relMoment by mutableStateOf<MomentItem?>(null)
|
||||
fun asNewPost() {
|
||||
textContent = ""
|
||||
searchPlaceAddressResult = null
|
||||
modificationList = listOf()
|
||||
imageUriList = listOf()
|
||||
relPostId = null
|
||||
}
|
||||
|
||||
suspend fun createMoment() {
|
||||
momentService.createMoment(
|
||||
content = textContent,
|
||||
authorId = 1,
|
||||
imageUriList = imageUriList
|
||||
imageUriList = imageUriList,
|
||||
relPostId = relPostId
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun init(){
|
||||
relPostId?.let {
|
||||
val moment = momentService.getMomentById(it)
|
||||
relMoment = moment
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user