I am trying to figure out how I can create 2 different textfields (name and phone-number) in jetpack compose that when the user enters this type of info and press the continue button, the information will asynchronously save until the person is navigated/enters the "mainscreen". After the user enters the "mainscreen" in this case just a screen with a column saying hello, will the information be saved in mongoDatabase. How can I achieve this? Appreciate the help and feedback!
This is the code so far:
The screen with name, phonenumber and a continue button:
https://gyazo.com/12f15eac19a25f19c3ac1fea42820ab0
Column(
modifier = Modifier
.fillMaxSize()
.weight(1f),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
modifier = Modifier
.fillMaxWidth(0.80f),
value = name,
onValueChange = onNameChanged,
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = LightBlue,
),
label = {
Text(
text = "Name", // Goes top in a small text
color = LightBlue,
fontWeight = FontWeight.Bold
)
},
placeholder = {
Text(
text = "Enter your name", // Gives a hint to the user
color = Color.Black
)
},
singleLine = true,
leadingIcon = {
Icon(
imageVector = Icons.Default.Person,
contentDescription = null
)
},
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
modifier = Modifier.fillMaxWidth(0.8f),
value = phoneNumber,
onValueChange = { phoneNumber = it },
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
// You can perform an action here when the user presses Done on the keyboard.
// For example, hide the keyboard.
keyboardController?.hide()
}
),
singleLine = true,
textStyle = MaterialTheme.typography.bodyMedium.copy(fontSize = 16.sp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color.Blue,
unfocusedBorderColor = Color.Gray
),
label = {
Text(
text = "Phone Number", // Goes top in a small text
color = LightBlue,
fontWeight = FontWeight.Bold
)
},
placeholder = { Text(text = "Enter your telephone number") },
leadingIcon = {
Icon(
imageVector = Icons.Default.Phone,
contentDescription = null
)
},
)
Spacer(modifier = Modifier.height(10.dp))
Button(
modifier = Modifier
.wrapContentSize()
.fillMaxWidth(0.8f)
.height(80.dp)
.padding(start = 20.dp, end = 20.dp, bottom = 40.dp)
.align(Alignment.CenterHorizontally), // Align the button at the bottom center
colors = ButtonDefaults.buttonColors(ConfirmButtonColor),
shape = RoundedCornerShape(10.dp),
onClick = {
if (name.isNotEmpty() && phoneNumber.isNotEmpty()) {
navController.navigate(AuthScreen.GenderProfile.route)
} else {
Toast.makeText(context, "Not all fields are filled-in!", Toast.LENGTH_SHORT).show()
}
},
) {
Text(
text = "Confirm",
color = Color.White,
)
}
Person Class:
class Person : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId.invoke()
var owner_id: String = ""
// Profile
var name: String = ""
var phoneNumber: Int = 0
}
MongoRepository:
interface MongoRepository {
fun configureTheRealm()
fun getData(): Flow<List<Person>>
suspend fun insertPerson(person: Person)
suspend fun updatePerson(person: Person)
}
MongoDB Object:
object MongoDB : MongoRepository {
private val app = App.create(APP_ID)
private val user = app.currentUser
private lateinit var realm: Realm
init {
configureTheRealm()
}
override fun configureTheRealm() {
if (user != null) {
val config = SyncConfiguration.Builder(
user,
setOf(Person::class)
)
.initialSubscriptions { sub ->
add(query = sub.query<Person>(query = "owner_id == $0", user.id))
}
.log(LogLevel.ALL)
.build()
realm = Realm.open(config)
}
}
override fun getData(): Flow<List<Person>> {
return realm.query<Person>().asFlow().map { it.list }
}
override suspend fun insertPerson(person: Person) {
if (user != null) {
realm.write {
try {
copyToRealm(person.apply { owner_id = user.id })
} catch (e: Exception) {
Log.d("MongoRepository", e.message.toString())
}
}
}
}
override suspend fun updatePerson(person: Person) {
realm.write {
val queriedPerson =
query<Person>(query = "_id == $0", person._id)
.first()
.find()
if (queriedPerson != null) {
queriedPerson.name = person.name
queriedPerson.phoneNumber = person.phoneNumber
} else {
Log.d("MongoRepository", "Queried Person does not exist.")
}
}
}
}
HomeViewModel:
class HomeViewModel : ViewModel() {
var objectId = mutableStateOf("")
var data = mutableStateOf(emptyList<Person>())
// Profile + PickGender screen
var name = mutableStateOf("")
var phoneNumber = mutableStateOf(0)
init {
viewModelScope.launch {
MongoDB.getData().collect {
data.value = it
}
}
}
fun updateObjectId(id: String) {
this.objectId.value = id
}
fun updateName(name: String) {
this.name.value = name
}
fun updatePhoneNumber(phoneNumber: Int) {
this.phoneNumber.value = phoneNumber
}
// The phoneNumber and Age will be set in string since I don't know how to set it in Int form
fun insertPerson() {
viewModelScope.launch(Dispatchers.IO) {
if (
name.value.isNotEmpty() &&
phoneNumber.value.toString().isNotEmpty() &&
) {
MongoDB.insertPerson(person = Person().apply {
name = [email protected]
phoneNumber = [email protected]
})
}
}
}
fun updatePerson() {
viewModelScope.launch(Dispatchers.IO) {
if (objectId.value.isNotEmpty()) {
MongoDB.updatePerson(person = Person().apply {
_id = ObjectId(hexString = [email protected])
name = [email protected]
phoneNumber = [email protected]
})
}
}
}
}
2
Answers
Accessing and editing
ViewModel
variables from your views is a very bad practice. Here’s another way to temporarily save values till the user goes to the next screen: Use theremember
API to save the states of theTextField
s between recompositions. At theButton
‘s click, you then call the save function you have at theViewModel
.MongoDB is a NoSQL database, and it does not require integration with Google Sign-In or email/password authentication for basic CRUD (Create, Read, Update, Delete) operations.
If you are using MongoDB Realm, a serverless platform by MongoDB, you might be referring to the authentication methods it provides. Realm supports various authentication providers, including anonymous authentication, email/password, and OAuth 2.0 providers such as Google.
You can enable anonymous authentication in MongoDB Realm if you don’t want to prompt users to provide credentials. This way, users can perform CRUD operations without signing in.
Here’s an example of how you might use anonymous authentication with MongoDB Realm:
Navigate to the Realm UI, find the "Authentication" section, and
enable "Allow users to log in anonymously."