How to read child of child data from firebase in android / kotlin - android

I am trying to read data from my firebase realtime database to a TextView. But every time it shows null in TextView. I want to read single user data. I want to read data when user give input.
My Data Structure look like this..
{
"Date": {
"04-10-2019": {
"-LqR-e2UJLJCccqfgGi1":{
address: Dhaka
date: 04-10-2019
name: Mark
phoneNo: 017#######
serialNo: -LqR-e2UJLJCccqfgGi1
type: New
},
},
"05-10-2019": {
"-LqU-e2UJLJCDcqfgGi9":{
address: Dhaka
date: 04-10-2019
name: Tony
phoneNo: 017#######
serialNo: -LqU-e2UJLJCDcqfgGi9
type: OLd
},
}
}
The code that I am trying.
class Info(
val serialNo: String? = "",
val name: String = "",
val address: String = "",
val phoneNo: String = "",
val date: String = "",
var type: String = ""
)
private fun saveInfo() {
// Edit Text Field
val name = editTextName.text.toString().trim()
if (name.isEmpty()) {
editTextName.error = "Please Enter Your Name"
return
}
val address = editTextAddress.text.toString().trim()
if (address.isEmpty()) {
editTextAddress.error = "Please Enter Your Address"
return
}
val phoneNo = editTextPhoneNo.text.toString().trim()
if (phoneNo.isEmpty()) {
editTextPhoneNo.error = "Please Enter Your Phone Number"
return
}
val date = dateText.text.toString().trim()
//Radio Button
var type = ""
when {
checkboxNew.isChecked -> type += "New"
checkboxOld.isChecked -> type += "Old"
radioGroup.checkedRadioButtonId <= 0 -> {
Toast.makeText(applicationContext, "Please Check New or Old", Toast.LENGTH_LONG)
.show()
return
}
}
val current = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
val formatted = current.format(formatter)
val myRef = FirebaseDatabase.getInstance().getReference("Date").child(formatted)
myRef.orderByChild(formatted).startAt("28-09-2019").endAt("31-12-2070")
val patientId = myRef.push().key
val patient = Info(patientId, name, address, phoneNo, date, type)
myRef.child((patientId).toString()).setValue(patient).addOnCompleteListener {
Toast.makeText(applicationContext, "Info saved Successfully", Toast.LENGTH_LONG).show()
myRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (data in dataSnapshot.children) {
val user = data.child(formatted).value.toString()
dataText.text = user
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}
I want to show the data into a textview when the user give input and hit a button.

If you are trying to read the date attribute from the database then change this :
val user = data.child(formatted).value.toString()
Into this:
val user = data.child("date").value.toString()
Inside the child() you need to pass the name of the attribute.

Related

how to get position of deleted Firestore Data that have been deleted from console (outside source) to update Or notify the adapter

I have this app that someone can delete his document at any time so if he deletes the document I want every other user to get updated the document has been removed and remove the document from the listView, it's more like a Food Ordering app so the user order could be taking by another Driver so the document will no longer be available for other users, I want to update the recyclerView Whenever a user deletes a document, so how to get the position without clicking how to detect that change to get the position, Sorry if I couldn't explain much I'm Using Groupie Adapter
val ref = firestore.collection("orders").whereNotEqualTo("userUid", uid)
val adapter = GroupAdapter<GroupieViewHolder>()
ref.addSnapshotListener { value, error ->
if (error != null){
return#addSnapshotListener
}
value?.documentChanges?.forEach {
if (it.type == DocumentChange.Type.ADDED) {
val userUid = it.document.data.get("userUid") as String
val userPhone = it.document.data.get("phone") as String
val userName = it.document.data.get("name") as String
val time = it.document.data.get("time") as String
val marketName = it.document.data.get("marketName") as String
val amount = it.document.data.get("amount") as String
val storeimgUrl = it.document.data.get("storeImg") as String
val order = it.document.data.get("order") as String
val userImg = it.document.data.get("userImg") as String
adapter.add(DriverOrders(userUid, userPhone, userName, time, marketName, amount, storeimgUrl, order, userImg))
adapter.notifyDataSetChanged()
}
if(it.type == DocumentChange.Type.REMOVED){
// here Wher I'm trying to get the position of deleted Or removed data
if (it.document.id == DriverOrders.docId){
adapter.notifyItemRemoved(it.oldIndex)
}
}
}
recyclerview_driverorders.adapter = adapter
}
class DriverOrders(val userUid: String, val userPhone: String,
val userName: String, val time: String,
val marketName: String, val amount: String, val storeimgUrl: String, val order: String,
val userImg: String):Item<GroupieViewHolder>() {
override fun getLayout(): Int {
return R.layout.driver_row
}
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.itemView.driverorders_sName.text = marketName
viewHolder.itemView.driverorders_order.text = order
viewHolder.itemView.driverorders_time.text = Date
Picasso.get().load(storeimgUrl).fit().into(viewHolder.itemView.driverorders_sImg)
}
}

How to send POST with json using Retrofit?

I'm Struggling how to send POST with json using Retrofit2.
like this:
{
"user_available_id": 702,
"teacher_id" : 3207,
"schedule" : [{
"event_id" : 47533,
"schedule_time" : "2020-11-30 07:00:00",
"status" :1
},
{
"event_id" : 47532,
"schedule_time" : "2020-11-30 06:30:00",
"status" :1
}]
}
I'm suppose send post like that. And I wonder is it possible to send like that or there is another way. can you kindly tell me if there is another way. btw here's how I try to send it
CreateSchduleAPI.kt
#POST("schedule/student-create")
#Headers("Accept: application/json")
#SerializedName("data")
suspend fun createScheduleSesi2(
#Header("Authorization") token: String?,
#Body createSchedule: String
): Response<ScheduleModel>
And the Model
ScheduleModel.kt
#Parcelize
data class ScheduleModel(
#field:SerializedName("user_available_id")
var userAvailableId: String? = null,
#field:SerializedName("schedule")
var schedule: ArrayList<schedule?>? = null,
#field:SerializedName("teacher_id")
var teacherId: String? = null
) : Parcelable
#Parcelize
data class schedule(
#field:SerializedName("event_id")
var eventId: String? = null,
#field:SerializedName("schedule_time")
var scheduleTime: String? = null,
#field:SerializedName("status")
var status: String? = null
) : Parcelable
First
private suspend fun getMultiSlotJadwal(id: String, date: String) {
jamList.clear()
val networkConfig =
NetworkConfig().getTeacher().getTeacherScheduleAvailability(token, id, date)
if (networkConfig.isSuccessful) {
if (networkConfig.body()!!.availability!!.isEmpty()) {
binding.rvSlot.visibility = View.GONE
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Jam tidak tersedia",
Toast.LENGTH_SHORT
).show()
}
} else {
for (slot in networkConfig.body()!!.availability!!) {
//convert tanggal start ke millis
val tanggalSlot = slot!!.start!!.toDate().formatTo("yyyy-MM-dd HH:mm")
val tanggalInMillis = convertToMillis(tanggalSlot)
//ambil tanggal sekarang
val myFormat = "yyyy-MM-dd HH:mm" // format tanggal
val calendar = Calendar.getInstance()
val time = calendar.time
val sdf = SimpleDateFormat(myFormat, Locale.getDefault())
val curdate = sdf.format(time) //diconvert ke tanggal local
val curDateinMillis = convertToMillis(curdate) // convert ke millis
val hasilDate = tanggalInMillis - curDateinMillis
val tanggalJam = hasilDate / 3600000 //diubah dari millis ke jam
if (tanggalJam >= 6) {
jamList.add(slot)
val sortJamList = jamList.sortedBy { jamList -> jamList.start }
binding.rvSlot.visibility = View.VISIBLE
binding.rvSlot.adapter = SlotJamAdapter(sortJamList) {
teacher_id = it.teacherId.toString()
scheduleModel.teacherId = teacher_id
scheduleModel.userAvailableId = user_avalaible_id
scheduleItem.scheduleTime = it.start.toString()
scheduleItem.status = "1"
scheduleItem.eventId = it.id.toString()
scheduleList.add(scheduleItem)
scheduleModel.schedule = scheduleList
itemClicked = true
changeBackgroundButtonSesi2()
}
}
}
}
} else {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Jam tidak tersedia",
Toast.LENGTH_SHORT
).show()
}
}
}
Second
private suspend fun createSchedule2Sesi() {
val jsonSchedule = Gson().toJson(scheduleModel)
val networkConfig = NetworkConfig().createSchedule().createScheduleSesi2(
token,
jsonSchedule
)
try {
if (networkConfig.isSuccessful) {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Pembuatan Jadwal Berhasil",
Toast.LENGTH_LONG
).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
}
} else {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Pembuatan Jadwal Gagal, Cek Koneksi",
Toast.LENGTH_LONG
).show()
}
}
}catch (e:Exception){
Log.e(TAG, "createSchedule2Sesi: ${e.message}", )
}
}
Thank you in advance
Retrofit allows you to use your Kotlin object as a parameter of a call. It will take care of the json serialisation itself if you use GsonConverterFactory when building your Retrofit instance.
That will allow you to change the definition of your endpoint as below
#POST("schedule/student-create")
suspend fun createScheduleSesi2(
#Header("Authorization") token: String?,
#Body createSchedule: ScheduleModel
): Response<ScheduleModel>

Parse internal map from JSON in Moshi

I am trying to parse following JSON using moshi but I am unable to dynamic data like USA or UK. USA and UK are dynamic keys.
{
"USA": {
"name": "United State of America",
"code": "US"
},
"UK": {
"name": "United Kingdom",
"code": "UK"
},
"soft_update": "500",
"hard_update": "500"
}
Data class:
data class ApiAppUpdate(val countryMap: Map<String, ApiCountry>,
#field:Json(name = "hard_update")
val forceUpdateVersion: Int,
#field:Json(name = "soft_update")
val softUpdateVersion: Int)
Following is my json adapter code:
fun getConfig(){
val adapter: JsonAdapter<ApiAppUpdate> = moshi.adapter(ApiAppUpdatee::class.java)
}
I get soft and hard update values but countryMap is always null. I am not sure what's wrong in here. Can someone please help me. Thanks.
The problem is that your model description would match this json and not the one you attached:
{
"countryMap":{
"USA":{
"name":"United State of America",
"code":"US"
},
"UK":{
"name":"United Kingdom",
"code":"UK"
}
},
"soft_update":"500",
"hard_update":"500"
}
In your example "USA" and "UK" are on the same level with "soft_update" and "hard_update".
UPDATE:
This is a working solution:
data class ApiCountry(val name: String, val code: String)
data class ApiAppUpdate(
val countryMap: Map<String, ApiCountry>,
#field:Json(name = "hard_update")
val forceUpdateVersion: Int,
#field:Json(name = "soft_update")
val softUpdateVersion: Int
)
class ApiUpdateAdapter {
#FromJson
fun fromJson(reader: JsonReader): ApiAppUpdate {
var forceUpdateVersion: Int = -1
var softUpdateVersion: Int = -1
val map: MutableMap<String, ApiCountry> = mutableMapOf()
reader.beginObject()
while (reader.hasNext()) {
when (reader.peek()) {
JsonReader.Token.NAME ->
when (val fieldName = reader.nextName()) {
"hard_update" -> forceUpdateVersion = reader.nextInt()
"soft_update" -> softUpdateVersion = reader.nextInt()
else -> {
reader.beginObject()
var name = ""
var code = ""
while (reader.hasNext()) {
when (reader.nextName()) {
"name" -> name = reader.nextString()
"code" -> code = reader.nextString()
else -> reader.skipValue()
}
}
reader.endObject()
map[fieldName] = ApiCountry(name, code)
}
}
else -> reader.skipValue()
}
}
reader.endObject()
return ApiAppUpdate(map, forceUpdateVersion, softUpdateVersion)
}
}
fun main() {
val sourceJson =
"{\"USA\":{\"name\":\"United States of America\",\"code\":\"US\"},\"UK\":{\"name\":\"United Kingdom\",\"code\":\"UK\"}" +
",\"soft_update\":\"200\",\"hard_update\":\"300\"}"
val adapter = Moshi.Builder()
.add(ApiUpdateAdapter())
.build()
.adapter(ApiAppUpdate::class.java)
val apiAppUpdate = adapter.fromJson(sourceJson)
println(apiAppUpdate)
}

How to save ArrayList data into Firebase using Kotlin?

I have some problem when I try to save array data from an Android Kotlin to Firebase Database.
I want to save data as shown below:
Image 1
but, when I saved the data, in the Firebase database it always updated the "pemasukan" object, not creating new data.
the stored data is always like the picture below
Image 2
Anyone can help me please.
Sorry for my English ;)
This is the code I am using for
class PemasukanActivity : AppCompatActivity() {
private lateinit var database : FirebaseDatabase
private lateinit var mRef : DatabaseReference
lateinit var currentDate : String
private val id_user = "agus"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pemasukan)
btnSimpan()
}
//aksi tombol untuk simpan data
private fun btnSimpan(){
btn_simpan_pemasukan.setOnClickListener {
val pemasukan = Pemasukan()
if (edt_nama_barang.length() > 3){
pemasukan.keterangan = edt_nama_barang.text.toString()
} else {
edt_nama_barang.error ="Nama Barang Harus lebih dari 3 huruf"
return#setOnClickListener
}
if (edt_jumlah.length() > 3){
var jumlah = edt_jumlah.text.toString()
pemasukan.jumlah = jumlah.toLong()
}else{
edt_jumlah.error ="Jumlah Harus lebih dari 3 huruf"
return#setOnClickListener
}
simpanData(pemasukan)
}
}
//simpan data ke firebase
private fun simpanData(listPemasukan :Pemasukan){
val sdf = SimpleDateFormat("ddMyyyy")
currentDate = sdf.format(Date())
val data = Dataitem()
data.id = currentDate
data.user_id = id_user
val nameList = ArrayList<Pemasukan>(Arrays.asList(listPemasukan))
data.pemasukan = nameList
database = FirebaseDatabase.getInstance()
mRef = database.getReference("pendataan")
mRef.child("${currentDate}").setValue(data)
.addOnSuccessListener {
Toast.makeText(this, "Success . .", Toast.LENGTH_LONG).show()
edt_nama_barang.text.clear()
edt_jumlah.text.clear()
}
.addOnFailureListener {
Toast.makeText(this, "Gagal Input Data", Toast.LENGTH_LONG).show()
it.printStackTrace()
Log.e("FIREBASE_ERROR", it.message)
}
}
And the POJO class like this:
data class Dataitem (
var id : String = "",
var user_id : String = "",
var pemasukan : ArrayList<Pemasukan>? = null,
var pengeluaran : ArrayList<Pengeluaran>? = null
)
data class Pengeluaran (var jumlah : Long = 0,
var keterangan : String = "")
data class Pemasukan (var jumlah : Long = 0,
var keterangan : String ="")

Kotlin how to return a SINGLE object from a list that contains a specific id?

Good day, i'm stuck figuring out how to get a single object from a list, i did google but all the topics show how to return a List with sorted objects or something similar.
I have a User Class
class User() {
var email: String = ""
var firstname: String = ""
var lastname: String = ""
var password: String = ""
var image: String = ""
var userId: String = ""
constructor(email:String,
firstname: String,
lastname: String,
password: String,
image: String, userId : String) : this() {
this.email = email
this.firstname = firstname
this.lastname = lastname
this.password = password
this.image = image
this.userId = userId
}
}
In java i would write something like
User getUserById(String id) {
User user = null;
for(int i = 0; i < myList.size;i++;) {
if(id == myList.get(i).getUserId())
user = myList.get(i)
}
return user;
}
How can i achieve the same result in kotlin?
You can do this with find, which gives you the first element of a list that matches a given predicate (or null, if none matched):
val user: User? = myList.find { it.userId == id }
Or if you really do need the last element that matches the predicate, as your Java example code does, you can use last:
val user: User? = myList.last { it.userId == id }
Simplify
val user: User = myList.single { it.userId == id }
or if may list not have your filter
val user: User? = myList.singleOrNull{ it.userId == id }
If you don't want to deal with null objects, try this:
val index = myList.indexOfFirst { it.userId == id } // -1 if not found
if (index >= 0) {
val user = myList[index]
// do something with user
}
You can use this extension function also which return pair Pair(Boolean,T)
e.g
val id=2
val item= myList.customContains{it-> it.userId ==id}
if(item.first){
item.second //your object
// your code here
}else{
// if item no present
}
fun <E> List<E>.customContains(function: (currentItem: E) -> Boolean): Pair<Boolean, E?> {
for (current in 0 until this.size) {
if (function(this[current])) {
return Pair(true, this[current])
}
}
return Pair(false, null)
}

Categories

Resources