调整细节
This commit is contained in:
@@ -460,11 +460,17 @@ class AccountServiceImpl : AccountService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun resetPassword(email: String) {
|
override suspend fun resetPassword(email: String) {
|
||||||
ApiClient.api.resetPassword(
|
val resp = ApiClient.api.resetPassword(
|
||||||
ResetPasswordRequestBody(
|
ResetPasswordRequestBody(
|
||||||
username = email
|
username = email
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if (!resp.isSuccessful) {
|
||||||
|
parseErrorResponse(resp.errorBody())?.let {
|
||||||
|
throw it.toServiceException()
|
||||||
|
}
|
||||||
|
throw ServiceException("Failed to reset password")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -49,8 +49,17 @@ fun ResetPasswordScreen() {
|
|||||||
var isSendSuccess by remember { mutableStateOf<Boolean?>(null) }
|
var isSendSuccess by remember { mutableStateOf<Boolean?>(null) }
|
||||||
var isLoading by remember { mutableStateOf(false) }
|
var isLoading by remember { mutableStateOf(false) }
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
|
var usernameError by remember { mutableStateOf<String?>(null) }
|
||||||
|
fun validate(): Boolean {
|
||||||
|
if (username.isEmpty()) {
|
||||||
|
usernameError = context.getString(R.string.text_error_email_required)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
usernameError = null
|
||||||
|
return true
|
||||||
|
}
|
||||||
fun resetPassword() {
|
fun resetPassword() {
|
||||||
|
if (!validate()) return
|
||||||
scope.launch {
|
scope.launch {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
try {
|
try {
|
||||||
@@ -78,7 +87,7 @@ fun ResetPasswordScreen() {
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
NoticeScreenHeader(
|
NoticeScreenHeader(
|
||||||
"RECOVER ACCOUNT",
|
stringResource(R.string.recover_account_upper),
|
||||||
moreIcon = false
|
moreIcon = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -93,7 +102,7 @@ fun ResetPasswordScreen() {
|
|||||||
if (isSendSuccess!!) {
|
if (isSendSuccess!!) {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Text(
|
Text(
|
||||||
text = "Reset password email has been sent to your email address",
|
text = stringResource(R.string.reset_mail_send_success),
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = Color(0xFF333333),
|
color = Color(0xFF333333),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
@@ -103,7 +112,7 @@ fun ResetPasswordScreen() {
|
|||||||
} else {
|
} else {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Text(
|
Text(
|
||||||
text = "Failed to send reset password email",
|
text = stringResource(R.string.reset_mail_send_failed),
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = Color(0xFF333333),
|
color = Color(0xFF333333),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
@@ -138,7 +147,8 @@ fun ResetPasswordScreen() {
|
|||||||
onValueChange = { username = it },
|
onValueChange = { username = it },
|
||||||
label = stringResource(R.string.login_email_label),
|
label = stringResource(R.string.login_email_label),
|
||||||
hint = stringResource(R.string.text_hint_email),
|
hint = stringResource(R.string.text_hint_email),
|
||||||
enabled = !isLoading
|
enabled = !isLoading,
|
||||||
|
error = usernameError
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(72.dp))
|
Spacer(modifier = Modifier.height(72.dp))
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -148,7 +158,7 @@ fun ResetPasswordScreen() {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(345.dp)
|
.width(345.dp)
|
||||||
.height(48.dp),
|
.height(48.dp),
|
||||||
text = "Recover Account",
|
text = stringResource(R.string.recover),
|
||||||
backgroundImage = R.mipmap.rider_pro_signup_red_bg
|
backgroundImage = R.mipmap.rider_pro_signup_red_bg
|
||||||
) {
|
) {
|
||||||
resetPassword()
|
resetPassword()
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.aiosman.riderpro.ui.composables
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.TextUnit
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.aiosman.riderpro.R
|
||||||
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun FollowButton(
|
||||||
|
isFollowing: Boolean,
|
||||||
|
fontSize: TextUnit = 12.sp,
|
||||||
|
imageModifier: Modifier = Modifier,
|
||||||
|
onFollowClick: () -> Unit,
|
||||||
|
){
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentWidth()
|
||||||
|
.padding(start = 6.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
onFollowClick()
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
modifier = imageModifier,
|
||||||
|
painter = painterResource(id = R.drawable.follow_bg),
|
||||||
|
contentDescription = "",
|
||||||
|
contentScale = ContentScale.FillWidth
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = if (isFollowing) stringResource(R.string.following_upper) else stringResource(
|
||||||
|
R.string.follow_upper
|
||||||
|
),
|
||||||
|
fontSize = fontSize,
|
||||||
|
color = Color.White,
|
||||||
|
style = TextStyle(fontWeight = FontWeight.Bold)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
package com.aiosman.riderpro.ui.composables
|
package com.aiosman.riderpro.ui.composables
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -112,16 +116,23 @@ fun TextInputField(
|
|||||||
.height(16.dp),
|
.height(16.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
if (error != null) {
|
AnimatedVisibility(
|
||||||
|
visible = error != null,
|
||||||
|
enter = fadeIn(),
|
||||||
|
exit = fadeOut()
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.mipmap.rider_pro_input_error),
|
painter = painterResource(id = R.mipmap.rider_pro_input_error),
|
||||||
contentDescription = "Error",
|
contentDescription = "Error",
|
||||||
modifier = Modifier.size(8.dp)
|
modifier = Modifier.size(8.dp)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.size(4.dp))
|
Spacer(modifier = Modifier.size(4.dp))
|
||||||
Text(error, color = Color(0xFFE53935), fontSize = 12.sp)
|
AnimatedContent(targetState = error) { targetError ->
|
||||||
|
Text(targetError ?: "", color = Color(0xFFE53935), fontSize = 12.sp)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,7 @@ fun FavouriteNoticeScreen() {
|
|||||||
var dataFlow = model.favouriteItemsFlow
|
var dataFlow = model.favouriteItemsFlow
|
||||||
var favourites = dataFlow.collectAsLazyPagingItems()
|
var favourites = dataFlow.collectAsLazyPagingItems()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
|
model.reload()
|
||||||
model.updateNotice()
|
model.updateNotice()
|
||||||
}
|
}
|
||||||
StatusBarMaskLayout(
|
StatusBarMaskLayout(
|
||||||
|
|||||||
@@ -26,8 +26,13 @@ object FavouriteNoticeViewModel : ViewModel() {
|
|||||||
private val _favouriteItemsFlow =
|
private val _favouriteItemsFlow =
|
||||||
MutableStateFlow<PagingData<AccountFavouriteEntity>>(PagingData.empty())
|
MutableStateFlow<PagingData<AccountFavouriteEntity>>(PagingData.empty())
|
||||||
val favouriteItemsFlow = _favouriteItemsFlow.asStateFlow()
|
val favouriteItemsFlow = _favouriteItemsFlow.asStateFlow()
|
||||||
|
var isFirstLoad = true
|
||||||
|
|
||||||
init {
|
fun reload(force: Boolean = false) {
|
||||||
|
if (!isFirstLoad && !force) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isFirstLoad = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Pager(
|
Pager(
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ fun FollowerListScreen(userId: Int) {
|
|||||||
isFollowing = user.isFollowing
|
isFollowing = user.isFollowing
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
if (user.isFollowing) {
|
||||||
|
model.unFollowUser(user.id)
|
||||||
|
} else {
|
||||||
model.followUser(user.id)
|
model.followUser(user.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,4 +57,5 @@ fun FollowerListScreen(userId: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -43,11 +43,11 @@ object FollowerListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateIsFollow(id: Int) {
|
private fun updateIsFollow(id: Int, isFollow: Boolean = true) {
|
||||||
val currentPagingData = usersFlow.value
|
val currentPagingData = usersFlow.value
|
||||||
val updatedPagingData = currentPagingData.map { user ->
|
val updatedPagingData = currentPagingData.map { user ->
|
||||||
if (user.id == id) {
|
if (user.id == id) {
|
||||||
user.copy(isFollowing = true)
|
user.copy(isFollowing = isFollow)
|
||||||
} else {
|
} else {
|
||||||
user
|
user
|
||||||
}
|
}
|
||||||
@@ -60,4 +60,9 @@ object FollowerListViewModel : ViewModel() {
|
|||||||
updateIsFollow(userId)
|
updateIsFollow(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun unFollowUser(userId: Int) {
|
||||||
|
userService.unFollowUser(userId.toString())
|
||||||
|
updateIsFollow(userId, false)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,14 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import com.aiosman.riderpro.AppState
|
||||||
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.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||||
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||||
|
import com.aiosman.riderpro.ui.composables.FollowButton
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -47,11 +49,14 @@ fun FollowerNoticeScreen() {
|
|||||||
var dataFlow = model.followerItemsFlow
|
var dataFlow = model.followerItemsFlow
|
||||||
var followers = dataFlow.collectAsLazyPagingItems()
|
var followers = dataFlow.collectAsLazyPagingItems()
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp)
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 16.dp)
|
||||||
) {
|
) {
|
||||||
NoticeScreenHeader(stringResource(R.string.followers_upper), moreIcon = false)
|
NoticeScreenHeader(stringResource(R.string.followers_upper), moreIcon = false)
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
|
model.reload()
|
||||||
model.updateNotice()
|
model.updateNotice()
|
||||||
}
|
}
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@@ -114,30 +119,43 @@ fun FollowItem(
|
|||||||
) {
|
) {
|
||||||
Text(nickname, fontWeight = FontWeight.Bold, fontSize = 16.sp)
|
Text(nickname, fontWeight = FontWeight.Bold, fontSize = 16.sp)
|
||||||
}
|
}
|
||||||
if (!isFollowing) {
|
if (userId != AppState.UserId) {
|
||||||
Box(
|
FollowButton(
|
||||||
modifier = Modifier.noRippleClickable {
|
isFollowing = isFollowing,
|
||||||
onFollow()
|
onFollowClick = onFollow,
|
||||||
}
|
fontSize = 14.sp,
|
||||||
) {
|
imageModifier = Modifier
|
||||||
Image(
|
.width(100.dp)
|
||||||
painter = painterResource(id = R.drawable.follow_bg),
|
|
||||||
contentDescription = "Follow",
|
|
||||||
modifier = Modifier
|
|
||||||
.width(79.dp)
|
|
||||||
.height(24.dp)
|
.height(24.dp)
|
||||||
)
|
)
|
||||||
Text(
|
|
||||||
"FOLLOW",
|
|
||||||
fontSize = 14.sp,
|
|
||||||
color = Color(0xFFFFFFFF),
|
|
||||||
modifier = Modifier.align(
|
|
||||||
Alignment.Center
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Box(
|
||||||
|
// modifier = Modifier.noRippleClickable {
|
||||||
|
// onFollow()
|
||||||
|
// }
|
||||||
|
// ) {
|
||||||
|
// Image(
|
||||||
|
// painter = painterResource(id = R.drawable.follow_bg),
|
||||||
|
// contentDescription = "Follow",
|
||||||
|
// modifier = Modifier
|
||||||
|
// .width(79.dp)
|
||||||
|
// .height(24.dp)
|
||||||
|
// )
|
||||||
|
// Text(
|
||||||
|
// text = if (isFollowing) {
|
||||||
|
// stringResource(R.string.following_upper)
|
||||||
|
// } else {
|
||||||
|
// stringResource(R.string.follow_upper)
|
||||||
|
// },
|
||||||
|
// fontSize = 14.sp,
|
||||||
|
// color = Color(0xFFFFFFFF),
|
||||||
|
// modifier = Modifier.align(
|
||||||
|
// Alignment.Center
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,13 @@ object FollowerNoticeViewModel : ViewModel() {
|
|||||||
private val _followerItemsFlow =
|
private val _followerItemsFlow =
|
||||||
MutableStateFlow<PagingData<AccountFollow>>(PagingData.empty())
|
MutableStateFlow<PagingData<AccountFollow>>(PagingData.empty())
|
||||||
val followerItemsFlow = _followerItemsFlow.asStateFlow()
|
val followerItemsFlow = _followerItemsFlow.asStateFlow()
|
||||||
|
var isFirstLoad = true
|
||||||
|
|
||||||
init {
|
fun reload(force: Boolean = false) {
|
||||||
|
if (!isFirstLoad && !force) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isFirstLoad = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Pager(
|
Pager(
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FollowingListScreen(userId: Int) {
|
fun FollowingListScreen(userId: Int) {
|
||||||
val model = FollowerListViewModel
|
val model = FollowingListViewModel
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
model.loadData(userId)
|
model.loadData(userId)
|
||||||
@@ -47,6 +47,9 @@ fun FollowingListScreen(userId: Int) {
|
|||||||
isFollowing = user.isFollowing
|
isFollowing = user.isFollowing
|
||||||
) {
|
) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
if (user.isFollowing) {
|
||||||
|
model.unfollowUser(user.id)
|
||||||
|
} else {
|
||||||
model.followUser(user.id)
|
model.followUser(user.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,4 +57,5 @@ fun FollowingListScreen(userId: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -24,9 +24,6 @@ object FollowingListViewModel : ViewModel() {
|
|||||||
val usersFlow = _usersFlow.asStateFlow()
|
val usersFlow = _usersFlow.asStateFlow()
|
||||||
private var userId by mutableStateOf<Int?>(null)
|
private var userId by mutableStateOf<Int?>(null)
|
||||||
fun loadData(id: Int) {
|
fun loadData(id: Int) {
|
||||||
if (userId == id) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userId = id
|
userId = id
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Pager(
|
Pager(
|
||||||
@@ -34,7 +31,7 @@ object FollowingListViewModel : ViewModel() {
|
|||||||
pagingSourceFactory = {
|
pagingSourceFactory = {
|
||||||
AccountPagingSource(
|
AccountPagingSource(
|
||||||
userService,
|
userService,
|
||||||
followerId = id
|
followingId = id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
).flow.cachedIn(viewModelScope).collectLatest {
|
).flow.cachedIn(viewModelScope).collectLatest {
|
||||||
@@ -43,11 +40,11 @@ object FollowingListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateIsFollow(id: Int) {
|
private fun updateIsFollow(id: Int, isFollow: Boolean = true) {
|
||||||
val currentPagingData = usersFlow.value
|
val currentPagingData = usersFlow.value
|
||||||
val updatedPagingData = currentPagingData.map { user ->
|
val updatedPagingData = currentPagingData.map { user ->
|
||||||
if (user.id == id) {
|
if (user.id == id) {
|
||||||
user.copy(isFollowing = true)
|
user.copy(isFollowing = isFollow)
|
||||||
} else {
|
} else {
|
||||||
user
|
user
|
||||||
}
|
}
|
||||||
@@ -60,4 +57,9 @@ object FollowingListViewModel : ViewModel() {
|
|||||||
updateIsFollow(userId)
|
updateIsFollow(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun unfollowUser(userId: Int) {
|
||||||
|
userService.unFollowUser(userId.toString())
|
||||||
|
updateIsFollow(userId, false)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,6 +54,9 @@ import com.aiosman.riderpro.ui.NavigationRoute
|
|||||||
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||||
|
import com.aiosman.riderpro.ui.favourite.FavouriteNoticeViewModel
|
||||||
|
import com.aiosman.riderpro.ui.follower.FollowerNoticeViewModel
|
||||||
|
import com.aiosman.riderpro.ui.like.LikeNoticeViewModel
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import com.aiosman.riderpro.ui.post.PostViewModel
|
import com.aiosman.riderpro.ui.post.PostViewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
@@ -72,7 +75,7 @@ fun NotificationsScreen() {
|
|||||||
var comments = dataFlow.collectAsLazyPagingItems()
|
var comments = dataFlow.collectAsLazyPagingItems()
|
||||||
val state = rememberPullRefreshState(MessageListViewModel.isLoading, onRefresh = {
|
val state = rememberPullRefreshState(MessageListViewModel.isLoading, onRefresh = {
|
||||||
MessageListViewModel.viewModelScope.launch {
|
MessageListViewModel.viewModelScope.launch {
|
||||||
MessageListViewModel.initData()
|
MessageListViewModel.initData(force = true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -103,6 +106,13 @@ fun NotificationsScreen() {
|
|||||||
R.drawable.rider_pro_like,
|
R.drawable.rider_pro_like,
|
||||||
stringResource(R.string.like_upper)
|
stringResource(R.string.like_upper)
|
||||||
) {
|
) {
|
||||||
|
if (MessageListViewModel.likeNoticeCount > 0) {
|
||||||
|
// 刷新点赞消息列表
|
||||||
|
LikeNoticeViewModel.isFirstLoad = true
|
||||||
|
// 清除点赞消息数量
|
||||||
|
MessageListViewModel.clearLikeNoticeCount()
|
||||||
|
}
|
||||||
|
|
||||||
navController.navigate(NavigationRoute.Likes.route)
|
navController.navigate(NavigationRoute.Likes.route)
|
||||||
}
|
}
|
||||||
NotificationIndicator(
|
NotificationIndicator(
|
||||||
@@ -110,6 +120,11 @@ fun NotificationsScreen() {
|
|||||||
R.drawable.rider_pro_followers,
|
R.drawable.rider_pro_followers,
|
||||||
stringResource(R.string.followers_upper)
|
stringResource(R.string.followers_upper)
|
||||||
) {
|
) {
|
||||||
|
if (MessageListViewModel.followNoticeCount > 0) {
|
||||||
|
// 刷新关注消息列表
|
||||||
|
FollowerNoticeViewModel.isFirstLoad = true
|
||||||
|
MessageListViewModel.clearFollowNoticeCount()
|
||||||
|
}
|
||||||
navController.navigate(NavigationRoute.Followers.route)
|
navController.navigate(NavigationRoute.Followers.route)
|
||||||
}
|
}
|
||||||
NotificationIndicator(
|
NotificationIndicator(
|
||||||
@@ -117,6 +132,11 @@ fun NotificationsScreen() {
|
|||||||
R.drawable.rider_pro_favoriate,
|
R.drawable.rider_pro_favoriate,
|
||||||
stringResource(R.string.favourites_upper)
|
stringResource(R.string.favourites_upper)
|
||||||
) {
|
) {
|
||||||
|
if (MessageListViewModel.favouriteNoticeCount > 0) {
|
||||||
|
// 刷新收藏消息列表
|
||||||
|
FavouriteNoticeViewModel.isFirstLoad = true
|
||||||
|
MessageListViewModel.clearFavouriteNoticeCount()
|
||||||
|
}
|
||||||
navController.navigate(NavigationRoute.FavouritesScreen.route)
|
navController.navigate(NavigationRoute.FavouritesScreen.route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,15 @@ object MessageListViewModel : ViewModel() {
|
|||||||
private val _commentItemsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
private val _commentItemsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||||
val commentItemsFlow = _commentItemsFlow.asStateFlow()
|
val commentItemsFlow = _commentItemsFlow.asStateFlow()
|
||||||
var isLoading by mutableStateOf(false)
|
var isLoading by mutableStateOf(false)
|
||||||
|
var isFirstLoad = true
|
||||||
suspend fun initData() {
|
suspend fun initData(force: Boolean = false) {
|
||||||
|
if (!isFirstLoad && !force) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (force) {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
}
|
||||||
|
isFirstLoad = false
|
||||||
val info = accountService.getMyNoticeInfo()
|
val info = accountService.getMyNoticeInfo()
|
||||||
noticeInfo = info
|
noticeInfo = info
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@@ -43,7 +49,7 @@ object MessageListViewModel : ViewModel() {
|
|||||||
CommentPagingSource(
|
CommentPagingSource(
|
||||||
CommentRemoteDataSource(commentService),
|
CommentRemoteDataSource(commentService),
|
||||||
selfNotice = true,
|
selfNotice = true,
|
||||||
order="latest"
|
order = "latest"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
).flow.cachedIn(viewModelScope).collectLatest {
|
).flow.cachedIn(viewModelScope).collectLatest {
|
||||||
@@ -51,6 +57,7 @@ object MessageListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val likeNoticeCount
|
val likeNoticeCount
|
||||||
@@ -80,4 +87,15 @@ object MessageListViewModel : ViewModel() {
|
|||||||
updateIsRead(id)
|
updateIsRead(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clearLikeNoticeCount() {
|
||||||
|
noticeInfo = noticeInfo?.copy(likeCount = 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearFollowNoticeCount() {
|
||||||
|
noticeInfo = noticeInfo?.copy(followCount = 0)
|
||||||
|
}
|
||||||
|
fun clearFavouriteNoticeCount() {
|
||||||
|
noticeInfo = noticeInfo?.copy(favoriteCount = 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -37,11 +37,16 @@ object MyProfileViewModel : ViewModel() {
|
|||||||
private var _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
private var _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||||
var momentsFlow = _momentsFlow.asStateFlow()
|
var momentsFlow = _momentsFlow.asStateFlow()
|
||||||
var refreshing by mutableStateOf(false)
|
var refreshing by mutableStateOf(false)
|
||||||
|
var firstLoad = true
|
||||||
fun loadProfile(pullRefresh: Boolean = false) {
|
fun loadProfile(pullRefresh: Boolean = false) {
|
||||||
|
if (!firstLoad && !pullRefresh) {
|
||||||
|
return
|
||||||
|
}
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (pullRefresh){
|
if (pullRefresh){
|
||||||
refreshing = true
|
refreshing = true
|
||||||
}
|
}
|
||||||
|
firstLoad = false
|
||||||
profile = accountService.getMyAccountProfile()
|
profile = accountService.getMyAccountProfile()
|
||||||
val profile = accountService.getMyAccountProfile()
|
val profile = accountService.getMyAccountProfile()
|
||||||
refreshing = false
|
refreshing = false
|
||||||
|
|||||||
@@ -23,8 +23,12 @@ object LikeNoticeViewModel : ViewModel() {
|
|||||||
private val accountService: AccountService = AccountServiceImpl()
|
private val accountService: AccountService = AccountServiceImpl()
|
||||||
private val _likeItemsFlow = MutableStateFlow<PagingData<AccountLikeEntity>>(PagingData.empty())
|
private val _likeItemsFlow = MutableStateFlow<PagingData<AccountLikeEntity>>(PagingData.empty())
|
||||||
val likeItemsFlow = _likeItemsFlow.asStateFlow()
|
val likeItemsFlow = _likeItemsFlow.asStateFlow()
|
||||||
|
var isFirstLoad = true
|
||||||
init {
|
fun reload(force: Boolean = false) {
|
||||||
|
if (!isFirstLoad && !force) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isFirstLoad = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Pager(
|
Pager(
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
|
|||||||
@@ -56,8 +56,10 @@ fun LikeNoticeScreen() {
|
|||||||
var dataFlow = model.likeItemsFlow
|
var dataFlow = model.likeItemsFlow
|
||||||
var likes = dataFlow.collectAsLazyPagingItems()
|
var likes = dataFlow.collectAsLazyPagingItems()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
|
model.reload()
|
||||||
model.updateNotice()
|
model.updateNotice()
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBarMaskLayout(
|
StatusBarMaskLayout(
|
||||||
darkIcons = true,
|
darkIcons = true,
|
||||||
maskBoxBackgroundColor = Color(0xFFFFFFFF)
|
maskBoxBackgroundColor = Color(0xFFFFFFFF)
|
||||||
@@ -125,7 +127,7 @@ fun ActionPostNoticeItem(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 16.dp)
|
modifier = Modifier.padding(vertical = 16.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@@ -188,7 +190,7 @@ fun LikeCommentNoticeItem(
|
|||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp).noRippleClickable {
|
modifier = Modifier.padding(vertical = 16.dp).noRippleClickable {
|
||||||
item.comment?.postId.let {
|
item.comment?.postId.let {
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
NavigationRoute.Post.route.replace(
|
NavigationRoute.Post.route.replace(
|
||||||
@@ -261,7 +263,8 @@ fun LikeCommentNoticeItem(
|
|||||||
Text(
|
Text(
|
||||||
text = item.comment?.content ?: "",
|
text = item.comment?.content ?: "",
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = Color(0x99000000)
|
color = Color(0x99000000),
|
||||||
|
maxLines = 2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EmailSignupScreen() {
|
fun EmailSignupScreen() {
|
||||||
var email by remember { mutableStateOf("takayamaaren@gmail.com") }
|
var email by remember { mutableStateOf("") }
|
||||||
var password by remember { mutableStateOf("Dzh17217.") }
|
var password by remember { mutableStateOf("") }
|
||||||
var confirmPassword by remember { mutableStateOf("Dzh17217.") }
|
var confirmPassword by remember { mutableStateOf("") }
|
||||||
var rememberMe by remember { mutableStateOf(false) }
|
var rememberMe by remember { mutableStateOf(false) }
|
||||||
var acceptTerms by remember { mutableStateOf(false) }
|
var acceptTerms by remember { mutableStateOf(false) }
|
||||||
var acceptPromotions by remember { mutableStateOf(false) }
|
var acceptPromotions by remember { mutableStateOf(false) }
|
||||||
@@ -68,7 +68,6 @@ fun EmailSignupScreen() {
|
|||||||
var confirmPasswordError by remember { mutableStateOf<String?>(null) }
|
var confirmPasswordError by remember { mutableStateOf<String?>(null) }
|
||||||
var termsError by remember { mutableStateOf<Boolean>(false) }
|
var termsError by remember { mutableStateOf<Boolean>(false) }
|
||||||
var promotionsError by remember { mutableStateOf<Boolean>(false) }
|
var promotionsError by remember { mutableStateOf<Boolean>(false) }
|
||||||
|
|
||||||
fun validateForm(): Boolean {
|
fun validateForm(): Boolean {
|
||||||
emailError = when {
|
emailError = when {
|
||||||
// 非空
|
// 非空
|
||||||
|
|||||||
@@ -93,9 +93,15 @@ fun UserAuthScreen() {
|
|||||||
}
|
}
|
||||||
} catch (e: ServiceException) {
|
} catch (e: ServiceException) {
|
||||||
// handle error
|
// handle error
|
||||||
|
|
||||||
|
if (e.code == 12005) {
|
||||||
|
emailError = context.getString(R.string.error_invalidate_username_password)
|
||||||
|
passwordError = context.getString(R.string.error_invalidate_username_password)
|
||||||
|
} else {
|
||||||
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,15 +187,12 @@ fun UserAuthScreen() {
|
|||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) {
|
com.aiosman.riderpro.ui.composables.Checkbox(
|
||||||
Checkbox(
|
|
||||||
checked = rememberMe,
|
checked = rememberMe,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
rememberMe = it
|
rememberMe = it
|
||||||
},
|
},
|
||||||
colors = CheckboxDefaults.colors(
|
size = 18
|
||||||
checkedColor = Color.Black
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.remember_me),
|
stringResource(R.string.remember_me),
|
||||||
@@ -197,10 +200,34 @@ fun UserAuthScreen() {
|
|||||||
fontSize = 12.sp
|
fontSize = 12.sp
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Text(stringResource(R.string.forgot_password), fontSize = 12.sp, modifier = Modifier.noRippleClickable {
|
Text(
|
||||||
|
stringResource(R.string.forgot_password),
|
||||||
|
fontSize = 12.sp,
|
||||||
|
modifier = Modifier.noRippleClickable {
|
||||||
navController.navigate(NavigationRoute.ResetPassword.route)
|
navController.navigate(NavigationRoute.ResetPassword.route)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
// CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) {
|
||||||
|
// Checkbox(
|
||||||
|
// checked = rememberMe,
|
||||||
|
// onCheckedChange = {
|
||||||
|
// rememberMe = it
|
||||||
|
// },
|
||||||
|
// colors = CheckboxDefaults.colors(
|
||||||
|
// checkedColor = Color.Black
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// Text(
|
||||||
|
// stringResource(R.string.remember_me),
|
||||||
|
// modifier = Modifier.padding(start = 8.dp),
|
||||||
|
// fontSize = 12.sp
|
||||||
|
// )
|
||||||
|
// Spacer(modifier = Modifier.weight(1f))
|
||||||
|
// Text(stringResource(R.string.forgot_password), fontSize = 12.sp, modifier = Modifier.noRippleClickable {
|
||||||
|
// navController.navigate(NavigationRoute.ResetPassword.route)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(64.dp))
|
Spacer(modifier = Modifier.height(64.dp))
|
||||||
ActionButton(
|
ActionButton(
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class CommentsViewModel(
|
|||||||
val commentsFlow = _commentsFlow.asStateFlow()
|
val commentsFlow = _commentsFlow.asStateFlow()
|
||||||
var order: String by mutableStateOf("like")
|
var order: String by mutableStateOf("like")
|
||||||
var addedCommentList by mutableStateOf<List<CommentEntity>>(emptyList())
|
var addedCommentList by mutableStateOf<List<CommentEntity>>(emptyList())
|
||||||
|
var subCommentLoadingMap by mutableStateOf(mutableMapOf<Int, Boolean>())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预加载,在跳转到 PostScreen 之前设置好内容
|
* 预加载,在跳转到 PostScreen 之前设置好内容
|
||||||
@@ -162,6 +163,8 @@ class CommentsViewModel(
|
|||||||
val currentPagingData = commentsFlow.value
|
val currentPagingData = commentsFlow.value
|
||||||
val updatedPagingData = currentPagingData.map { comment ->
|
val updatedPagingData = currentPagingData.map { comment ->
|
||||||
if (comment.id == commentId) {
|
if (comment.id == commentId) {
|
||||||
|
try {
|
||||||
|
subCommentLoadingMap[commentId] = true
|
||||||
val subCommentList = commentService.getComments(
|
val subCommentList = commentService.getComments(
|
||||||
postId = postId.toInt(),
|
postId = postId.toInt(),
|
||||||
parentCommentId = commentId,
|
parentCommentId = commentId,
|
||||||
@@ -172,6 +175,11 @@ class CommentsViewModel(
|
|||||||
reply = comment.reply.plus(subCommentList),
|
reply = comment.reply.plus(subCommentList),
|
||||||
replyPage = comment.replyPage + 1
|
replyPage = comment.replyPage + 1
|
||||||
)
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return@map comment.copy()
|
||||||
|
} finally {
|
||||||
|
subCommentLoadingMap[commentId] = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
comment
|
comment
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ import androidx.compose.foundation.pager.HorizontalPager
|
|||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.ClickableText
|
import androidx.compose.material.LinearProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -47,7 +48,6 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalClipboardManager
|
import androidx.compose.ui.platform.LocalClipboardManager
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -67,6 +67,7 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.paging.LoadState
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import com.aiosman.riderpro.AppState
|
import com.aiosman.riderpro.AppState
|
||||||
import com.aiosman.riderpro.LocalAnimatedContentScope
|
import com.aiosman.riderpro.LocalAnimatedContentScope
|
||||||
@@ -79,22 +80,18 @@ import com.aiosman.riderpro.entity.MomentImageEntity
|
|||||||
import com.aiosman.riderpro.exp.formatPostTime
|
import com.aiosman.riderpro.exp.formatPostTime
|
||||||
import com.aiosman.riderpro.exp.timeAgo
|
import com.aiosman.riderpro.exp.timeAgo
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
|
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||||
import com.aiosman.riderpro.ui.composables.AnimatedFavouriteIcon
|
import com.aiosman.riderpro.ui.composables.AnimatedFavouriteIcon
|
||||||
import com.aiosman.riderpro.ui.composables.AnimatedLikeIcon
|
import com.aiosman.riderpro.ui.composables.AnimatedLikeIcon
|
||||||
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||||
|
import com.aiosman.riderpro.ui.composables.CustomClickableText
|
||||||
import com.aiosman.riderpro.ui.composables.EditCommentBottomModal
|
import com.aiosman.riderpro.ui.composables.EditCommentBottomModal
|
||||||
|
import com.aiosman.riderpro.ui.composables.FollowButton
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel
|
import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
|
||||||
import androidx.compose.material.LinearProgressIndicator
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.paging.LoadState
|
|
||||||
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
|
||||||
import com.aiosman.riderpro.ui.composables.CustomClickableText
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -618,31 +615,12 @@ fun Header(
|
|||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Text(text = nickname ?: "", fontWeight = FontWeight.Bold)
|
Text(text = nickname ?: "", fontWeight = FontWeight.Bold)
|
||||||
if (AppState.UserId != userId) {
|
if (AppState.UserId != userId) {
|
||||||
Box(
|
FollowButton(
|
||||||
modifier = Modifier
|
isFollowing = isFollowing,
|
||||||
.height(20.dp)
|
onFollowClick = onFollowClick,
|
||||||
.wrapContentWidth()
|
imageModifier = Modifier.height(18.dp).width(80.dp),
|
||||||
.padding(start = 6.dp)
|
fontSize = 12.sp
|
||||||
.noRippleClickable {
|
|
||||||
onFollowClick()
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.height(18.dp).width(80.dp),
|
|
||||||
painter = painterResource(id = R.drawable.follow_bg),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.FillWidth
|
|
||||||
)
|
)
|
||||||
Text(
|
|
||||||
text = if (isFollowing) stringResource(R.string.following_upper) else stringResource(
|
|
||||||
R.string.follow_upper
|
|
||||||
),
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = Color.White,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (AppState.UserId == userId) {
|
if (AppState.UserId == userId) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
@@ -757,28 +735,6 @@ fun PostDetails(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun LongPressClickableText(
|
|
||||||
text: AnnotatedString,
|
|
||||||
onClick: (Int) -> Unit,
|
|
||||||
onLongClick: () -> Unit,
|
|
||||||
style: TextStyle = TextStyle.Default
|
|
||||||
) {
|
|
||||||
ClickableText(
|
|
||||||
text = text,
|
|
||||||
onClick = onClick,
|
|
||||||
style = style,
|
|
||||||
modifier = Modifier.pointerInput(Unit) {
|
|
||||||
detectTapGestures(
|
|
||||||
onLongPress = {
|
|
||||||
onLongClick()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CommentItem(
|
fun CommentItem(
|
||||||
@@ -910,7 +866,7 @@ fun CommentItem(
|
|||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
if (AppState.UserId?.toLong() != commentEntity.author) {
|
if (AppState.UserId?.toLong() != commentEntity.author) {
|
||||||
Text(
|
Text(
|
||||||
text = "Reply",
|
text = stringResource(R.string.reply),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = Color.Gray,
|
color = Color.Gray,
|
||||||
modifier = Modifier.noRippleClickable {
|
modifier = Modifier.noRippleClickable {
|
||||||
@@ -970,7 +926,7 @@ fun CommentItem(
|
|||||||
if (commentEntity.replyCount > 0 && !isChild && commentEntity.reply.size < commentEntity.replyCount) {
|
if (commentEntity.replyCount > 0 && !isChild && commentEntity.reply.size < commentEntity.replyCount) {
|
||||||
val remaining = commentEntity.replyCount - commentEntity.reply.size
|
val remaining = commentEntity.replyCount - commentEntity.reply.size
|
||||||
Text(
|
Text(
|
||||||
text = "View $remaining more replies",
|
text = stringResource(R.string.view_more_reply, remaining),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = Color(0xFF6F94AE),
|
color = Color(0xFF6F94AE),
|
||||||
modifier = Modifier.noRippleClickable {
|
modifier = Modifier.noRippleClickable {
|
||||||
@@ -1242,7 +1198,7 @@ fun CommentMenuModal(
|
|||||||
commentEntity?.let {
|
commentEntity?.let {
|
||||||
Spacer(modifier = Modifier.width(48.dp))
|
Spacer(modifier = Modifier.width(48.dp))
|
||||||
MenuActionItem(
|
MenuActionItem(
|
||||||
text = "Like",
|
text = stringResource(R.string.like),
|
||||||
content = {
|
content = {
|
||||||
AnimatedLikeIcon(
|
AnimatedLikeIcon(
|
||||||
liked = it.liked,
|
liked = it.liked,
|
||||||
@@ -1258,7 +1214,7 @@ fun CommentMenuModal(
|
|||||||
Spacer(modifier = Modifier.width(48.dp))
|
Spacer(modifier = Modifier.width(48.dp))
|
||||||
MenuActionItem(
|
MenuActionItem(
|
||||||
icon = R.drawable.rider_pro_comment,
|
icon = R.drawable.rider_pro_comment,
|
||||||
text = "Reply"
|
text = stringResource(R.string.reply)
|
||||||
) {
|
) {
|
||||||
onReplyClick()
|
onReplyClick()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,4 +61,13 @@
|
|||||||
<string name="original">原始图片</string>
|
<string name="original">原始图片</string>
|
||||||
<string name="favourites">收藏</string>
|
<string name="favourites">收藏</string>
|
||||||
<string name="delete">删除</string>
|
<string name="delete">删除</string>
|
||||||
|
<string name="copy">复制</string>
|
||||||
|
<string name="like">点赞</string>
|
||||||
|
<string name="reply">回复</string>
|
||||||
|
<string name="view_more_reply">查看更多%1d条回复</string>
|
||||||
|
<string name="error_invalidate_username_password">错误的用户名或密码</string>
|
||||||
|
<string name="recover_account_upper">找回密码</string>
|
||||||
|
<string name="recover">找回</string>
|
||||||
|
<string name="reset_mail_send_success">邮件已发送!请查收您的邮箱,按照邮件中的指示重置密码。</string>
|
||||||
|
<string name="reset_mail_send_failed">邮件发送失败,请检查您的网络连接或稍后重试。</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -61,4 +61,12 @@
|
|||||||
<string name="favourites">Favourite</string>
|
<string name="favourites">Favourite</string>
|
||||||
<string name="delete">Delete</string>
|
<string name="delete">Delete</string>
|
||||||
<string name="copy">Copy</string>
|
<string name="copy">Copy</string>
|
||||||
|
<string name="like">Like</string>
|
||||||
|
<string name="reply">Reply</string>
|
||||||
|
<string name="view_more_reply">View %1d more replies</string>
|
||||||
|
<string name="error_invalidate_username_password">Invalid email or password</string>
|
||||||
|
<string name="recover_account_upper">RCOVER ACCOUNT</string>
|
||||||
|
<string name="recover">Recover</string>
|
||||||
|
<string name="reset_mail_send_success">An email has been sent to your registered email address. Please check your inbox and follow the instructions to reset your password.</string>
|
||||||
|
<string name="reset_mail_send_failed">Failed to send email. Please check your network connection or try again later.</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user