更新
@@ -31,6 +31,8 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
|
import com.aiosman.riderpro.data.AccountService
|
||||||
|
import com.aiosman.riderpro.data.TestAccountServiceImpl
|
||||||
import com.aiosman.riderpro.data.TestUserServiceImpl
|
import com.aiosman.riderpro.data.TestUserServiceImpl
|
||||||
import com.aiosman.riderpro.data.UserService
|
import com.aiosman.riderpro.data.UserService
|
||||||
import com.aiosman.riderpro.ui.Navigation
|
import com.aiosman.riderpro.ui.Navigation
|
||||||
@@ -49,8 +51,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
if (!AppStore.rememberMe) {
|
if (!AppStore.rememberMe) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val userService: UserService = TestUserServiceImpl()
|
val accountService: AccountService = TestAccountServiceImpl()
|
||||||
userService.getMyAccount()
|
accountService.getMyAccount()
|
||||||
}
|
}
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|||||||
@@ -15,14 +15,50 @@ data class AccountProfile(
|
|||||||
interface AccountService {
|
interface AccountService {
|
||||||
suspend fun getMyAccountProfile(): AccountProfile
|
suspend fun getMyAccountProfile(): AccountProfile
|
||||||
suspend fun getAccountProfileById(id: Int): AccountProfile
|
suspend fun getAccountProfileById(id: Int): AccountProfile
|
||||||
|
suspend fun getMyAccount(): UserAuth
|
||||||
|
suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth
|
||||||
|
suspend fun logout()
|
||||||
|
suspend fun updateAvatar(uri: String)
|
||||||
|
suspend fun updateProfile(nickName: String, bio: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestAccountServiceImpl : AccountService {
|
class TestAccountServiceImpl : AccountService {
|
||||||
override suspend fun getMyAccountProfile(): AccountProfile {
|
override suspend fun getMyAccountProfile(): AccountProfile {
|
||||||
return TestDatabase.accountData.first { it.id == 0 }
|
return TestDatabase.accountData.first { it.id == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getAccountProfileById(id: Int): AccountProfile {
|
override suspend fun getAccountProfileById(id: Int): AccountProfile {
|
||||||
return TestDatabase.accountData.first { it.id == id }
|
return TestDatabase.accountData.first { it.id == id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getMyAccount(): UserAuth {
|
||||||
|
return UserAuth(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth {
|
||||||
|
return UserAuth(1, "token")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun logout() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateAvatar(uri: String) {
|
||||||
|
TestDatabase.accountData = TestDatabase.accountData.map {
|
||||||
|
if (it.id == 1) {
|
||||||
|
it.copy(avatar = uri)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override suspend fun updateProfile(nickName: String, bio: String) {
|
||||||
|
TestDatabase.accountData = TestDatabase.accountData.map {
|
||||||
|
if (it.id == 1) {
|
||||||
|
it.copy(nickName = nickName, bio = bio)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,8 @@ interface MomentService {
|
|||||||
suspend fun createMoment(
|
suspend fun createMoment(
|
||||||
content: String,
|
content: String,
|
||||||
authorId: Int,
|
authorId: Int,
|
||||||
imageUriList: List<String>
|
imageUriList: List<String>,
|
||||||
|
relPostId: Int? = null
|
||||||
): MomentItem
|
): MomentItem
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +97,10 @@ class TestMomentServiceImpl() : MomentService {
|
|||||||
override suspend fun createMoment(
|
override suspend fun createMoment(
|
||||||
content: String,
|
content: String,
|
||||||
authorId: Int,
|
authorId: Int,
|
||||||
imageUriList: List<String>
|
imageUriList: List<String>,
|
||||||
|
relPostId: Int?
|
||||||
): MomentItem {
|
): MomentItem {
|
||||||
return testMomentBackend.createMoment(content, authorId, imageUriList)
|
return testMomentBackend.createMoment(content, authorId, imageUriList, relPostId)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -140,6 +142,9 @@ class TestMomentBackend(
|
|||||||
if (myLikeIdList.contains(it.id)) {
|
if (myLikeIdList.contains(it.id)) {
|
||||||
it.liked = true
|
it.liked = true
|
||||||
}
|
}
|
||||||
|
if (it.relPostId != null) {
|
||||||
|
it.relMoment = rawList.first { it1 -> it1.id == it.relPostId }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delay
|
// delay
|
||||||
@@ -186,7 +191,8 @@ class TestMomentBackend(
|
|||||||
suspend fun createMoment(
|
suspend fun createMoment(
|
||||||
content: String,
|
content: String,
|
||||||
authorId: Int,
|
authorId: Int,
|
||||||
imageUriList: List<String>
|
imageUriList: List<String>,
|
||||||
|
relPostId: Int?
|
||||||
): MomentItem {
|
): MomentItem {
|
||||||
TestDatabase.momentIdCounter += 1
|
TestDatabase.momentIdCounter += 1
|
||||||
val person = TestDatabase.accountData.first {
|
val person = TestDatabase.accountData.first {
|
||||||
@@ -206,7 +212,8 @@ class TestMomentBackend(
|
|||||||
shareCount = 0,
|
shareCount = 0,
|
||||||
favoriteCount = 0,
|
favoriteCount = 0,
|
||||||
images = imageUriList,
|
images = imageUriList,
|
||||||
authorId = person.id
|
authorId = person.id,
|
||||||
|
relPostId = relPostId
|
||||||
)
|
)
|
||||||
TestDatabase.momentData += newMoment
|
TestDatabase.momentData += newMoment
|
||||||
return newMoment
|
return newMoment
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ data class UserAuth(
|
|||||||
|
|
||||||
interface UserService {
|
interface UserService {
|
||||||
suspend fun getUserProfile(id: String): AccountProfile
|
suspend fun getUserProfile(id: String): AccountProfile
|
||||||
suspend fun getMyAccount(): UserAuth
|
|
||||||
suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth
|
|
||||||
suspend fun logout()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestUserServiceImpl : UserService {
|
class TestUserServiceImpl : UserService {
|
||||||
@@ -23,17 +21,4 @@ class TestUserServiceImpl : UserService {
|
|||||||
}
|
}
|
||||||
return AccountProfile(0, 0, 0, "", "", "", "")
|
return AccountProfile(0, 0, 0, "", "", "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMyAccount(): UserAuth {
|
|
||||||
return UserAuth(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun loginUserWithPassword(loginName: String, password: String): UserAuth {
|
|
||||||
return UserAuth(1, "token")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun logout() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,4 +19,6 @@ data class MomentItem(
|
|||||||
val images: List<String> = emptyList(),
|
val images: List<String> = emptyList(),
|
||||||
val authorId: Int = 0,
|
val authorId: Int = 0,
|
||||||
var liked: Boolean = false,
|
var liked: Boolean = false,
|
||||||
|
var relPostId: Int? = null,
|
||||||
|
var relMoment: MomentItem? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import androidx.navigation.navArgument
|
|||||||
import com.aiosman.riderpro.LocalAnimatedContentScope
|
import com.aiosman.riderpro.LocalAnimatedContentScope
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.LocalSharedTransitionScope
|
import com.aiosman.riderpro.LocalSharedTransitionScope
|
||||||
|
import com.aiosman.riderpro.ui.account.AccountEditScreen
|
||||||
import com.aiosman.riderpro.ui.comment.CommentsScreen
|
import com.aiosman.riderpro.ui.comment.CommentsScreen
|
||||||
import com.aiosman.riderpro.ui.follower.FollowerScreen
|
import com.aiosman.riderpro.ui.follower.FollowerScreen
|
||||||
import com.aiosman.riderpro.ui.gallery.OfficialGalleryScreen
|
import com.aiosman.riderpro.ui.gallery.OfficialGalleryScreen
|
||||||
@@ -60,11 +61,15 @@ sealed class NavigationRoute(
|
|||||||
data object SignUp : NavigationRoute("SignUp")
|
data object SignUp : NavigationRoute("SignUp")
|
||||||
data object UserAuth : NavigationRoute("UserAuth")
|
data object UserAuth : NavigationRoute("UserAuth")
|
||||||
data object EmailSignUp : NavigationRoute("EmailSignUp")
|
data object EmailSignUp : NavigationRoute("EmailSignUp")
|
||||||
|
data object AccountEdit : NavigationRoute("AccountEditScreen")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NavigationController(navController: NavHostController,startDestination: String = NavigationRoute.Login.route) {
|
fun NavigationController(
|
||||||
|
navController: NavHostController,
|
||||||
|
startDestination: String = NavigationRoute.Login.route
|
||||||
|
) {
|
||||||
val navigationBarHeight = with(LocalDensity.current) {
|
val navigationBarHeight = with(LocalDensity.current) {
|
||||||
WindowInsets.navigationBars.getBottom(this).toDp()
|
WindowInsets.navigationBars.getBottom(this).toDp()
|
||||||
}
|
}
|
||||||
@@ -163,6 +168,9 @@ fun NavigationController(navController: NavHostController,startDestination: Stri
|
|||||||
composable(route = NavigationRoute.EmailSignUp.route) {
|
composable(route = NavigationRoute.EmailSignUp.route) {
|
||||||
EmailSignupScreen()
|
EmailSignupScreen()
|
||||||
}
|
}
|
||||||
|
composable(route = NavigationRoute.AccountEdit.route) {
|
||||||
|
AccountEditScreen()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -178,7 +186,10 @@ fun Navigation(startDestination: String = NavigationRoute.Login.route) {
|
|||||||
LocalSharedTransitionScope provides this@SharedTransitionLayout,
|
LocalSharedTransitionScope provides this@SharedTransitionLayout,
|
||||||
) {
|
) {
|
||||||
Box {
|
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
@@ -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.comment.CommentModalContent
|
||||||
import com.aiosman.riderpro.ui.composables.AnimatedCounter
|
import com.aiosman.riderpro.ui.composables.AnimatedCounter
|
||||||
import com.aiosman.riderpro.ui.composables.AnimatedLikeIcon
|
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.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -68,7 +70,6 @@ import kotlinx.coroutines.launch
|
|||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MomentsList() {
|
fun MomentsList() {
|
||||||
|
|
||||||
val model = MomentViewModel
|
val model = MomentViewModel
|
||||||
var dataFlow = model.momentsFlow
|
var dataFlow = model.momentsFlow
|
||||||
var moments = dataFlow.collectAsLazyPagingItems()
|
var moments = dataFlow.collectAsLazyPagingItems()
|
||||||
@@ -110,7 +111,6 @@ fun MomentsList() {
|
|||||||
}
|
}
|
||||||
PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter))
|
PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -141,7 +141,12 @@ fun MomentCard(
|
|||||||
momentOperateBtnBoxModifier,
|
momentOperateBtnBoxModifier,
|
||||||
momentItem = momentItem,
|
momentItem = momentItem,
|
||||||
onLikeClick = onLikeClick,
|
onLikeClick = onLikeClick,
|
||||||
onAddComment = onAddComment
|
onAddComment = onAddComment,
|
||||||
|
onShareClick = {
|
||||||
|
NewPostViewModel.asNewPost()
|
||||||
|
NewPostViewModel.relPostId = momentItem.id
|
||||||
|
navController.navigate(NavigationRoute.NewPost.route)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,6 +310,9 @@ fun MomentContentGroup(
|
|||||||
.padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp),
|
.padding(top = 22.dp, bottom = 16.dp, start = 24.dp, end = 24.dp),
|
||||||
fontSize = 16.sp
|
fontSize = 16.sp
|
||||||
)
|
)
|
||||||
|
if (momentItem.relMoment != null) {
|
||||||
|
RelPostCard(momentItem = momentItem.relMoment!!, modifier = Modifier.background(Color(0xFFF8F8F8)))
|
||||||
|
}else{
|
||||||
displayImageUrl?.let {
|
displayImageUrl?.let {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
it,
|
it,
|
||||||
@@ -315,6 +323,7 @@ fun MomentContentGroup(
|
|||||||
contentDescription = ""
|
contentDescription = ""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,6 +366,7 @@ fun MomentBottomOperateRowGroup(
|
|||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
onLikeClick: () -> Unit = {},
|
onLikeClick: () -> Unit = {},
|
||||||
onAddComment: () -> Unit = {},
|
onAddComment: () -> Unit = {},
|
||||||
|
onShareClick: () -> Unit = {},
|
||||||
momentItem: MomentItem
|
momentItem: MomentItem
|
||||||
) {
|
) {
|
||||||
var systemUiController = rememberSystemUiController()
|
var systemUiController = rememberSystemUiController()
|
||||||
@@ -411,7 +421,9 @@ fun MomentBottomOperateRowGroup(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier.noRippleClickable {
|
||||||
|
onShareClick()
|
||||||
|
},
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
MomentOperateBtn(
|
MomentOperateBtn(
|
||||||
|
|||||||
@@ -106,6 +106,13 @@ fun ProfilePage() {
|
|||||||
}, text = {
|
}, text = {
|
||||||
Text("Logout")
|
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.AppStore
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.R
|
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.TestUserServiceImpl
|
||||||
import com.aiosman.riderpro.data.UserService
|
import com.aiosman.riderpro.data.UserService
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
@@ -52,12 +54,12 @@ fun UserAuthScreen() {
|
|||||||
var email by remember { mutableStateOf("") }
|
var email by remember { mutableStateOf("") }
|
||||||
var password by remember { mutableStateOf("") }
|
var password by remember { mutableStateOf("") }
|
||||||
var rememberMe by remember { mutableStateOf(false) }
|
var rememberMe by remember { mutableStateOf(false) }
|
||||||
var userService: UserService = TestUserServiceImpl()
|
var accountService: AccountService = TestAccountServiceImpl()
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
fun onLogin() {
|
fun onLogin() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
val authResp = userService.loginUserWithPassword(email, password)
|
val authResp = accountService.loginUserWithPassword(email, password)
|
||||||
if (authResp.token != null) {
|
if (authResp.token != null) {
|
||||||
AppStore.apply {
|
AppStore.apply {
|
||||||
token = authResp.token
|
token = authResp.token
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.heightIn
|
|||||||
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.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
@@ -34,6 +35,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.PathEffect
|
import androidx.compose.ui.graphics.PathEffect
|
||||||
@@ -48,6 +50,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
|
import com.aiosman.riderpro.ui.composables.RelPostCard
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
@@ -62,6 +65,7 @@ fun NewPostScreen() {
|
|||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
systemUiController.setNavigationBarColor(color = Color.Transparent)
|
systemUiController.setNavigationBarColor(color = Color.Transparent)
|
||||||
|
model.init()
|
||||||
}
|
}
|
||||||
StatusBarMaskLayout(
|
StatusBarMaskLayout(
|
||||||
darkIcons = true,
|
darkIcons = true,
|
||||||
@@ -79,6 +83,23 @@ fun NewPostScreen() {
|
|||||||
NewPostTextField("Share your adventure…", NewPostViewModel.textContent) {
|
NewPostTextField("Share your adventure…", NewPostViewModel.textContent) {
|
||||||
NewPostViewModel.textContent = it
|
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()
|
AddImageGrid()
|
||||||
AdditionalPostItem()
|
AdditionalPostItem()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.aiosman.riderpro.data.MomentService
|
import com.aiosman.riderpro.data.MomentService
|
||||||
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
import com.aiosman.riderpro.data.TestMomentServiceImpl
|
||||||
|
import com.aiosman.riderpro.model.MomentItem
|
||||||
import com.aiosman.riderpro.ui.modification.Modification
|
import com.aiosman.riderpro.ui.modification.Modification
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -18,17 +19,29 @@ object NewPostViewModel : ViewModel() {
|
|||||||
var searchPlaceAddressResult by mutableStateOf<SearchPlaceAddressResult?>(null)
|
var searchPlaceAddressResult by mutableStateOf<SearchPlaceAddressResult?>(null)
|
||||||
var modificationList by mutableStateOf<List<Modification>>(listOf())
|
var modificationList by mutableStateOf<List<Modification>>(listOf())
|
||||||
var imageUriList by mutableStateOf(listOf<String>())
|
var imageUriList by mutableStateOf(listOf<String>())
|
||||||
|
var relPostId by mutableStateOf<Int?>(null)
|
||||||
|
var relMoment by mutableStateOf<MomentItem?>(null)
|
||||||
fun asNewPost() {
|
fun asNewPost() {
|
||||||
textContent = ""
|
textContent = ""
|
||||||
searchPlaceAddressResult = null
|
searchPlaceAddressResult = null
|
||||||
modificationList = listOf()
|
modificationList = listOf()
|
||||||
|
imageUriList = listOf()
|
||||||
|
relPostId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun createMoment() {
|
suspend fun createMoment() {
|
||||||
momentService.createMoment(
|
momentService.createMoment(
|
||||||
content = textContent,
|
content = textContent,
|
||||||
authorId = 1,
|
authorId = 1,
|
||||||
imageUriList = imageUriList
|
imageUriList = imageUriList,
|
||||||
|
relPostId = relPostId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun init(){
|
||||||
|
relPostId?.let {
|
||||||
|
val moment = momentService.getMomentById(it)
|
||||||
|
relMoment = moment
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BIN
app/src/main/res/mipmap-hdpi/rider_pro_blue_bg_big.webp
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_email.webp
Normal file
|
After Width: | Height: | Size: 916 B |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_grey_bg_big.webp
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_logo.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_red_bg_big.webp
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_signup_facebook.webp
Normal file
|
After Width: | Height: | Size: 984 B |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_signup_facebook_bg.webp
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_signup_google.webp
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_signup_red_bg.webp
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_signup_white_bg.webp
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_blue_bg_big.webp
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_email.webp
Normal file
|
After Width: | Height: | Size: 680 B |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_grey_bg_big.webp
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_logo.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_red_bg_big.webp
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_signup_facebook.webp
Normal file
|
After Width: | Height: | Size: 702 B |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_signup_facebook_bg.webp
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_signup_google.webp
Normal file
|
After Width: | Height: | Size: 956 B |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_signup_red_bg.webp
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_signup_white_bg.webp
Normal file
|
After Width: | Height: | Size: 872 B |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_blue_bg_big.webp
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_email.webp
Normal file
|
After Width: | Height: | Size: 1008 B |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_grey_bg_big.webp
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_logo.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_red_bg_big.webp
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_signup_facebook.webp
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_signup_facebook_bg.webp
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_signup_google.webp
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_signup_red_bg.webp
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_signup_white_bg.webp
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_blue_bg_big.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_email.webp
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_grey_bg_big.webp
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_logo.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_red_bg_big.webp
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_signup_facebook.webp
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_signup_facebook_bg.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_signup_google.webp
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_signup_red_bg.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_signup_white_bg.webp
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_blue_bg_big.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_email.webp
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_grey_bg_big.webp
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_logo.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_red_bg_big.webp
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_signup_facebook.webp
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_signup_google.webp
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_signup_red_bg.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_signup_white_bg.webp
Normal file
|
After Width: | Height: | Size: 1.8 KiB |