这是我的视图模型
@HiltViewModel
class galBaatviewModel @Inject constructor(
val auth: FirebaseAuth,
var db : FirebaseFirestore,
val storage : FirebaseStorage
) : ViewModel() {
var inProcess = mutableStateOf(false)
val eventMutableState = mutableStateOf<Event<String>?>(null)
var signIn = mutableStateOf(false)
val userData = mutableStateOf<UserData?>(null)
init {
val currentUser = auth.currentUser
signIn.value = currentUser!= null
currentUser?.uid?.let {
getUserData(it)
}
}
fun signUp(name: String, number: String, email: String, Password: String) {
inProcess.value = true
if(name.isEmpty() or number.isEmpty() or email.isEmpty() or Password.isEmpty()){
HandleException(customMessage = "Please fill all fields")
return
}
inProcess.value = true
db.collection(USER_NODE).whereEqualTo("number",number).get().addOnSuccessListener {
if(it.isEmpty){
auth.createUserWithEmailAndPassword(email, Password).addOnCompleteListener {
if (it.isSuccessful) {
signIn.value = true
createOrUpdateProfile(name,number)
} else {
HandleException(it.exception, customMessage = "Sign Up failed")
}
}
}
else{
HandleException(customMessage = "number already exist")
inProcess.value = false
}
}
}
fun LogIn(email: String,Password: String){
if(email.isEmpty() or Password.isEmpty()){
HandleException(customMessage = "Please fill all the fields")
}
else{
inProcess.value = true
auth.signInWithEmailAndPassword(email,Password).addOnCompleteListener {
if(it.isSuccessful){
signIn.value = true
inProcess.value = false
auth.currentUser?.uid?.let {
getUserData(it)
}
}else{
HandleException(exception = it.exception, customMessage = "Login failed")
}
}
}
}
fun uploadProfileImage(uri : Uri){
uploadImage(uri){
createOrUpdateProfile(imageUrl = it.toString())
}
}
fun uploadImage(uri: Uri,onSuccess: (Uri)->Unit){
inProcess.value = true
val storageRef = storage.reference
val uuid = UUID.randomUUID()
val imageRef = storageRef.child("images/$uuid")
val uploadTask = imageRef.putFile(uri)
uploadTask.addOnSuccessListener {
val result = it.metadata?.reference?.downloadUrl
result?.addOnSuccessListener(onSuccess)
inProcess.value = false
}
.addOnFailureListener{
HandleException(it)
}
}
fun createOrUpdateProfile(name: String?=null,number: String?=null,imageUrl:String?=null){
var uid=auth.currentUser?.uid
val userData =UserData(
userId = uid,
name = name?:userData.value?.name,
number = number?: userData.value?.number,
imageUrl = imageUrl?: userData.value?.imageUrl
)
uid?.let{
inProcess.value = true
db.collection(USER_NODE).document(uid).get().addOnSuccessListener {
if(it.exists()){
//update user data
}
else{
db.collection(USER_NODE).document(uid).set(userData)
inProcess.value = false
getUserData(uid )
}
}
.addOnFailureListener{
HandleException(it, "cannot retrieve user")
}
}
}
private fun getUserData(uid: String) {
inProcess.value = true
db.collection(USER_NODE).document(uid).addSnapshotListener{
value, error->
if(error!= null){
HandleException(error,"can not retrieve user")
}
if(value != null){
var user = value.toObject<UserData>()
userData.value = user
inProcess.value = false
}
}
}
fun HandleException(exception: Exception? = null, customMessage: String = "") {
Log.e("GalBaat", "GalBaat exception: ", exception)
exception?.printStackTrace()
val errorMsg = exception?.localizedMessage ?: ""
val message = if (customMessage.isNullOrEmpty()) errorMsg else customMessage
eventMutableState.value = Event(message)
inProcess.value = false
}
}
这是我的个人资料屏幕代码
package com.example.galbaat.screen
@Composable
fun ProfileScreen(navController: NavController,vm : galBaatviewModel) {
val inProgress = vm.inProcess.value
if(inProgress){
CommonProgressBar()
}else{
Column {
ProfileContent(
modifier = Modifier
.weight(1f)
.verticalScroll(rememberScrollState())
.padding(8.dp),
vm =vm,
name = "",
number = "",
onNameChange = {""},
onNumberChange = {""},
onSave = {},
onBack = {},
onLogOut ={}
)
BottomNavigationMenu(selectedItem = BottomNavigationItem.PROFILE, navController = navController)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProfileContent(
vm: galBaatviewModel,
name: String,
number:String,
onNameChange:(String)->Unit,
onNumberChange:(String)->Unit,
onBack : ()->Unit,
onSave: ()-> Unit,
onLogOut: () -> Unit,
modifier: Modifier,) {
val imageUrl = vm.userData.value?.imageUrl
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(text = "BACK", Modifier.clickable {
onBack.invoke()
})
Text(text = "SAVE", Modifier.clickable {
onSave.invoke()
})
CommonDivider()
ProfileImage(imageUrl = imageUrl, vm = vm)
CommonDivider()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(4.dp),
verticalAlignment = Alignment.CenterVertically
)
{
Text(text = "Name", modifier = Modifier.width(100.dp))
TextField(
value = name, onValueChange = onNameChange,
colors = TextFieldDefaults.textFieldColors(
focusedTextColor = Color.Black,
containerColor = Color.Transparent
)
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(4.dp), verticalAlignment = Alignment.CenterVertically
)
{
Text(text = "Number", modifier = Modifier.width(100.dp))
TextField(
value = number, onValueChange = onNumberChange,
colors = TextFieldDefaults.textFieldColors(
focusedTextColor = Color.Black,
containerColor = Color.Transparent
)
)
}
CommonDivider()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.Center
) {
Text(text = "Logout", modifier = Modifier.clickable {
onLogOut.invoke()
})
}
}
}
}
@Composable
fun ProfileImage(imageUrl:String?,vm: galBaatviewModel){
val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()
) {
uri ->
uri?.let {
vm.uploadProfileImage(uri)
}
}
Box(modifier = Modifier.height(intrinsicSize = IntrinsicSize.Min)){
Column(modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
.clickable {
launcher.launch("image/*")
},
horizontalAlignment = Alignment.CenterHorizontally) {
Card(shape = CircleShape,
modifier = Modifier
.padding(8.dp)
.size(100.dp)) {
CommonImage(data = imageUrl)
}
Text(text = "Change Profile Picture")
}
if(vm.inProcess.value)
CommonProgressBar()
}
}
这是我的主要活动
package com.example.galbaat
sealed class DestinationScreens(var route: String){
object SignUp : DestinationScreens("signup")
object Login : DestinationScreens("login")
object profile : DestinationScreens("ProfileScreen")
object ChatList : DestinationScreens("chatList")
object SingleChat : DestinationScreens("singleChat/{chatId}"){
fun createRoute(id: String) = "SingleChat/$id"
}
object StatusList : DestinationScreens("statusList")
object SingleStatus : DestinationScreens("singleStatus/{UserId}"){
fun createRoute(Userid: String) = "SingleChat/$Userid"
}
}
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GALBAATTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
chatAppNavigation()
}
}
}
}
@Composable
fun chatAppNavigation(){
val navController = rememberNavController()
var vm = hiltViewModel<galBaatviewModel>()
NavHost(navController = navController, startDestination = DestinationScreens.SignUp.route){
composable(DestinationScreens.SignUp.route){
SignUp(navController,vm)
}
composable(DestinationScreens.Login.route){
loginScreen(navController=navController,vm = vm)
}
composable(DestinationScreens.ChatList.route){
chatScreen(navController = navController , vm = vm)
}
composable(DestinationScreens.StatusList.route){
StatusScreen(navController = navController , vm = vm)
}
composable(DestinationScreens.profile.route){
ProfileScreen(navController = navController , vm = vm)
}
}
}
}
我尝试正确路由它,但在我的 prfile 上它没有显示任何内容,我已附加我的个人资料屏幕代码以及我的视图模型代码和主要活动代码,这似乎更多是我无法解决的函数调用问题
在您的撰写函数中,不要调用
.value
,而是使用 collectAsState
,
当您调用 .value
时,它不会对更改做出反应,但是使用 collectAsState
时,它将用新数据重新组合可组合项,请全部替换...
例如这个:
vm.userData.value?.imageUrl
将更改为: vm.userData.collectAsState()?.imageUrl`
希望对你有帮助