Order firestore documents - android

I have a chat done in firestore and obviously I need to get the messages from each chat room but the messages never come sorted by the date always by the id of the user.
In the beginning I did without using #ServerTimestamp and was generating the date on the Android device itself but at the suggestion right here in Stackoverflow I changed to the firestore itself to generate the date, according to the suggestion that would solve but it does not work. It's coming in an order I did not order, it's coming in the order of the user id, lateinit var from_id: String
class Message {
lateinit var content: String
#ServerTimestamp
var timestamp: Timestamp ?= null
lateinit var from_id: String
lateinit var type: String
constructor(content: String, timestamp : Timestamp, from_id: String, type: String) {
this.content = content
this.from_id = from_id
this.timestamp = timestamp
this.type = type
}
constructor(content: String, from_id: String, type: String) {
this.content = content
this.from_id = from_id
this.type = type
}
constructor()
}
ControllerChat
...
override fun sendMessageText(idChatRoom: String, from_id: String, text: String, listenerSendMessage: ListenerSendChatMessage) {
var message = Message(text, from_id, Message.TEXT)
chatChannelsCollectionRef
.document(idChatRoom)
.collection(MESSAGES)
.add(message).addOnSuccessListener {
listenerSendMessage.onSendChatMessageSucess()
}.addOnFailureListener {
listenerSendMessage.errorSendChatMessage(it)
}
}
...
override fun getAllMessageFromChatRoom(idChatRoom: String, listenerGetAllChatMessage: ListenerGetAllChatMessage) {
Log.d(TAG, "ChatController - getAllMessageFromChatRoom")
listenerSnapshotAllMessageFromChatRoom = chatChannelsCollectionRef
.document(idChatRoom)
.collection(MESSAGES)
.orderBy("timestamp", Query.Direction.ASCENDING)
.addSnapshotListener(object : EventListener<QuerySnapshot> {
override fun onEvent(querySnapshot: QuerySnapshot?, p1: FirebaseFirestoreException?) {
querySnapshot?.let { qSnap ->
if (!qSnap.isEmpty) {
var documentChange = qSnap.documentChanges
for (doc in documentChange) {
var message = doc.document.toObject(Message::class.java)
Log.i(TAG, "Document Change: " + message.content)
listenerGetAllChatMessage.onChatMessage(message)
}
}
}
}
})
}

Related

java.lang.NumberFormatException: For input string:"something"

i tried to split a string to two variable, one is string and one is Long. it work, when i Log it i can see it and i can insert it to Room Database, but i don't know why "sometime" i get this error.
the string like this
m8fw5sMdAcaX4Ezv7vzImeRAjkq2_1635234951781
java.lang.NumberFormatException: For input string: "m8fw5sMdAcaX4Ezv7vzImeRAjkq2"
at java.lang.Long.parseLong(Long.java:594)
at java.lang.Long.parseLong(Long.java:636)
at com.animals.snowy.MainActivity$insertMessage$1$messageListener$1.onChildAdded(MainActivity.kt:88)
my Model
#IgnoreExtraProperties
#Entity(tableName = "message_table")
data class MessageModel(
#NonNull
#PrimaryKey
var messageId: String = "",
var messageType: String? = null,
var messageTimestamp: Long? = null,
var messageData: String? = null,
var messageSenderId: String? = null,
var roomId: String = "",
var isSeen: Boolean = false,
var uploadSuccess : Boolean = false
) : Serializable {
}
and this is my code , i want to get new message of friends, so i get list friend from Room Database and use for loop to get roomId(name of child container message of me and my friend).
private fun insertMessage() {
viewModel.readRoomIdFriendsDAO().observe(this, { listRoomId ->
if (listRoomId != null && listRoomId.isNotEmpty()) {
for (item in listRoomId) {
val messageListener = object : ChildEventListener {
override fun onChildAdded(snapshot:DataSnapshot,previousChildName: String?) {
val messageModel: MessageModel? =
snapshot.getValue(MessageModel::class.java)
if (messageModel != null) {
messageModel.messageId = snapshot.key.toString().trim()
messageModel.roomId = item
messageModel.uploadSuccess = true
val listTemp = messageModel.messageId.split("_")
messageModel.messageSenderId = listTemp[0]
messageModel.messageTimestamp = listTemp[1].trim().toLong()
Log.e(TAG,"senderId: ${messageModel.messageSenderId}")
Log.e(TAG,"timestamp: ${messageModel.messageTimestamp}")
// messageViewModel.insertMessageDAO(messageModel)
}
}
override fun onChildChanged(
snapshot: DataSnapshot,
previousChildName: String?
) {
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
override fun onChildMoved(
snapshot: DataSnapshot,
previousChildName: String?
) {
TODO("Not yet implemented")
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
}
messageRef
.child(item)
.addChildEventListener(messageListener)
}
}
})
}
java.lang.NumberFormatException is thrown whenever the compiler tries to type cast an invalid input to number.
For example:
String validInputToCast = "123456789";
Long validInputToCast = validInputToCast.toLong(); // this casting will succeed.
String invalidInputToCast = "abce124";
Long invalidCastedInput = inputToCast.toLong(); // compiler will throw number exception on this line.
Try debugging the line below and hopefully you will find the error.
messageModel.messageTimestamp = listTemp[1].trim().toLong()

How you do simplify this Kotlin Getter and Settle code?

I am new to Kotlin and have been developing with the language. From Java, I am used to coding getters and setters by creating two functions. For example:
public String getName(){
return name;
}
public void setName(name){
this.name = name;
}
However, can this code be simplified in Kotlin? My code right now is:
class ClassName{
private var username: String? = null
private var photoFileName: String? = null
private var userId: String? = null
private var requestSent: Boolean? = null
fun ClassName(username: String?, photoFileName: String?, userId: String?, requestSent: Boolean?) {
this.username = username
this.photoFileName = photoFileName
this.userId = userId
this.requestSent = requestSent
}
fun getUsername(): String? {
return username
}
fun setUsername(string: String){
username = string
}
fun getPhotoFileName(): String? {
return photoFileName
}
fun setPhotoFileName(string: String){
photoFileName = string
}
fun getUserId(): String? {
return userId
}
fun setUserId(string: String){
userId = string
}
fun getRequestSent(): Boolean? {
return requestSent
}
fun setRequestSent(bool: Boolean){
requestSent = bool
}
}
Here's a more enhanced version of your kotlin class
data class YourClass(
var username: String? = null,
var photoFilename: String? = null,
var userId: String? = null,
var requestSent: Boolean? = null
)
You don't have to manually create setter, getter function in Kotlin.
Your class will get converted to this if you use data class in kotlin. All the setters and getters will be replaced by the properties.And yes you can always call them like you used to do like set and get.
data class ClassName(
var username: String,
var photoFileName: String,
var userId: String,
var requestSent: String
)

Observing class parameters in Android using databinding and Kotlin

I have a model
data class RegisterPostDataWithPwdCheck(
var phone_number: String?,
var name: String?,
var password: String?,
var secondPassword: String?)
And a ViewModel
class SignUpViewModel(application: Application) : BaseViewModel(application){
val registerPostData = MutableLiveData<RegisterPostDataWithPwdCheck>...
fun checkPassword(){}...}
I also have a View that has this code inside
viewModel.registerPostData.observe(viewLifecycleOwner, Observer {
viewModel.checkPassword()
})
In the XML there are two fields of interest
<EditText
android:id="#+id/edittext_sign_up_password"
android:text="#={view_model.registerPostData.password}" />
<EditText
android:id="#+id/edittext_sign_up_second_pw"
android:text="#={view_model.registerPostData.secondPassword}" />
What I understood so far is that the .observe will be called only when the entire RegisterPostDataWithPwdCheck object changes and I don't want that. I want it to be triggered when any of the parameters changes so I can call the fun checkPassword(){} in order to see if the two fields match. Is this possible?
Using #mahdi-shahbazi comment I've managed to work this out in Kotlin. My Model is now:
data class RegisterPostDataWithPwdCheck(
#SerializedName(value = "phone_number")
private var phoneNumber: String?,
private var name: String?,
private var password: String?,
private var secondPassword: String?
) : BaseObservable() {
#Bindable
fun getPhoneNumber(): String? {
return phoneNumber
}
fun setPhoneNumber(value: String) {
if (value != phoneNumber) {
phoneNumber = value
notifyPropertyChanged(BR.phoneNumber)
}
}
#Bindable
fun getName(): String? {
return name
}
fun setName(value: String?) {
if (value != name) {
name = value
notifyPropertyChanged(BR.name)
}
}
#Bindable
fun getPassword(): String? {
return password
}
fun setPassword(value: String?) {
if (value != password) {
password = value
notifyPropertyChanged(BR.password)
}
}
#Bindable
fun getSecondPassword(): String? {
return secondPassword
}
fun setSecondPassword(value: String?) {
if (value != secondPassword) {
secondPassword = value
notifyPropertyChanged(BR.secondPassword)
}
}
}
And creating custom LiveData class:
class PropertyAwareMutableLiveData<T : BaseObservable> : MutableLiveData<T>()
{
private val callback = object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
value = value
}
}
override fun setValue(value: T?) {
super.setValue(value)
value?.addOnPropertyChangedCallback(callback)
}
}
What I still don't know if there is a way to automate this #Binding process which is terribly slow and boring and also forces some changes (turning parameters to private).

Query all nodes in firebase with kotlin android

I am building an simple chat with firebase. my firebase structure
chats
PSTQL2W3qqV8GGu7bjXhYZKrXh92&sCv3CCXOLnYrb38db4V41PoArxD2
conversatins
87483
sender: "sCv3CCXOLnYrb38db4V41PoArxD2"
time: "3:08"
title: "hey!"
type: "text"
348843
sender: "sCv3CCXOLnYrb38db4V41PoArxD2"
time: "4:33"
title: "HI!"
type: "text"
last_message: "Hey!"
last_time: "23:23 am"
My Model
data class Message(
var conversations: ArrayList<Conversations> = ArrayList(),
val last_message: String = "",
val last_time: String = "") {
data class Conversations(
var sender: String = "",
var time: String = "",
var title: String = "",
var type: String = "")
}
I want to retrieve array object in conversations, I've tried
val listenToChild = object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
val chat = p0.getValue(Message::class.java)
Log.d("message",${chat?.conversations?.size}"
}
}
mMessageReference.child(keySnapshot.toString()).addValueEventListener(listenToChild)
I get result size 0. Is there any problems with my model?

No args error retrofit request body

I am facing problem while sending json object body using retrofit to the server. Below is the error.
Failed to invoke public
com.nitesh.brill.saleslines._User_Classes.User_PojoClass.UpdatePreviousDetails()
with no args
code snippet
// Api endpoint
#Headers("Content-Type: application/json")
#POST("UpdatePreviousDetails/{Id}")
fun updatePreviousDetails(#Path("Id") Id: Int, #Body updateDetails :UpdatePreviousDetails): Call<UpdatePreviousDetails>
//pojo class
package com.nitesh.brill.saleslines._User_Classes.User_PojoClass
import java.util.*
/**
* Created by Nitesh Android on 16-08-2017.
*/
class UpdatePreviousDetails(
var CompanyName: String? = null!!,
var Designation: String? = null!!,
var DateOfJoin: Date? = null!!,
var DateOfLeaving: Date? = null!!,
var SectorPreviouslyWorked: String? = null!!,
var Id: Int? = null!!
) {
}
//sending data
val details = UpdatePreviousDetails("rr", "asm", date, date, "Pharmaceuticals",3)
val call = apiEndpointInterface!!.updatePreviousDetails(5, details)
call.enqueue(object :Callback<UpdatePreviousDetails> {
override fun onResponse(call: Call<UpdatePreviousDetails>?, response: Response<UpdatePreviousDetails>?) {
objUsefullData.showSnackBar("success")
UsefullData.Log("============="+response!!.body().toString())
}
override fun onFailure(call: Call<UpdatePreviousDetails>?, t: Throwable?) {
objUsefullData.showSnackBar("fail")
UsefullData.Log("============="+t)
}
})
I am using kotlin language
Your UpdatePreviousDetails class has to have a constructor with no params to enable Gson (inside Retrofit) to convert your object into JSON.
EDIT
class UpdatePreviousDetails() {
var CompanyName: String? = null
var Designation: String? = null
var DateOfJoin: Date? = null
var DateOfLeaving: Date? = null
var SectorPreviouslyWorked: String? = null
var Id: Int? = null
constructor(
CompanyName: String?,
Designation: String?,
DateOfJoin: Date?,
DateOfLeaving: Date?,
SectorPreviouslyWorked: String?,
Id: Int?
) : this() {
this.CompanyName = CompanyName
this.Designation = Designation
this.DateOfJoin = DateOfJoin
this.DateOfLeaving = DateOfLeaving
this.SectorPreviouslyWorked = SectorPreviouslyWorked
this.Id = Id
}
}

Categories

Resources