更新个人资料编辑功能
- 新增主页背景图编辑 - 优化个人资料编辑页面布局
This commit is contained in:
@@ -90,7 +90,5 @@ dependencies {
|
||||
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
|
||||
implementation("androidx.credentials:credentials:1.2.2")
|
||||
implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,11 @@ data class AccountProfile(
|
||||
// 粉丝数
|
||||
val followerCount: Int,
|
||||
// 是否关注
|
||||
val isFollowing: Boolean
|
||||
val isFollowing: Boolean,
|
||||
// 个人简介
|
||||
val bio: String,
|
||||
// 主页背景图
|
||||
val banner: String?,
|
||||
) {
|
||||
/**
|
||||
* 转换为Entity
|
||||
@@ -48,9 +52,10 @@ data class AccountProfile(
|
||||
followingCount = followingCount,
|
||||
nickName = nickname,
|
||||
avatar = "${ApiClient.BASE_SERVER}$avatar",
|
||||
bio = "",
|
||||
bio = bio,
|
||||
country = "Worldwide",
|
||||
isFollowing = isFollowing
|
||||
isFollowing = isFollowing,
|
||||
banner = "${ApiClient.BASE_SERVER}$banner"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -230,8 +235,14 @@ interface AccountService {
|
||||
* @param avatar 头像
|
||||
* @param nickName 昵称
|
||||
* @param bio 简介
|
||||
* @param banner 主页背景图
|
||||
*/
|
||||
suspend fun updateProfile(avatar: UploadImage?, nickName: String?, bio: String?)
|
||||
suspend fun updateProfile(
|
||||
avatar: UploadImage?,
|
||||
banner: UploadImage?,
|
||||
nickName: String?,
|
||||
bio: String?
|
||||
)
|
||||
|
||||
/**
|
||||
* 注册用户
|
||||
@@ -328,12 +339,21 @@ class AccountServiceImpl : AccountService {
|
||||
return MultipartBody.Part.createFormData(name, filename, requestFile)
|
||||
}
|
||||
|
||||
override suspend fun updateProfile(avatar: UploadImage?, nickName: String?, bio: String?) {
|
||||
override suspend fun updateProfile(
|
||||
avatar: UploadImage?,
|
||||
banner: UploadImage?,
|
||||
nickName: String?,
|
||||
bio: String?
|
||||
) {
|
||||
val nicknameField: RequestBody? = nickName?.toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val bioField: RequestBody? = bio?.toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val avatarField: MultipartBody.Part? = avatar?.let {
|
||||
createMultipartBody(it.file, it.filename, "avatar")
|
||||
}
|
||||
ApiClient.api.updateProfile(avatarField, nicknameField)
|
||||
val bannerField: MultipartBody.Part? = banner?.let {
|
||||
createMultipartBody(it.file, it.filename, "banner")
|
||||
}
|
||||
ApiClient.api.updateProfile(avatarField, bannerField, nicknameField, bioField)
|
||||
}
|
||||
|
||||
override suspend fun registerUserWithPassword(loginName: String, password: String) {
|
||||
|
||||
@@ -169,7 +169,9 @@ interface RiderProAPI {
|
||||
@PATCH("account/my/profile")
|
||||
suspend fun updateProfile(
|
||||
@Part avatar: MultipartBody.Part?,
|
||||
@Part banner: MultipartBody.Part?,
|
||||
@Part("nickname") nickname: RequestBody?,
|
||||
@Part("bio") bio: RequestBody?,
|
||||
): Response<Unit>
|
||||
|
||||
@POST("account/my/password")
|
||||
|
||||
@@ -52,7 +52,9 @@ data class AccountProfileEntity(
|
||||
// 国家
|
||||
val country: String,
|
||||
// 是否关注,针对当前登录用户
|
||||
val isFollowing: Boolean
|
||||
val isFollowing: Boolean,
|
||||
// 主页背景图
|
||||
val banner: String?,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -33,12 +34,11 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.data.UploadImage
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.ui.post.NewPostViewModel.uriToFile
|
||||
@@ -54,11 +54,13 @@ fun AccountEditScreen() {
|
||||
var name by remember { mutableStateOf("") }
|
||||
var bio by remember { mutableStateOf("") }
|
||||
var imageUrl by remember { mutableStateOf<Uri?>(null) }
|
||||
var bannerImageUrl by remember { mutableStateOf<Uri?>(null) }
|
||||
var profile by remember {
|
||||
mutableStateOf<AccountProfileEntity?>(
|
||||
null
|
||||
)
|
||||
}
|
||||
val navController = LocalNavController.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
|
||||
@@ -71,8 +73,6 @@ fun AccountEditScreen() {
|
||||
name = it.nickName
|
||||
bio = it.bio
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun updateUserProfile() {
|
||||
@@ -93,10 +93,31 @@ fun AccountEditScreen() {
|
||||
}
|
||||
newAvatar
|
||||
}
|
||||
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
|
||||
}
|
||||
val newName = if (name == profile?.nickName) null else name
|
||||
|
||||
accountService.updateProfile(newAvatar, newName, bio)
|
||||
accountService.updateProfile(
|
||||
avatar = newAvatar,
|
||||
banner = newBanner,
|
||||
nickName = newName,
|
||||
bio = bio
|
||||
)
|
||||
reloadProfile()
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,11 +131,20 @@ fun AccountEditScreen() {
|
||||
}
|
||||
}
|
||||
}
|
||||
val pickBannerImageLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val uri = result.data?.data
|
||||
uri?.let {
|
||||
bannerImageUrl = uri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
reloadProfile()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -161,6 +191,26 @@ fun AccountEditScreen() {
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
CustomAsyncImage(
|
||||
context,
|
||||
if (bannerImageUrl != null) {
|
||||
bannerImageUrl.toString()
|
||||
} else {
|
||||
it.banner
|
||||
},
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(200.dp)
|
||||
.noRippleClickable {
|
||||
Intent(Intent.ACTION_PICK).apply {
|
||||
type = "image/*"
|
||||
pickBannerImageLauncher.launch(this)
|
||||
}
|
||||
},
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
TextField(
|
||||
value = name,
|
||||
onValueChange = {
|
||||
|
||||
@@ -115,9 +115,10 @@ fun IndexScreen() {
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
innerPadding
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
modifier = Modifier.padding(0.dp),
|
||||
beyondBoundsPageCount = 5,
|
||||
userScrollEnabled = false
|
||||
) { page ->
|
||||
|
||||
@@ -7,11 +7,14 @@ 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.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
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.layout.systemBars
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@@ -51,6 +54,8 @@ fun NotificationsScreen() {
|
||||
val systemUiController = rememberSystemUiController()
|
||||
var dataFlow = MessageListViewModel.commentItemsFlow
|
||||
var comments = dataFlow.collectAsLazyPagingItems()
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
||||
MessageListViewModel.initData()
|
||||
@@ -59,6 +64,7 @@ fun NotificationsScreen() {
|
||||
modifier = Modifier.fillMaxSize()
|
||||
|
||||
) {
|
||||
Spacer(modifier = Modifier.padding(statusBarPaddingValues.calculateTopPadding()))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Column
|
||||
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.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
@@ -21,6 +22,7 @@ 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.layout.systemBars
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -100,44 +102,52 @@ fun MomentsList() {
|
||||
refreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
Box(Modifier.pullRefresh(state)) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
items(
|
||||
moments.itemCount,
|
||||
key = { idx -> moments[idx]?.id ?: idx }
|
||||
) { idx ->
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
MomentCard(momentEntity = momentItem,
|
||||
onAddComment = {
|
||||
scope.launch {
|
||||
model.onAddComment(momentItem.id)
|
||||
}
|
||||
},
|
||||
onLikeClick = {
|
||||
scope.launch {
|
||||
if (momentItem.liked) {
|
||||
model.dislikeMoment(momentItem.id)
|
||||
} else {
|
||||
model.likeMoment(momentItem.id)
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(
|
||||
top = statusBarPaddingValues.calculateTopPadding(),
|
||||
)
|
||||
) {
|
||||
Box(Modifier.pullRefresh(state)) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
items(
|
||||
moments.itemCount,
|
||||
key = { idx -> moments[idx]?.id ?: idx }
|
||||
) { idx ->
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
MomentCard(momentEntity = momentItem,
|
||||
onAddComment = {
|
||||
scope.launch {
|
||||
model.onAddComment(momentItem.id)
|
||||
}
|
||||
},
|
||||
onLikeClick = {
|
||||
scope.launch {
|
||||
if (momentItem.liked) {
|
||||
model.dislikeMoment(momentItem.id)
|
||||
} else {
|
||||
model.likeMoment(momentItem.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFavoriteClick = {
|
||||
scope.launch {
|
||||
if (momentItem.isFavorite) {
|
||||
model.unfavoriteMoment(momentItem.id)
|
||||
} else {
|
||||
model.favoriteMoment(momentItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onFavoriteClick = {
|
||||
scope.launch {
|
||||
if (momentItem.isFavorite) {
|
||||
model.unfavoriteMoment(momentItem.id)
|
||||
} else {
|
||||
model.favoriteMoment(momentItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||
}
|
||||
PullRefreshIndicator(refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ package com.aiosman.riderpro.ui.index.tabs.profile
|
||||
import android.util.Log
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -12,12 +14,15 @@ 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.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
@@ -75,67 +80,92 @@ fun ProfilePage() {
|
||||
val moments = model.momentsFlow.collectAsLazyPagingItems()
|
||||
val navController: NavController = LocalNavController.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
.fillMaxSize()
|
||||
) {
|
||||
item {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
) {
|
||||
val banner = model.profile?.banner
|
||||
if (banner != null) {
|
||||
CustomAsyncImage(
|
||||
LocalContext.current,
|
||||
banner,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(400.dp),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(400.dp)
|
||||
.background(Color.Gray)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.align(Alignment.TopEnd)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.noRippleClickable {
|
||||
expanded = true
|
||||
}
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(
|
||||
top = statusBarPaddingValues.calculateTopPadding(),
|
||||
start = 16.dp,
|
||||
end = 16.dp
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
DropdownMenuItem(onClick = {
|
||||
scope.launch {
|
||||
model.logout()
|
||||
navController.navigate(NavigationRoute.Login.route) {
|
||||
popUpTo(NavigationRoute.Index.route) {
|
||||
inclusive = true
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.noRippleClickable {
|
||||
expanded = true
|
||||
}
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
DropdownMenuItem(onClick = {
|
||||
scope.launch {
|
||||
model.logout()
|
||||
navController.navigate(NavigationRoute.Login.route) {
|
||||
popUpTo(NavigationRoute.Index.route) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
}, text = {
|
||||
Text("Logout")
|
||||
})
|
||||
DropdownMenuItem(onClick = {
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
||||
}
|
||||
}, text = {
|
||||
Text("Edit")
|
||||
})
|
||||
DropdownMenuItem(onClick = {
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
||||
}
|
||||
}, text = {
|
||||
Text("Change password")
|
||||
})
|
||||
}
|
||||
}
|
||||
}, text = {
|
||||
Text("Logout")
|
||||
})
|
||||
DropdownMenuItem(onClick = {
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
||||
}
|
||||
}, text = {
|
||||
Text("Edit")
|
||||
})
|
||||
DropdownMenuItem(onClick = {
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
||||
}
|
||||
}, text = {
|
||||
Text("Change password")
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
CarGroup()
|
||||
model.profile?.let {
|
||||
UserInformation(accountProfileEntity = it)
|
||||
}
|
||||
// RidingStyle()
|
||||
}
|
||||
// CarGroup()
|
||||
|
||||
model.profile?.let {
|
||||
UserInformation(accountProfileEntity = it)
|
||||
}
|
||||
// RidingStyle()
|
||||
}
|
||||
|
||||
items(moments.itemCount) { idx ->
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
|
||||
@@ -6,10 +6,14 @@ 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.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
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.layout.systemBars
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
@@ -63,6 +67,8 @@ fun SearchScreen() {
|
||||
val selectedTabIndex = remember { derivedStateOf { pagerState.currentPage } }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = true)
|
||||
}
|
||||
@@ -72,6 +78,7 @@ fun SearchScreen() {
|
||||
.fillMaxSize()
|
||||
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(statusBarPaddingValues.calculateTopPadding()))
|
||||
SearchInput(
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 16.dp, start = 24.dp, end = 24.dp),
|
||||
text = model.searchText,
|
||||
|
||||
Reference in New Issue
Block a user