更新个人主页
This commit is contained in:
18
app/src/main/java/com/aiosman/riderpro/data/DictService.kt
Normal file
18
app/src/main/java/com/aiosman/riderpro/data/DictService.kt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.aiosman.riderpro.data
|
||||||
|
|
||||||
|
import com.aiosman.riderpro.data.api.ApiClient
|
||||||
|
import com.aiosman.riderpro.data.api.DictItem
|
||||||
|
|
||||||
|
interface DictService {
|
||||||
|
/**
|
||||||
|
* 获取字典项
|
||||||
|
*/
|
||||||
|
suspend fun getDictByKey(key: String): DictItem
|
||||||
|
}
|
||||||
|
|
||||||
|
class DictServiceImpl : DictService {
|
||||||
|
override suspend fun getDictByKey(key: String): DictItem {
|
||||||
|
val resp = ApiClient.api.getDict(key)
|
||||||
|
return resp.body()?.data ?: throw Exception("failed to get dict")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,6 +119,15 @@ data class AppConfig(
|
|||||||
val trtcAppId: Int,
|
val trtcAppId: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class DictItem(
|
||||||
|
@SerializedName("key")
|
||||||
|
val key: String,
|
||||||
|
@SerializedName("value")
|
||||||
|
val value: String,
|
||||||
|
@SerializedName("desc")
|
||||||
|
val desc: String,
|
||||||
|
)
|
||||||
|
|
||||||
interface RiderProAPI {
|
interface RiderProAPI {
|
||||||
@POST("register")
|
@POST("register")
|
||||||
suspend fun register(@Body body: RegisterRequestBody): Response<Unit>
|
suspend fun register(@Body body: RegisterRequestBody): Response<Unit>
|
||||||
@@ -322,4 +331,9 @@ interface RiderProAPI {
|
|||||||
|
|
||||||
@GET("app/info")
|
@GET("app/info")
|
||||||
suspend fun getAppConfig(): Response<DataContainer<AppConfig>>
|
suspend fun getAppConfig(): Response<DataContainer<AppConfig>>
|
||||||
|
|
||||||
|
@GET("dict")
|
||||||
|
suspend fun getDict(
|
||||||
|
@Query("key") key: String
|
||||||
|
): Response<DataContainer<DictItem>>
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ import com.aiosman.riderpro.ui.modification.EditModificationScreen
|
|||||||
import com.aiosman.riderpro.ui.post.NewPostImageGridScreen
|
import com.aiosman.riderpro.ui.post.NewPostImageGridScreen
|
||||||
import com.aiosman.riderpro.ui.post.NewPostScreen
|
import com.aiosman.riderpro.ui.post.NewPostScreen
|
||||||
import com.aiosman.riderpro.ui.post.PostScreen
|
import com.aiosman.riderpro.ui.post.PostScreen
|
||||||
import com.aiosman.riderpro.ui.profile.AccountProfile
|
import com.aiosman.riderpro.ui.profile.AccountProfileV2
|
||||||
|
|
||||||
sealed class NavigationRoute(
|
sealed class NavigationRoute(
|
||||||
val route: String,
|
val route: String,
|
||||||
@@ -240,7 +240,7 @@ fun NavigationController(
|
|||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalAnimatedContentScope provides this,
|
LocalAnimatedContentScope provides this,
|
||||||
) {
|
) {
|
||||||
AccountProfile(it.arguments?.getString("id")!!)
|
AccountProfileV2(it.arguments?.getString("id")!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
composable(
|
composable(
|
||||||
@@ -363,7 +363,6 @@ fun NavigationController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
@OptIn(ExperimentalSharedTransitionApi::class)
|
||||||
@@ -394,7 +393,7 @@ fun Navigation(
|
|||||||
fun NavHostController.navigateToPost(
|
fun NavHostController.navigateToPost(
|
||||||
id: Int,
|
id: Int,
|
||||||
highlightCommentId: Int? = 0,
|
highlightCommentId: Int? = 0,
|
||||||
initImagePagerIndex: Int? = null
|
initImagePagerIndex: Int? = 0
|
||||||
) {
|
) {
|
||||||
navigate(
|
navigate(
|
||||||
route = NavigationRoute.Post.route
|
route = NavigationRoute.Post.route
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.aiosman.riderpro.ui.composables
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -13,15 +12,14 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import androidx.core.graphics.drawable.toDrawable
|
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.compose.rememberAsyncImagePainter
|
import coil.compose.rememberAsyncImagePainter
|
||||||
import coil.compose.rememberImagePainter
|
import coil.compose.rememberImagePainter
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.request.SuccessResult
|
import coil.request.SuccessResult
|
||||||
import com.aiosman.riderpro.utils.BlurHashDecoder
|
|
||||||
import com.aiosman.riderpro.utils.Utils.getImageLoader
|
import com.aiosman.riderpro.utils.Utils.getImageLoader
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package com.aiosman.riderpro.ui.composables
|
||||||
|
|
||||||
|
import android.net.http.SslError
|
||||||
|
import android.webkit.SslErrorHandler
|
||||||
|
import android.webkit.WebSettings
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.webkit.WebViewClient
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.text.ClickableText
|
||||||
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import com.aiosman.riderpro.data.DictService
|
||||||
|
import com.aiosman.riderpro.data.DictServiceImpl
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
fun PolicyCheckbox(
|
||||||
|
checked: Boolean = false,
|
||||||
|
error: Boolean = false,
|
||||||
|
onCheckedChange: (Boolean) -> Unit,
|
||||||
|
) {
|
||||||
|
var showModal by remember { mutableStateOf(false) }
|
||||||
|
var modalSheetState = androidx.compose.material3.rememberModalBottomSheetState(
|
||||||
|
skipPartiallyExpanded = true,
|
||||||
|
)
|
||||||
|
var scope = rememberCoroutineScope()
|
||||||
|
val dictService: DictService = DictServiceImpl()
|
||||||
|
var policyUrl by remember { mutableStateOf("") }
|
||||||
|
fun openPolicyModel() {
|
||||||
|
scope.launch {
|
||||||
|
try {
|
||||||
|
val resp = dictService.getDictByKey("private_policy")
|
||||||
|
policyUrl = resp.value
|
||||||
|
showModal = true
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (showModal) {
|
||||||
|
ModalBottomSheet(
|
||||||
|
onDismissRequest = {
|
||||||
|
showModal = false
|
||||||
|
},
|
||||||
|
sheetState = modalSheetState,
|
||||||
|
windowInsets = WindowInsets(0),
|
||||||
|
containerColor = Color.White,
|
||||||
|
) {
|
||||||
|
WebViewDisplay(
|
||||||
|
url = policyUrl
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
Checkbox(
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = {
|
||||||
|
onCheckedChange(it)
|
||||||
|
},
|
||||||
|
size = 16
|
||||||
|
)
|
||||||
|
val text = buildAnnotatedString {
|
||||||
|
append("I agree to the ")
|
||||||
|
withStyle(style = SpanStyle(color = if (error) Color.Red else Color.Black)) {
|
||||||
|
append("terms and conditions")
|
||||||
|
}
|
||||||
|
addStyle(
|
||||||
|
style = SpanStyle(
|
||||||
|
color = Color.Blue,
|
||||||
|
textDecoration = TextDecoration.Underline
|
||||||
|
),
|
||||||
|
start = "I agree to the ".length,
|
||||||
|
end = "I agree to the terms and conditions".length
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ClickableText(
|
||||||
|
text = text,
|
||||||
|
modifier = Modifier.padding(start = 8.dp),
|
||||||
|
onClick = {
|
||||||
|
openPolicyModel()
|
||||||
|
},
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = if (error) Color.Red else Color.Black
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun WebViewDisplay(modifier: Modifier = Modifier, url: String) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
AndroidView(
|
||||||
|
factory = { context ->
|
||||||
|
WebView(context).apply {
|
||||||
|
webViewClient = object : WebViewClient() {
|
||||||
|
override fun onReceivedSslError(
|
||||||
|
view: WebView?,
|
||||||
|
handler: SslErrorHandler?,
|
||||||
|
error: SslError?
|
||||||
|
) {
|
||||||
|
handler?.proceed() // 忽略证书错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.apply {
|
||||||
|
domStorageEnabled = true
|
||||||
|
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
||||||
|
}
|
||||||
|
loadUrl(url)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -33,9 +33,7 @@ import com.aiosman.riderpro.ui.NavigationRoute
|
|||||||
import com.aiosman.riderpro.ui.index.tabs.add.AddPage
|
import com.aiosman.riderpro.ui.index.tabs.add.AddPage
|
||||||
import com.aiosman.riderpro.ui.index.tabs.message.NotificationsScreen
|
import com.aiosman.riderpro.ui.index.tabs.message.NotificationsScreen
|
||||||
import com.aiosman.riderpro.ui.index.tabs.moment.MomentsList
|
import com.aiosman.riderpro.ui.index.tabs.moment.MomentsList
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.v2.Profile2
|
import com.aiosman.riderpro.ui.index.tabs.profile.ProfileWrap
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.v2.Profile4
|
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.v2.ProfilePage
|
|
||||||
import com.aiosman.riderpro.ui.index.tabs.search.DiscoverScreen
|
import com.aiosman.riderpro.ui.index.tabs.search.DiscoverScreen
|
||||||
import com.aiosman.riderpro.ui.index.tabs.shorts.ShortVideo
|
import com.aiosman.riderpro.ui.index.tabs.shorts.ShortVideo
|
||||||
import com.aiosman.riderpro.ui.index.tabs.street.StreetPage
|
import com.aiosman.riderpro.ui.index.tabs.street.StreetPage
|
||||||
@@ -209,7 +207,7 @@ fun Profile() {
|
|||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Profile2()
|
ProfileWrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
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.material.ExperimentalMaterialApi
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.material.LinearProgressIndicator
|
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
@@ -27,7 +26,6 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
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.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
@@ -37,21 +35,14 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
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.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.LoadState
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
import com.aiosman.riderpro.entity.CommentEntity
|
|
||||||
import com.aiosman.riderpro.exp.timeAgo
|
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
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.follower.FollowerNoticeViewModel
|
||||||
import com.aiosman.riderpro.ui.like.LikeNoticeViewModel
|
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.navigateToChat
|
|
||||||
import com.aiosman.riderpro.ui.navigateToPost
|
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.net.Uri
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
@@ -19,7 +18,6 @@ import com.aiosman.riderpro.data.AccountService
|
|||||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||||
import com.aiosman.riderpro.data.MomentService
|
import com.aiosman.riderpro.data.MomentService
|
||||||
import com.aiosman.riderpro.data.UploadImage
|
import com.aiosman.riderpro.data.UploadImage
|
||||||
import com.aiosman.riderpro.data.UserServiceImpl
|
|
||||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||||
import com.aiosman.riderpro.entity.MomentEntity
|
import com.aiosman.riderpro.entity.MomentEntity
|
||||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
import com.aiosman.riderpro.entity.MomentPagingSource
|
||||||
@@ -35,23 +33,24 @@ object MyProfileViewModel : ViewModel() {
|
|||||||
val accountService: AccountService = AccountServiceImpl()
|
val accountService: AccountService = AccountServiceImpl()
|
||||||
val momentService: MomentService = MomentServiceImpl()
|
val momentService: MomentService = MomentServiceImpl()
|
||||||
var profile by mutableStateOf<AccountProfileEntity?>(null)
|
var profile by mutableStateOf<AccountProfileEntity?>(null)
|
||||||
private var _momentsFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
private var _sharedFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
||||||
var momentsFlow = _momentsFlow.asStateFlow()
|
var sharedFlow = _sharedFlow.asStateFlow()
|
||||||
|
|
||||||
var refreshing by mutableStateOf(false)
|
var refreshing by mutableStateOf(false)
|
||||||
var firstLoad = true
|
var firstLoad = true
|
||||||
|
|
||||||
fun loadProfile(pullRefresh: Boolean = false) {
|
fun loadProfile(pullRefresh: Boolean = false) {
|
||||||
// if (!firstLoad && !pullRefresh) {
|
if (!firstLoad) return
|
||||||
// return
|
|
||||||
// }
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (pullRefresh){
|
if (pullRefresh) {
|
||||||
refreshing = true
|
refreshing = true
|
||||||
}
|
}
|
||||||
firstLoad = false
|
firstLoad = false
|
||||||
val profile = accountService.getMyAccountProfile()
|
val profile = accountService.getMyAccountProfile()
|
||||||
this@MyProfileViewModel.profile = profile
|
MyProfileViewModel.profile = profile
|
||||||
refreshing = false
|
refreshing = false
|
||||||
try {
|
try {
|
||||||
|
// Collect shared flow
|
||||||
Pager(
|
Pager(
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
pagingSourceFactory = {
|
pagingSourceFactory = {
|
||||||
@@ -61,13 +60,11 @@ object MyProfileViewModel : ViewModel() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
).flow.cachedIn(viewModelScope).collectLatest {
|
).flow.cachedIn(viewModelScope).collectLatest {
|
||||||
_momentsFlow.value = it
|
_sharedFlow.value = it
|
||||||
}
|
}
|
||||||
}catch (e: Exception){
|
} catch (e: Exception) {
|
||||||
Log.e("MyProfileViewModel", "loadProfile: ", e)
|
Log.e("MyProfileViewModel", "loadProfile: ", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +73,6 @@ object MyProfileViewModel : ViewModel() {
|
|||||||
token = null
|
token = null
|
||||||
rememberMe = false
|
rememberMe = false
|
||||||
saveData()
|
saveData()
|
||||||
|
|
||||||
}
|
}
|
||||||
AppState.ReloadAppState()
|
AppState.ReloadAppState()
|
||||||
}
|
}
|
||||||
@@ -115,8 +111,7 @@ object MyProfileViewModel : ViewModel() {
|
|||||||
|
|
||||||
fun ResetModel() {
|
fun ResetModel() {
|
||||||
profile = null
|
profile = null
|
||||||
_momentsFlow.value = PagingData.empty()
|
_sharedFlow.value = PagingData.empty()
|
||||||
firstLoad = true
|
firstLoad = true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,116 +0,0 @@
|
|||||||
package com.aiosman.riderpro.ui.index.tabs.profile.v2
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import androidx.paging.Pager
|
|
||||||
import androidx.paging.PagingConfig
|
|
||||||
import androidx.paging.PagingData
|
|
||||||
import androidx.paging.cachedIn
|
|
||||||
import com.aiosman.riderpro.AppState
|
|
||||||
import com.aiosman.riderpro.AppStore
|
|
||||||
import com.aiosman.riderpro.data.AccountService
|
|
||||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
|
||||||
import com.aiosman.riderpro.data.MomentService
|
|
||||||
import com.aiosman.riderpro.data.UploadImage
|
|
||||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
|
||||||
import com.aiosman.riderpro.entity.MomentEntity
|
|
||||||
import com.aiosman.riderpro.entity.MomentPagingSource
|
|
||||||
import com.aiosman.riderpro.entity.MomentRemoteDataSource
|
|
||||||
import com.aiosman.riderpro.entity.MomentServiceImpl
|
|
||||||
import com.aiosman.riderpro.ui.post.NewPostViewModel.uriToFile
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
object MyProfileViewModel2 : ViewModel() {
|
|
||||||
val accountService: AccountService = AccountServiceImpl()
|
|
||||||
val momentService: MomentService = MomentServiceImpl()
|
|
||||||
var profile by mutableStateOf<AccountProfileEntity?>(null)
|
|
||||||
private var _sharedFlow = MutableStateFlow<PagingData<MomentEntity>>(PagingData.empty())
|
|
||||||
var sharedFlow = _sharedFlow.asStateFlow()
|
|
||||||
|
|
||||||
var refreshing by mutableStateOf(false)
|
|
||||||
var firstLoad = true
|
|
||||||
|
|
||||||
fun loadProfile(pullRefresh: Boolean = false) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
if (pullRefresh) {
|
|
||||||
refreshing = true
|
|
||||||
}
|
|
||||||
firstLoad = false
|
|
||||||
val profile = accountService.getMyAccountProfile()
|
|
||||||
MyProfileViewModel2.profile = profile
|
|
||||||
refreshing = false
|
|
||||||
try {
|
|
||||||
// Collect shared flow
|
|
||||||
Pager(
|
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
|
||||||
pagingSourceFactory = {
|
|
||||||
MomentPagingSource(
|
|
||||||
MomentRemoteDataSource(momentService),
|
|
||||||
author = profile.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
).flow.cachedIn(viewModelScope).collectLatest {
|
|
||||||
_sharedFlow.value = it
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("MyProfileViewModel", "loadProfile: ", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun logout() {
|
|
||||||
AppStore.apply {
|
|
||||||
token = null
|
|
||||||
rememberMe = false
|
|
||||||
saveData()
|
|
||||||
}
|
|
||||||
AppState.ReloadAppState()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateUserProfileBanner(bannerImageUrl: Uri?, context: Context) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
var newBanner = bannerImageUrl?.let {
|
|
||||||
val cursor = context.contentResolver.query(it, null, null, null, null)
|
|
||||||
var newBanner: UploadImage? = null
|
|
||||||
cursor?.use { cur ->
|
|
||||||
if (cur.moveToFirst()) {
|
|
||||||
val displayName = cur.getString(cur.getColumnIndex("_display_name"))
|
|
||||||
val extension = displayName.substringAfterLast(".")
|
|
||||||
Log.d("NewPost", "File name: $displayName, extension: $extension")
|
|
||||||
// read as file
|
|
||||||
val file = uriToFile(context, it)
|
|
||||||
Log.d("NewPost", "File size: ${file.length()}")
|
|
||||||
newBanner = UploadImage(file, displayName, it.toString(), extension)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newBanner
|
|
||||||
}
|
|
||||||
accountService.updateProfile(
|
|
||||||
banner = newBanner,
|
|
||||||
avatar = null,
|
|
||||||
nickName = null,
|
|
||||||
bio = null
|
|
||||||
)
|
|
||||||
profile = accountService.getMyAccountProfile()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val bio get() = profile?.bio ?: ""
|
|
||||||
val nickName get() = profile?.nickName ?: ""
|
|
||||||
val avatar get() = profile?.avatar
|
|
||||||
|
|
||||||
fun ResetModel() {
|
|
||||||
profile = null
|
|
||||||
_sharedFlow.value = PagingData.empty()
|
|
||||||
firstLoad = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,542 +0,0 @@
|
|||||||
package com.aiosman.riderpro.ui.index.tabs.profile.v2
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.systemBars
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Edit
|
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
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.draw.clip
|
|
||||||
import androidx.compose.ui.draw.shadow
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
|
||||||
import com.aiosman.riderpro.LocalNavController
|
|
||||||
import com.aiosman.riderpro.R
|
|
||||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
|
||||||
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
|
||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
|
||||||
import com.aiosman.riderpro.ui.composables.MenuItem
|
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.MyProfileViewModel
|
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
|
||||||
fun Profile2() {
|
|
||||||
val model = MyProfileViewModel2
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
MyProfileViewModel2.loadProfile()
|
|
||||||
}
|
|
||||||
val navController: NavController = LocalNavController.current
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val state = rememberPullRefreshState(MyProfileViewModel2.refreshing, onRefresh = {
|
|
||||||
MyProfileViewModel2.loadProfile(pullRefresh = true)
|
|
||||||
})
|
|
||||||
val context = LocalContext.current
|
|
||||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
|
||||||
val pickBannerImageLauncher = rememberLauncherForActivityResult(
|
|
||||||
contract = ActivityResultContracts.StartActivityForResult()
|
|
||||||
) { result ->
|
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
|
||||||
val uri = result.data?.data
|
|
||||||
uri?.let {
|
|
||||||
MyProfileViewModel2.updateUserProfileBanner(it, context = context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val nestedScrollConnection = remember {
|
|
||||||
object : NestedScrollConnection {
|
|
||||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
|
||||||
// 处理滚动事件之前的逻辑
|
|
||||||
return Offset.Zero
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
|
|
||||||
// 处理滚动事件之后的逻辑
|
|
||||||
return Offset.Zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(Color(0xFFF5F5F5))
|
|
||||||
.padding(bottom = with(LocalDensity.current) {
|
|
||||||
val da = WindowInsets.navigationBars
|
|
||||||
.getBottom(this)
|
|
||||||
.toDp() + 48.dp
|
|
||||||
da
|
|
||||||
})
|
|
||||||
.pullRefresh(state)
|
|
||||||
) {
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.nestedScroll(nestedScrollConnection),
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
|
|
||||||
) {
|
|
||||||
// banner
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(500.dp)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.noRippleClickable {
|
|
||||||
Intent(Intent.ACTION_PICK).apply {
|
|
||||||
type = "image/*"
|
|
||||||
pickBannerImageLauncher.launch(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.shadow(
|
|
||||||
elevation = 4.dp,
|
|
||||||
shape = RoundedCornerShape(
|
|
||||||
bottomStart = 32.dp,
|
|
||||||
bottomEnd = 32.dp
|
|
||||||
)
|
|
||||||
) // 添加阴影
|
|
||||||
|
|
||||||
|
|
||||||
) {
|
|
||||||
val banner = MyProfileViewModel2.profile?.banner
|
|
||||||
|
|
||||||
if (banner != null) {
|
|
||||||
CustomAsyncImage(
|
|
||||||
LocalContext.current,
|
|
||||||
banner,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize(),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_moment_demo_2),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize(),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopEnd)
|
|
||||||
.padding(
|
|
||||||
top = statusBarPaddingValues.calculateTopPadding(),
|
|
||||||
start = 8.dp,
|
|
||||||
end = 8.dp
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(16.dp)
|
|
||||||
.clip(RoundedCornerShape(8.dp))
|
|
||||||
.shadow(
|
|
||||||
elevation = 20.dp
|
|
||||||
)
|
|
||||||
.background(Color.White.copy(alpha = 0.7f))
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
|
||||||
contentDescription = "",
|
|
||||||
modifier = Modifier.noRippleClickable {
|
|
||||||
expanded = true
|
|
||||||
},
|
|
||||||
tint = Color.Black
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
com.aiosman.riderpro.ui.composables.DropdownMenu(
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = { expanded = false },
|
|
||||||
width = 250,
|
|
||||||
menuItems = listOf(
|
|
||||||
MenuItem(
|
|
||||||
stringResource(R.string.logout),
|
|
||||||
R.mipmap.rider_pro_logout
|
|
||||||
) {
|
|
||||||
expanded = false
|
|
||||||
scope.launch {
|
|
||||||
MyProfileViewModel2.logout()
|
|
||||||
navController.navigate(NavigationRoute.Login.route) {
|
|
||||||
popUpTo(NavigationRoute.Index.route) {
|
|
||||||
inclusive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MenuItem(
|
|
||||||
stringResource(R.string.change_password),
|
|
||||||
R.mipmap.rider_pro_change_password
|
|
||||||
) {
|
|
||||||
expanded = false
|
|
||||||
scope.launch {
|
|
||||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MenuItem(
|
|
||||||
stringResource(R.string.favourites),
|
|
||||||
R.drawable.rider_pro_favourite
|
|
||||||
) {
|
|
||||||
expanded = false
|
|
||||||
scope.launch {
|
|
||||||
navController.navigate(NavigationRoute.FavouriteList.route)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
// 个人信息
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.padding(horizontal = 16.dp)
|
|
||||||
) {
|
|
||||||
MyProfileViewModel2.profile?.let {
|
|
||||||
UserItem(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
MyProfileViewModel2.profile?.let {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.padding(horizontal = 16.dp)
|
|
||||||
) {
|
|
||||||
SelfProfileAction {
|
|
||||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
// 动态列表
|
|
||||||
}
|
|
||||||
UserContentTab(nestedScrollConnection)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
PullRefreshIndicator(MyProfileViewModel2.refreshing, state, Modifier.align(Alignment.TopCenter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun UserItem(accountProfileEntity: AccountProfileEntity) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
// 头像
|
|
||||||
CustomAsyncImage(
|
|
||||||
LocalContext.current,
|
|
||||||
accountProfileEntity.avatar,
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(CircleShape)
|
|
||||||
.size(48.dp),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(32.dp))
|
|
||||||
//个人统计
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = accountProfileEntity.followerCount.toString(),
|
|
||||||
fontWeight = FontWeight.W600,
|
|
||||||
fontSize = 16.sp
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.followers_upper),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = accountProfileEntity.followingCount.toString(),
|
|
||||||
fontWeight = FontWeight.W600,
|
|
||||||
fontSize = 16.sp
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.following_upper),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
|
||||||
// 昵称
|
|
||||||
Text(
|
|
||||||
text = accountProfileEntity.nickName,
|
|
||||||
fontWeight = FontWeight.W600,
|
|
||||||
fontSize = 16.sp,
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
// 个人简介
|
|
||||||
Text(
|
|
||||||
text = accountProfileEntity.bio,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
color = Color.Gray
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SelfProfileAction(
|
|
||||||
onEditProfile: () -> Unit
|
|
||||||
) {
|
|
||||||
// 按钮
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(RoundedCornerShape(32.dp))
|
|
||||||
.background(Color(0xffebebeb))
|
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
onEditProfile()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
Icons.Default.Edit,
|
|
||||||
contentDescription = "",
|
|
||||||
modifier = Modifier.size(24.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.edit_profile),
|
|
||||||
fontSize = 14.sp,
|
|
||||||
fontWeight = FontWeight.W600,
|
|
||||||
color = Color.Black,
|
|
||||||
modifier = Modifier.padding(8.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun UserContentTab(nestedScrollConnection: NestedScrollConnection) {
|
|
||||||
val pagerState = rememberPagerState(pageCount = { 2 })
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp),
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(RoundedCornerShape(32.dp))
|
|
||||||
.background(if (pagerState.currentPage == 0) Color(0xFFFFFFFF) else Color.Transparent)
|
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
// switch to gallery
|
|
||||||
scope.launch {
|
|
||||||
pagerState.scrollToPage(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Gallery",
|
|
||||||
fontSize = 14.sp,
|
|
||||||
fontWeight = FontWeight.W600,
|
|
||||||
color = Color.Black,
|
|
||||||
modifier = Modifier.padding(8.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(RoundedCornerShape(32.dp))
|
|
||||||
.background(if (pagerState.currentPage == 1) Color(0xFFFFFFFF) else Color.Transparent)
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
// switch to moments
|
|
||||||
scope.launch {
|
|
||||||
pagerState.scrollToPage(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Moments",
|
|
||||||
fontSize = 16.sp,
|
|
||||||
fontWeight = FontWeight.W600,
|
|
||||||
color = Color.Black,
|
|
||||||
modifier = Modifier.padding(8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
HorizontalPager(
|
|
||||||
state = pagerState,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(0.dp)
|
|
||||||
.height(900.dp),
|
|
||||||
beyondBoundsPageCount = 2,
|
|
||||||
verticalAlignment = Alignment.Top
|
|
||||||
) { page ->
|
|
||||||
when (page) {
|
|
||||||
0 -> Gallery()
|
|
||||||
1 -> MomentsList(nestedScrollConnection)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
|
||||||
@Composable
|
|
||||||
fun Gallery() {
|
|
||||||
val moments = MyProfileViewModel2.sharedFlow.collectAsLazyPagingItems()
|
|
||||||
val screenWidth = LocalConfiguration.current.screenWidthDp.dp
|
|
||||||
val itemWidth = (screenWidth / 2) - 16.dp - 2.dp
|
|
||||||
FlowRow(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(horizontal = 16.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
|
||||||
maxItemsInEachRow = 2,
|
|
||||||
) {
|
|
||||||
for (idx in 0 until moments.itemCount) {
|
|
||||||
val moment = moments[idx]
|
|
||||||
moment?.let {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(itemWidth)
|
|
||||||
.aspectRatio(1f)
|
|
||||||
.background(Color.Gray)
|
|
||||||
) {
|
|
||||||
CustomAsyncImage(
|
|
||||||
LocalContext.current,
|
|
||||||
it.images[0].thumbnail,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize(),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BottomNavigationPlaceholder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MomentsList(nestedScrollConnection: NestedScrollConnection) {
|
|
||||||
val moments = MyProfileViewModel2.sharedFlow.collectAsLazyPagingItems()
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(900.dp).nestedScroll(nestedScrollConnection),
|
|
||||||
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
for (idx in 0 until moments.itemCount) {
|
|
||||||
val moment = moments[idx]
|
|
||||||
moment?.let {
|
|
||||||
MomentPostUnit(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
package com.aiosman.riderpro.ui.index.tabs.profile.v2
|
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun Profile3() {
|
|
||||||
Scaffold(
|
|
||||||
|
|
||||||
) { it
|
|
||||||
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
|
|
||||||
var headHeight by remember { mutableStateOf(400.dp) }
|
|
||||||
val speedFactor = 2 // 调整速度因子
|
|
||||||
// val animatedHeadHeight by animateDpAsState(
|
|
||||||
// targetValue = headHeight,
|
|
||||||
// animationSpec = tween(durationMillis = 0)
|
|
||||||
// )
|
|
||||||
val nestedScrollConnection = remember {
|
|
||||||
object : NestedScrollConnection {
|
|
||||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
|
||||||
val delta = available.y
|
|
||||||
val newHeight = (headHeight + delta.dp).coerceIn(0.dp, 400.dp)
|
|
||||||
headHeight = newHeight
|
|
||||||
return Offset.Zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.nestedScroll(nestedScrollConnection)
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
// head
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(headHeight)
|
|
||||||
.background(Color.DarkGray)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier.fillMaxWidth().height(screenHeight),
|
|
||||||
) {
|
|
||||||
items(100) { idx ->
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(64.dp)
|
|
||||||
.background(Color.Green)
|
|
||||||
) {
|
|
||||||
Text("Item $idx")
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// item {
|
|
||||||
// HorizontalPager(
|
|
||||||
// state = rememberPagerState(pageCount = { 2 }),
|
|
||||||
// modifier = Modifier
|
|
||||||
// .fillMaxWidth()
|
|
||||||
// .height(screenHeight)
|
|
||||||
// ) { page ->
|
|
||||||
// when (page) {
|
|
||||||
// 0 -> {
|
|
||||||
// LazyVerticalGrid(
|
|
||||||
// columns = GridCells.Fixed(2),
|
|
||||||
// verticalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp),
|
|
||||||
// horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp),
|
|
||||||
// modifier = Modifier.fillMaxSize(),
|
|
||||||
//// userScrollEnabled = headHeight < 2.dp
|
|
||||||
// ) {
|
|
||||||
// items(100) { idx ->
|
|
||||||
// Box(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .fillMaxWidth()
|
|
||||||
// .height(64.dp)
|
|
||||||
// ) {
|
|
||||||
// Text("Item $idx")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// 1 -> {
|
|
||||||
// LazyColumn(
|
|
||||||
// modifier = Modifier.fillMaxSize(),
|
|
||||||
//// userScrollEnabled = headHeight < 2.dp
|
|
||||||
// ) {
|
|
||||||
// items(100) { idx ->
|
|
||||||
// Box(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .fillMaxWidth()
|
|
||||||
// .height(64.dp)
|
|
||||||
// .background(Color.Green)
|
|
||||||
// ) {
|
|
||||||
// Text("Item $idx")
|
|
||||||
// }
|
|
||||||
// Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
package com.aiosman.riderpro.ui.index.tabs.profile.v2
|
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun Profile4() {
|
|
||||||
Scaffold(
|
|
||||||
|
|
||||||
) { it
|
|
||||||
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
|
|
||||||
var headHeight by remember { mutableStateOf(400.dp) }
|
|
||||||
val speedFactor = 2 // 调整速度因子
|
|
||||||
// val animatedHeadHeight by animateDpAsState(
|
|
||||||
// targetValue = headHeight,
|
|
||||||
// animationSpec = tween(durationMillis = 0)
|
|
||||||
// )
|
|
||||||
val nestedScrollConnection = remember {
|
|
||||||
object : NestedScrollConnection {
|
|
||||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
|
||||||
val delta = available.y
|
|
||||||
val newHeight = (headHeight + delta.dp).coerceIn(0.dp, 400.dp)
|
|
||||||
headHeight = newHeight
|
|
||||||
return Offset.Zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.nestedScroll(nestedScrollConnection)
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
// head
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(headHeight)
|
|
||||||
.background(Color.DarkGray)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier.fillMaxWidth().height(screenHeight),
|
|
||||||
) {
|
|
||||||
items(100) { idx ->
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(64.dp)
|
|
||||||
.background(Color.Green)
|
|
||||||
) {
|
|
||||||
Text("Item $idx")
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// item {
|
|
||||||
// HorizontalPager(
|
|
||||||
// state = rememberPagerState(pageCount = { 2 }),
|
|
||||||
// modifier = Modifier
|
|
||||||
// .fillMaxWidth()
|
|
||||||
// .height(screenHeight)
|
|
||||||
// ) { page ->
|
|
||||||
// when (page) {
|
|
||||||
// 0 -> {
|
|
||||||
// LazyVerticalGrid(
|
|
||||||
// columns = GridCells.Fixed(2),
|
|
||||||
// verticalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp),
|
|
||||||
// horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp),
|
|
||||||
// modifier = Modifier.fillMaxSize(),
|
|
||||||
//// userScrollEnabled = headHeight < 2.dp
|
|
||||||
// ) {
|
|
||||||
// items(100) { idx ->
|
|
||||||
// Box(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .fillMaxWidth()
|
|
||||||
// .height(64.dp)
|
|
||||||
// ) {
|
|
||||||
// Text("Item $idx")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// 1 -> {
|
|
||||||
// LazyColumn(
|
|
||||||
// modifier = Modifier.fillMaxSize(),
|
|
||||||
//// userScrollEnabled = headHeight < 2.dp
|
|
||||||
// ) {
|
|
||||||
// items(100) { idx ->
|
|
||||||
// Box(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .fillMaxWidth()
|
|
||||||
// .height(64.dp)
|
|
||||||
// .background(Color.Green)
|
|
||||||
// ) {
|
|
||||||
// Text("Item $idx")
|
|
||||||
// }
|
|
||||||
// Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,879 +0,0 @@
|
|||||||
package com.aiosman.riderpro.ui.index.tabs.profile.v2
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.compose.foundation.Canvas
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.systemBars
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.layout.widthIn
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Add
|
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
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.draw.clip
|
|
||||||
import androidx.compose.ui.draw.shadow
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.PathEffect
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.TextStyle
|
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import com.aiosman.riderpro.AppState
|
|
||||||
import com.aiosman.riderpro.LocalNavController
|
|
||||||
import com.aiosman.riderpro.R
|
|
||||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
|
||||||
import com.aiosman.riderpro.entity.MomentEntity
|
|
||||||
import com.aiosman.riderpro.exp.formatPostTime2
|
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
|
||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
|
||||||
import com.aiosman.riderpro.ui.composables.MenuItem
|
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.MyProfileViewModel
|
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
|
||||||
import com.aiosman.riderpro.ui.navigateToChat
|
|
||||||
import com.aiosman.riderpro.ui.navigateToPost
|
|
||||||
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
|
||||||
fun ProfilePage() {
|
|
||||||
val model = MyProfileViewModel2
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
MyProfileViewModel.loadProfile()
|
|
||||||
}
|
|
||||||
val navController: NavController = LocalNavController.current
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val state = rememberPullRefreshState(MyProfileViewModel.refreshing, onRefresh = {
|
|
||||||
MyProfileViewModel.loadProfile(pullRefresh = true)
|
|
||||||
})
|
|
||||||
val context = LocalContext.current
|
|
||||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
|
||||||
val pickBannerImageLauncher = rememberLauncherForActivityResult(
|
|
||||||
contract = ActivityResultContracts.StartActivityForResult()
|
|
||||||
) { result ->
|
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
|
||||||
val uri = result.data?.data
|
|
||||||
uri?.let {
|
|
||||||
MyProfileViewModel.updateUserProfileBanner(it, context = context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(Color(0xFFF5F5F5))
|
|
||||||
.padding(bottom = with(LocalDensity.current) {
|
|
||||||
val da = WindowInsets.navigationBars
|
|
||||||
.getBottom(this)
|
|
||||||
.toDp() + 48.dp
|
|
||||||
da
|
|
||||||
})
|
|
||||||
.pullRefresh(state)
|
|
||||||
) {
|
|
||||||
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(400.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
Intent(Intent.ACTION_PICK).apply {
|
|
||||||
type = "image/*"
|
|
||||||
pickBannerImageLauncher.launch(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
val banner = MyProfileViewModel.profile?.banner
|
|
||||||
|
|
||||||
if (banner != null) {
|
|
||||||
CustomAsyncImage(
|
|
||||||
LocalContext.current,
|
|
||||||
banner,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize(),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_moment_demo_2),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize(),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopEnd)
|
|
||||||
.padding(
|
|
||||||
top = statusBarPaddingValues.calculateTopPadding(),
|
|
||||||
start = 8.dp,
|
|
||||||
end = 8.dp
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(16.dp)
|
|
||||||
.clip(RoundedCornerShape(8.dp))
|
|
||||||
.shadow(
|
|
||||||
elevation = 20.dp
|
|
||||||
)
|
|
||||||
.background(Color.White.copy(alpha = 0.7f))
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
|
||||||
contentDescription = "",
|
|
||||||
modifier = Modifier.noRippleClickable {
|
|
||||||
expanded = true
|
|
||||||
},
|
|
||||||
tint = Color.Black
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
com.aiosman.riderpro.ui.composables.DropdownMenu(
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = { expanded = false },
|
|
||||||
width = 250,
|
|
||||||
menuItems = listOf(
|
|
||||||
MenuItem(
|
|
||||||
stringResource(R.string.logout),
|
|
||||||
R.mipmap.rider_pro_logout
|
|
||||||
) {
|
|
||||||
expanded = false
|
|
||||||
scope.launch {
|
|
||||||
MyProfileViewModel.logout()
|
|
||||||
navController.navigate(NavigationRoute.Login.route) {
|
|
||||||
popUpTo(NavigationRoute.Index.route) {
|
|
||||||
inclusive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MenuItem(
|
|
||||||
stringResource(R.string.change_password),
|
|
||||||
R.mipmap.rider_pro_change_password
|
|
||||||
) {
|
|
||||||
expanded = false
|
|
||||||
scope.launch {
|
|
||||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MenuItem(
|
|
||||||
stringResource(R.string.favourites),
|
|
||||||
R.drawable.rider_pro_favourite
|
|
||||||
) {
|
|
||||||
expanded = false
|
|
||||||
scope.launch {
|
|
||||||
navController.navigate(NavigationRoute.FavouriteList.route)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
MyProfileViewModel.profile?.let {
|
|
||||||
UserInformation(
|
|
||||||
accountProfileEntity = it,
|
|
||||||
onEditProfileClick = {
|
|
||||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// if (moments.itemCount == 0) {
|
|
||||||
// EmptyMomentPostUnit()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// items(moments.itemCount) { idx ->
|
|
||||||
// val momentItem = moments[idx] ?: return@items
|
|
||||||
// MomentPostUnit(momentItem)
|
|
||||||
// }
|
|
||||||
item {
|
|
||||||
Spacer(modifier = Modifier.height(48.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
PullRefreshIndicator(MyProfileViewModel.refreshing, state, Modifier.align(Alignment.TopCenter))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CarGroup() {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 54.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
CarTopInformation()
|
|
||||||
CarTopPicture()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CarTopInformation() {
|
|
||||||
Row {
|
|
||||||
Text(
|
|
||||||
text = "BMW",
|
|
||||||
color = Color.Black,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(start = 4.dp),
|
|
||||||
text = "/",
|
|
||||||
color = Color.Gray,
|
|
||||||
fontSize = 12.sp
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(start = 4.dp),
|
|
||||||
text = "M1000RR",
|
|
||||||
color = Color.Gray,
|
|
||||||
fontSize = 12.sp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CarTopPicture() {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 336.dp, height = 224.dp)
|
|
||||||
.padding(top = 42.dp),
|
|
||||||
painter = painterResource(id = R.drawable.default_profile_moto), contentDescription = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun UserInformation(
|
|
||||||
isSelf: Boolean = true,
|
|
||||||
accountProfileEntity: AccountProfileEntity,
|
|
||||||
onFollowClick: () -> Unit = {},
|
|
||||||
onEditProfileClick: () -> Unit = {}
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 8.dp, start = 33.dp, end = 33.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Row(modifier = Modifier.fillMaxWidth()) {
|
|
||||||
val userInfoModifier = Modifier.weight(1f)
|
|
||||||
UserInformationFollowers(userInfoModifier, accountProfileEntity)
|
|
||||||
UserInformationBasic(userInfoModifier, accountProfileEntity)
|
|
||||||
UserInformationFollowing(userInfoModifier, accountProfileEntity)
|
|
||||||
}
|
|
||||||
UserInformationSlogan(accountProfileEntity)
|
|
||||||
CommunicationOperatorGroup(
|
|
||||||
isSelf = isSelf,
|
|
||||||
isFollowing = accountProfileEntity.isFollowing,
|
|
||||||
onFollowClick = onFollowClick,
|
|
||||||
onEditProfileClick = onEditProfileClick,
|
|
||||||
accountProfileEntity = accountProfileEntity
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun UserInformationFollowers(modifier: Modifier, accountProfileEntity: AccountProfileEntity) {
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
Column(modifier = modifier.padding(top = 31.dp)) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(bottom = 5.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
navController.navigate(
|
|
||||||
NavigationRoute.FollowerList.route.replace(
|
|
||||||
"{id}",
|
|
||||||
accountProfileEntity.id.toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
text = accountProfileEntity.followerCount.toString(),
|
|
||||||
fontSize = 24.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontStyle = FontStyle.Italic, fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
Canvas(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 88.83.dp, height = 1.dp)
|
|
||||||
.padding(top = 2.dp, bottom = 5.dp)
|
|
||||||
) {
|
|
||||||
drawLine(
|
|
||||||
color = Color(0xFFCCCCCC),
|
|
||||||
start = Offset(0f, 0f),
|
|
||||||
end = Offset(size.width, 0f),
|
|
||||||
strokeWidth = 1f,
|
|
||||||
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(top = 5.dp),
|
|
||||||
text = stringResource(R.string.followers_upper),
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun UserInformationBasic(modifier: Modifier, accountProfileEntity: AccountProfileEntity) {
|
|
||||||
val context = LocalContext.current
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.size(width = 112.dp, height = 112.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
painter = painterResource(id = R.drawable.avatar_bold), contentDescription = ""
|
|
||||||
)
|
|
||||||
CustomAsyncImage(
|
|
||||||
context,
|
|
||||||
accountProfileEntity.avatar,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 88.dp, height = 88.dp)
|
|
||||||
.clip(
|
|
||||||
RoundedCornerShape(88.dp)
|
|
||||||
),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.widthIn(max = 220.dp)
|
|
||||||
.padding(top = 8.dp),
|
|
||||||
text = accountProfileEntity.nickName,
|
|
||||||
fontSize = 32.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold),
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(top = 4.dp),
|
|
||||||
text = accountProfileEntity.country,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = Color.Gray
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun UserInformationFollowing(modifier: Modifier, accountProfileEntity: AccountProfileEntity) {
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
Column(
|
|
||||||
modifier = modifier.padding(top = 6.dp),
|
|
||||||
horizontalAlignment = Alignment.End
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(bottom = 5.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
navController.navigate(
|
|
||||||
NavigationRoute.FollowingList.route.replace(
|
|
||||||
"{id}",
|
|
||||||
accountProfileEntity.id.toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
text = accountProfileEntity.followingCount.toString(),
|
|
||||||
fontSize = 24.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontStyle = FontStyle.Italic, fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
Canvas(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 88.83.dp, height = 1.dp)
|
|
||||||
.padding(top = 2.dp, bottom = 5.dp)
|
|
||||||
) {
|
|
||||||
drawLine(
|
|
||||||
color = Color(0xFFCCCCCC),
|
|
||||||
start = Offset(0f, 0f),
|
|
||||||
end = Offset(size.width, 0f),
|
|
||||||
strokeWidth = 1f,
|
|
||||||
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(top = 5.dp),
|
|
||||||
text = stringResource(R.string.following_upper),
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun UserInformationSlogan(accountProfileEntity: AccountProfileEntity) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(top = 23.dp),
|
|
||||||
text = accountProfileEntity.bio,
|
|
||||||
fontSize = 13.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CommunicationOperatorGroup(
|
|
||||||
accountProfileEntity: AccountProfileEntity,
|
|
||||||
isSelf: Boolean = true,
|
|
||||||
isFollowing: Boolean = false,
|
|
||||||
onFollowClick: () -> Unit = {},
|
|
||||||
onEditProfileClick: () -> Unit = {}
|
|
||||||
) {
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 16.dp), horizontalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
if (!isSelf && AppState.UserId != accountProfileEntity.id) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 142.dp, height = 40.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
onFollowClick()
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
painter = if (isFollowing) painterResource(id = R.mipmap.rider_pro_follow_grey) else painterResource(
|
|
||||||
id = R.mipmap.rider_pro_follow_red
|
|
||||||
),
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = if (isFollowing) stringResource(R.string.following_upper) else stringResource(
|
|
||||||
R.string.follow_upper
|
|
||||||
),
|
|
||||||
fontSize = 14.sp,
|
|
||||||
color = if (isFollowing) Color.Black else Color.White,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.W600, fontStyle = FontStyle.Italic),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 142.dp, height = 40.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
navController.navigateToChat(accountProfileEntity.id.toString())
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
painter = painterResource(id = R.mipmap.rider_pro_btn_bg_grey),
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "CHAT",
|
|
||||||
fontSize = 14.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSelf) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 142.dp, height = 40.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
onEditProfileClick()
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
painter = painterResource(id = R.mipmap.rider_pro_btn_bg_grey),
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.edit_profile),
|
|
||||||
fontSize = 14.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
|
||||||
@Composable
|
|
||||||
fun RidingStyle() {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(start = 24.dp, top = 40.dp, end = 24.dp),
|
|
||||||
horizontalAlignment = Alignment.Start
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "RIDING STYLES",
|
|
||||||
fontSize = 18.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
Image(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 4.dp)
|
|
||||||
.height(8.dp),
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_profile_line),
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
|
||||||
FlowRow(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 24.dp)
|
|
||||||
) {
|
|
||||||
RidingStyleItem(styleContent = "Cruiser")
|
|
||||||
RidingStyleItem(styleContent = "Bobber")
|
|
||||||
RidingStyleItem(styleContent = "Cafe")
|
|
||||||
RidingStyleItem(styleContent = "Chopper")
|
|
||||||
RidingStyleItem(styleContent = "Sport")
|
|
||||||
RidingStyleItem(styleContent = "Vintage")
|
|
||||||
RidingStyleItem(styleContent = "Trike")
|
|
||||||
RidingStyleItem(styleContent = "Touring")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RidingStyleItem(styleContent: String) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp, end = 8.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.shadow(
|
|
||||||
ambientColor = Color.Gray,
|
|
||||||
spotColor = Color(0f, 0f, 0f, 0.2f),
|
|
||||||
elevation = 20.dp,
|
|
||||||
),
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_style_wrapper),
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(start = 5.dp, end = 5.dp),
|
|
||||||
text = styleContent,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = Color.Gray,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun EmptyMomentPostUnit() {
|
|
||||||
TimeGroup(stringResource(R.string.empty_my_post_title))
|
|
||||||
ProfileEmptyMomentCard()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ProfileEmptyMomentCard(
|
|
||||||
|
|
||||||
) {
|
|
||||||
var columnHeight by remember { mutableStateOf(0) }
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(start = 24.dp, top = 18.dp, end = 24.dp)
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Canvas(
|
|
||||||
modifier = Modifier
|
|
||||||
.height(with(LocalDensity.current) { columnHeight.toDp() })
|
|
||||||
.width(14.dp)
|
|
||||||
) {
|
|
||||||
drawLine(
|
|
||||||
color = Color(0xff899DA9),
|
|
||||||
start = Offset(0f, 0f),
|
|
||||||
end = Offset(0f, size.height),
|
|
||||||
strokeWidth = 4f,
|
|
||||||
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.onGloballyPositioned { coordinates ->
|
|
||||||
columnHeight = coordinates.size.height
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.empty_my_post_content), fontSize = 16.sp)
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.aspectRatio(3f / 2f)
|
|
||||||
.background(Color.White)
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(Color(0xFFF5F5F5))
|
|
||||||
.noRippleClickable {
|
|
||||||
NewPostViewModel.asNewPost()
|
|
||||||
navController.navigate(NavigationRoute.NewPost.route)
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
Icons.Default.Add,
|
|
||||||
tint = Color(0xFFD8D8D8),
|
|
||||||
contentDescription = "New post",
|
|
||||||
modifier = Modifier
|
|
||||||
.size(32.dp)
|
|
||||||
.align(Alignment.Center)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MomentPostUnit(momentEntity: MomentEntity) {
|
|
||||||
TimeGroup(momentEntity.time.formatPostTime2())
|
|
||||||
ProfileMomentCard(
|
|
||||||
momentEntity.momentTextContent,
|
|
||||||
momentEntity.images[0].thumbnail,
|
|
||||||
momentEntity.likeCount.toString(),
|
|
||||||
momentEntity.commentCount.toString(),
|
|
||||||
momentEntity = momentEntity
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TimeGroup(time: String = "2024.06.08 12:23") {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(start = 24.dp, top = 40.dp, end = 24.dp),
|
|
||||||
horizontalArrangement = Arrangement.Start,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier
|
|
||||||
.height(16.dp)
|
|
||||||
.width(14.dp),
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_moment_time_flag),
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
|
||||||
Text(
|
|
||||||
text = time,
|
|
||||||
fontSize = 16.sp,
|
|
||||||
color = Color.Black,
|
|
||||||
style = TextStyle(fontWeight = FontWeight.W600)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ProfileMomentCard(
|
|
||||||
content: String,
|
|
||||||
imageUrl: String,
|
|
||||||
like: String,
|
|
||||||
comment: String,
|
|
||||||
momentEntity: MomentEntity
|
|
||||||
) {
|
|
||||||
var columnHeight by remember { mutableStateOf(0) }
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(start = 24.dp, top = 18.dp, end = 24.dp)
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Canvas(
|
|
||||||
modifier = Modifier
|
|
||||||
.height(with(LocalDensity.current) { columnHeight.toDp() })
|
|
||||||
.width(14.dp)
|
|
||||||
) {
|
|
||||||
drawLine(
|
|
||||||
color = Color(0xff899DA9),
|
|
||||||
start = Offset(0f, 0f),
|
|
||||||
end = Offset(0f, size.height),
|
|
||||||
strokeWidth = 4f,
|
|
||||||
pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f), 0f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.background(Color.White)
|
|
||||||
.weight(1f)
|
|
||||||
.onGloballyPositioned { coordinates ->
|
|
||||||
columnHeight = coordinates.size.height
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
if (content.isNotEmpty()) {
|
|
||||||
MomentCardTopContent(content)
|
|
||||||
}
|
|
||||||
MomentCardPicture(imageUrl, momentEntity = momentEntity)
|
|
||||||
MomentCardOperation(like, comment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MomentCardTopContent(content: String) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.Start,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(top = 16.dp, bottom = 0.dp, start = 16.dp, end = 16.dp),
|
|
||||||
text = content, fontSize = 16.sp, color = Color.Black
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) {
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
val context = LocalContext.current
|
|
||||||
CustomAsyncImage(
|
|
||||||
context,
|
|
||||||
imageUrl,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.aspectRatio(3f / 2f)
|
|
||||||
.padding(top = 16.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
navController.navigateToPost(
|
|
||||||
id = momentEntity.id,
|
|
||||||
highlightCommentId = 0,
|
|
||||||
initImagePagerIndex = 0
|
|
||||||
)
|
|
||||||
},
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MomentCardOperation(like: String, comment: String) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(48.dp),
|
|
||||||
horizontalArrangement = Arrangement.End,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
// Spacer(modifier = Modifier.weight(1f))
|
|
||||||
MomentCardOperationItem(
|
|
||||||
drawable = R.drawable.rider_pro_like,
|
|
||||||
number = like,
|
|
||||||
modifier = Modifier.padding(end = 32.dp)
|
|
||||||
)
|
|
||||||
MomentCardOperationItem(
|
|
||||||
drawable = R.drawable.rider_pro_moment_comment,
|
|
||||||
number = comment,
|
|
||||||
modifier = Modifier.padding(end = 32.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MomentCardOperationItem(@DrawableRes drawable: Int, number: String, modifier: Modifier) {
|
|
||||||
Row(
|
|
||||||
modifier = modifier,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
modifier = Modifier.padding(start = 16.dp, end = 8.dp),
|
|
||||||
painter = painterResource(id = drawable), contentDescription = ""
|
|
||||||
)
|
|
||||||
Text(text = number)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -38,6 +38,7 @@ import com.aiosman.riderpro.ui.NavigationRoute
|
|||||||
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||||
import com.aiosman.riderpro.ui.composables.ActionButton
|
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||||
import com.aiosman.riderpro.ui.composables.CheckboxWithLabel
|
import com.aiosman.riderpro.ui.composables.CheckboxWithLabel
|
||||||
|
import com.aiosman.riderpro.ui.composables.PolicyCheckbox
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.riderpro.ui.composables.TextInputField
|
import com.aiosman.riderpro.ui.composables.TextInputField
|
||||||
import com.aiosman.riderpro.utils.Utils
|
import com.aiosman.riderpro.utils.Utils
|
||||||
@@ -241,15 +242,21 @@ fun EmailSignupScreen() {
|
|||||||
rememberMe = it
|
rememberMe = it
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
CheckboxWithLabel(
|
PolicyCheckbox(
|
||||||
checked = acceptTerms,
|
checked = acceptTerms,
|
||||||
checkSize = 16,
|
|
||||||
fontSize = 12,
|
|
||||||
label = stringResource(R.string.agree_terms_of_service),
|
|
||||||
error = termsError
|
error = termsError
|
||||||
) {
|
) {
|
||||||
acceptTerms = it
|
acceptTerms = it
|
||||||
}
|
}
|
||||||
|
// CheckboxWithLabel(
|
||||||
|
// checked = acceptTerms,
|
||||||
|
// checkSize = 16,
|
||||||
|
// fontSize = 12,
|
||||||
|
// label = stringResource(R.string.agree_terms_of_service),
|
||||||
|
// error = termsError
|
||||||
|
// ) {
|
||||||
|
// acceptTerms = it
|
||||||
|
// }
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
CheckboxWithLabel(
|
CheckboxWithLabel(
|
||||||
checked = acceptPromotions,
|
checked = acceptPromotions,
|
||||||
@@ -263,17 +270,23 @@ fun EmailSignupScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(64.dp))
|
Spacer(modifier = Modifier.height(64.dp))
|
||||||
ActionButton(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxWidth(),
|
||||||
.width(345.dp)
|
contentAlignment = Alignment.Center
|
||||||
.height(48.dp),
|
|
||||||
text = stringResource(R.string.lets_ride_upper),
|
|
||||||
backgroundImage = R.mipmap.rider_pro_signup_red_bg
|
|
||||||
) {
|
) {
|
||||||
scope.launch(Dispatchers.IO) {
|
ActionButton(
|
||||||
registerUser()
|
modifier = Modifier
|
||||||
|
.width(345.dp)
|
||||||
|
.height(48.dp),
|
||||||
|
text = stringResource(R.string.lets_ride_upper),
|
||||||
|
backgroundImage = R.mipmap.rider_pro_signup_red_bg
|
||||||
|
) {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
registerUser()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,155 +0,0 @@
|
|||||||
package com.aiosman.riderpro.ui.profile
|
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
|
||||||
import com.aiosman.riderpro.LocalNavController
|
|
||||||
import com.aiosman.riderpro.R
|
|
||||||
import com.aiosman.riderpro.exp.viewModelFactory
|
|
||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.v2.MomentPostUnit
|
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.v2.UserInformation
|
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
|
||||||
fun AccountProfile(id: String) {
|
|
||||||
val model: AccountProfileViewModel = viewModel(factory = viewModelFactory {
|
|
||||||
AccountProfileViewModel()
|
|
||||||
}, key = "viewModel_${id}")
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val items = model.momentsFlow.collectAsLazyPagingItems()
|
|
||||||
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
|
|
||||||
model.loadProfile(id, pullRefresh = true)
|
|
||||||
})
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
model.loadProfile(id)
|
|
||||||
}
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.pullRefresh(state)
|
|
||||||
.background(Color(0xFFF5F5F5))
|
|
||||||
) {
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize(),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.Top,
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(400.dp)
|
|
||||||
|
|
||||||
) {
|
|
||||||
if (model.profile != null) {
|
|
||||||
val banner = model.profile?.banner
|
|
||||||
if (banner != null) {
|
|
||||||
CustomAsyncImage(
|
|
||||||
LocalContext.current,
|
|
||||||
banner,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_moment_demo_2),
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentDescription = "",
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
StatusBarSpacer()
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp, horizontal = 18.dp)
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_nav_back),
|
|
||||||
contentDescription = "",
|
|
||||||
modifier = Modifier
|
|
||||||
.size(24.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
navController.popBackStack()
|
|
||||||
},
|
|
||||||
colorFilter = ColorFilter.tint(Color.White)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
model.profile?.let {
|
|
||||||
UserInformation(
|
|
||||||
isSelf = false,
|
|
||||||
accountProfileEntity = it,
|
|
||||||
onFollowClick = {
|
|
||||||
scope.launch {
|
|
||||||
if (it.isFollowing) {
|
|
||||||
model.unFollowUser(id)
|
|
||||||
} else {
|
|
||||||
model.followUser(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// RidingStyle()
|
|
||||||
}
|
|
||||||
|
|
||||||
items(items.itemCount) { idx ->
|
|
||||||
val momentItem = items[idx] ?: return@items
|
|
||||||
MomentPostUnit(momentItem)
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.aiosman.riderpro.ui.profile
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.aiosman.riderpro.LocalNavController
|
||||||
|
import com.aiosman.riderpro.exp.viewModelFactory
|
||||||
|
import com.aiosman.riderpro.ui.index.tabs.profile.Profile
|
||||||
|
import com.aiosman.riderpro.ui.navigateToChat
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AccountProfileV2(id: String){
|
||||||
|
val model: AccountProfileViewModel = viewModel(factory = viewModelFactory {
|
||||||
|
AccountProfileViewModel()
|
||||||
|
}, key = "viewModel_${id}")
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
model.loadProfile(id)
|
||||||
|
}
|
||||||
|
Profile(
|
||||||
|
sharedFlow = model.momentsFlow,
|
||||||
|
profile = model.profile,
|
||||||
|
isSelf = false,
|
||||||
|
onChatClick = {
|
||||||
|
model.profile?.let {
|
||||||
|
navController.navigateToChat(it.id.toString())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFollowClick = {
|
||||||
|
model.profile?.let {
|
||||||
|
if (it.isFollowing) {
|
||||||
|
model.unFollowUser(id)
|
||||||
|
} else {
|
||||||
|
model.followUser(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
class AccountProfileViewModel : ViewModel() {
|
class AccountProfileViewModel : ViewModel() {
|
||||||
var profileId by mutableStateOf(0)
|
var profileId by mutableStateOf(0)
|
||||||
val accountService: AccountService = AccountServiceImpl()
|
val accountService: AccountService = AccountServiceImpl()
|
||||||
|
|||||||
Reference in New Issue
Block a user