Add button in recyclerview to edit or delete data from realtime database - kotlin

i'm a beginner in programming so forgive me if my code is messy. I need some help to complete my program.
I'm using recyclerview to retrieve some data from realtime database and i want to add edit and delete button in the recyclerview to edit and delete some data.
I already create the button in the xml file, i just don't know how to code the button. I already tried some tutorial from youtube and refer to some code in some others post on stack overflow but most of the time the code will either give me an error or the button will not do anything. I've included my code and database structure below:
DoctorViewAdapter.kt
package com.example.patientmonitor
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import java.util.ArrayList
import kotlin.concurrent.fixedRateTimer
class DoctorViewAdapter(private val patientList : ArrayList<doctorViewPatient>) : RecyclerView.Adapter<DoctorViewAdapter.DoctorViewHolder>() {
//WebView
private lateinit var pulseGraph: WebView
private lateinit var temperatureGraph: WebView
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DoctorViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.patient_item,parent,false)
return DoctorViewHolder(itemView)
pulseGraph.webViewClient = WebViewClient()
temperatureGraph.webViewClient = WebViewClient()
pulseGraph.settings.javaScriptEnabled = true
temperatureGraph.settings.javaScriptEnabled = true
pulseGraph.settings.builtInZoomControls = true
temperatureGraph.settings.builtInZoomControls = true
}
override fun onBindViewHolder(holder: DoctorViewHolder, position: Int) {
val currentitem = patientList[position]
holder.userID.text = currentitem.userID
holder.fullName.text = currentitem.fullName
holder.userEmail.text = currentitem.email
holder.phoneNumber.text = currentitem.phoneNumber
var pulseValue = "null"
var temperatureValue = "null"
//get pulse value from thingspeak and set to text view
val pulsequeue = Volley.newRequestQueue(holder.pulseValue.context)
val temperaturequeue = Volley.newRequestQueue(holder.temperatureValue.context)
val pulseRequest = StringRequest(Request.Method.GET, currentitem.pulseValue as String?,
Response.Listener<String> { response ->
pulseValue = response
holder.pulseValue.text = pulseValue
}, Response.ErrorListener {
// didn't work
})
//get temperature value from thingspeak and set to text view
val tempRequest = StringRequest(Request.Method.GET, currentitem.temperatureValue as String?,
Response.Listener<String> { response ->
temperatureValue = response
holder.temperatureValue.text = temperatureValue
}, Response.ErrorListener {
// didn't work
})
//get thingspeak data every 1 second
fixedRateTimer("timer", false, 0L, 1000) {
pulsequeue.add(pulseRequest)
temperaturequeue.add(tempRequest)
}
}
override fun getItemCount(): Int {
return patientList.size
}
class DoctorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val userID : TextView = itemView.findViewById(R.id.tvUserID)
val fullName : TextView = itemView.findViewById(R.id.tvFullName)
val userEmail : TextView = itemView.findViewById(R.id.tvEmail)
val phoneNumber : TextView = itemView.findViewById(R.id.tvPhoneNumber)
val pulseValue : TextView = itemView.findViewById(R.id.tvPulseValue)
val temperatureValue : TextView = itemView.findViewById(R.id.tvTemperatureValue)
}
}
PatientlistActivity.kt
package com.example.patientmonitor
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.WebView
import androidx.appcompat.app.ActionBar
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.firebase.database.*
class PatientListActivity : AppCompatActivity() {
private lateinit var dbref : DatabaseReference
private lateinit var userRecyclerview : RecyclerView
private lateinit var userArrayList : ArrayList<doctorViewPatient>
private lateinit var viewPatientBtn : FloatingActionButton
private lateinit var doctorViewAdapter : DoctorViewAdapter
//ActionBar
private lateinit var actionBar: ActionBar
//WebView
private lateinit var pulseView: WebView
private lateinit var tempView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_patient_list)
//configure Actionbar //enable back button
actionBar = supportActionBar!!
actionBar.title = "View Patients"
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setDisplayShowHomeEnabled(true)
userRecyclerview = findViewById(R.id.patientList)
userRecyclerview.layoutManager = LinearLayoutManager(this)
userRecyclerview.setHasFixedSize(true)
userArrayList = arrayListOf<doctorViewPatient>()
getUserData()
}
private fun getUserData() {
//get intent
val assignedDoctor = intent.getStringExtra("doctorID")
val currentUserAccess = intent.getStringExtra("currentUserAccess")
dbref = FirebaseDatabase.getInstance().getReference("Users")
dbref.orderByChild("assignedDoctor").equalTo(assignedDoctor).addListenerForSingleValueEvent(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()){
for (userSnapshot in snapshot.children){
val user = userSnapshot.getValue(doctorViewPatient::class.java)
userArrayList.add(user!!)
}
userRecyclerview.adapter = DoctorViewAdapter(userArrayList)
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
This is my data class
doctorViewPatient.kt
data class doctorViewPatient(val userID : String? =null,
val fullName : String? =null,
val email : String? =null,
val phoneNumber : String? =null,
val pulseValue : String? = null,
val temperatureValue : String? = null)
This is my Realtime Database Structure

Related

how to update Textview in main activity with button in adapter?

i want to update the value of my textview that is in the PosActivity when the button in MyAdapter is click ( to increase/decrease the quantity and to delete the card from recycler view). and i can't find anything on how to do it.
here is what i tried.
in MyAdapter :
package com.mycodlabs.pos.ui.sale.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.mycodlabs.pos.R
import com.mycodlabs.pos.domain.inventory.ProductModel
import kotlinx.android.synthetic.main.pos_item_card.view.*
import java.math.BigDecimal
class MyAdapter(mUx: Context, var selectedItems: ArrayList<ProductModel>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
val mUx = mUx
// var quantity = 1
var totalPrice = BigDecimal.ZERO
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var pclose = itemView.removeItempos
var pname = itemView.pos_name
var pprice = itemView.pos_price
var pqty = itemView.pos_qty
var pminus = itemView.cart_minus_img
var pplus = itemView.cart_plus_img
// val pimage = itemView.pos_image
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.pos_item_card, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val pos: ProductModel = selectedItems[position]
holder.pname.text = pos.name
holder.pprice.text = pos.unitPrice.toString()
holder.pqty.text = pos.quantity.toString()
// holder.pimage.= pos.image
holder.pclose.setOnClickListener {
val username = pos.name
var price = pos.unitPrice
totalPrice -= price
selectedItems.removeAt(position)
notifyDataSetChanged()
notifyItemRangeChanged(position, selectedItems.size)
// Toast.makeText(mUx, "User $username Deleted", Toast.LENGTH_SHORT).show()
}
holder.pminus.setOnClickListener {
if(pos.quantity == 1 ){
// Toast.makeText(mUx,"Can't go any lower", Toast.LENGTH_SHORT).show()
}else {
pos.quantity -= 1
notifyItemChanged(position)
}
}
holder.pplus.setOnClickListener {
pos.quantity += 1
notifyItemChanged(position)
}
}
fun grandTotal(items: ArrayList<ProductModel>): BigDecimal {
totalPrice = BigDecimal.ZERO
for (i in items.indices) {
totalPrice += items[i].unitPrice.multiply(items[i].quantity.toBigDecimal())
}
return totalPrice
}
fun clearData() {
selectedItems.clear()
notifyDataSetChanged()
}
override fun getItemCount() = selectedItems.size
}
and in the Activity:
package com.mycodlabs.pos.ui
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.mycodlabs.pos.R
import com.mycodlabs.pos.db.AndroidDatabase
import com.mycodlabs.pos.db.DatabaseTables
import com.mycodlabs.pos.db.inventory.InventoryDbo
import com.mycodlabs.pos.db.sale.SalesLinesDao
import com.mycodlabs.pos.domain.inventory.ProductModel
import com.mycodlabs.pos.ui.sale.adapter.MyAdapter
import kotlinx.android.synthetic.main.activity_pos.*
import kotlinx.android.synthetic.main.adapter_available_promotions.*
import kotlinx.android.synthetic.main.dialog_paymentsuccession.view.*
import kotlinx.android.synthetic.main.dialog_saleedit.*
import kotlinx.android.synthetic.main.layout_addcategory.*
import kotlinx.android.synthetic.main.layout_sale.*
import kotlinx.android.synthetic.main.listview_stock.*
import kotlinx.android.synthetic.main.pos_bottom_sheet.*
import kotlinx.android.synthetic.main.pos_item_card.*
class PosActivity : AppCompatActivity() {
private lateinit var bottomSheetBehavior: BottomSheetBehavior<LinearLayout>
private lateinit var productNames: ArrayList<String>
private lateinit var recyclerView: RecyclerView
private lateinit var db: SalesLinesDao
//// Create an empty list to store the selected items
var selectedItems = ArrayList<ProductModel>()
//// Create an adapter for the RecyclerView
val adapter = MyAdapter(this,selectedItems)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pos)
// for Back button
back.setOnClickListener {
finish()
}
check_out_Pos.setOnClickListener{
// val pos = ProductModel()
//
// db = SalesLinesDbo(this)
//
// pos.name = pos_name.text.toString()
//
// db.addLineItem(pos.id, LineItemModel())
adapter.clearData()
}
// val autoCompleteTextView = findViewById<AutoCompleteTextView>(R.id.searchBoxPos)
// autoCompleteTextView.threshold = 0
// val suggestions =InventoryDbo.getInstance(applicationContext).allProduct
// var NameArray=suggestions.toList().filter { t -> t.name.contains(autoCompleteTextView)}.toList().map { m->m.name }
// val arrayAdapter = ArrayAdapter(this, android.R.layout.simple_expandable_list_item_2 ,NameArray)
// autoCompleteTextView.setAdapter(arrayAdapter)
// Auto Complete Textview filtering from Product table colm "productName"
val autoCompleteTextView = findViewById<AutoCompleteTextView>(R.id.searchBoxPos)
val productNames = ArrayList<String>()
val dbHelper = AndroidDatabase(this)
val db = dbHelper.readableDatabase
val cursor = db.rawQuery(
"SELECT DISTINCT ${InventoryDbo.colm_productName} FROM ${DatabaseTables.TABLE_PRODUCT} WHERE ${InventoryDbo.colm_productName} like '%%'",
null
)
if (cursor.moveToFirst()) {
do {
productNames.add(cursor.getString(cursor.getColumnIndex(InventoryDbo.colm_productName)))
} while (cursor.moveToNext())
}
cursor.close()
db.close()
val adapterr = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, productNames)
autoCompleteTextView.setAdapter(adapterr)
// //// Auto Complete suggestion item display in recyclerview on select
// // Create the RecyclerView
val recyclerView = findViewById<RecyclerView>(R.id.sale_List_Pos)
//// Create a layout manager for the RecyclerView
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
recyclerView.adapter = adapter
// Set an item click listener for the AutoCompleteTextView
searchBoxPos.setOnItemClickListener { _, _, position, _ ->
// Get the selected product name and product from the list
val selectedItem = autoCompleteTextView.adapter.getItem(position).toString()
// val selectedProductName = productNames[position]
val selectedProduct = InventoryDbo.getInstance(applicationContext).getPosProductByName(selectedItem).first()
//InventoryDbo.getProductByName(selectedProductName)
// Add the selected product to the selected items list
selectedItems.add(selectedProduct)
// Notify the adapter that the data has changed
adapter.notifyDataSetChanged()
// Clear the focus and text from the AutoCompleteTextView
searchBoxPos.clearFocus()
searchBoxPos.setText("")
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
//for the bottomsheet
bottomSheetBehavior = BottomSheetBehavior.from<LinearLayout>(std_btm_sht)
bottomSheetBehavior.setBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, state: Int) {
print(state)
when (state) {
BottomSheetBehavior.STATE_HIDDEN -> {
}
BottomSheetBehavior.STATE_EXPANDED -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_COLLAPSED -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_DRAGGING -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_SETTLING -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_HALF_EXPANDED -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
})
}
}
i hope you can help me solve this because it was bugging me all day and i couldn't find anything about it
I'll post the changes for the plus button, you can then repeat it for the others. Mind that this is just an example, as I don't know in what way you'd like to update the text or what's the actual name of your TextView.
class MyAdapter(
mUx: Context,
var selectedItems: ArrayList<ProductModel>,
val plusLambda: (String) -> Unit // <------
) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val pos: ProductModel = selectedItems[position]
...
holder.pplus.setOnClickListener {
pos.quantity += 1
plusLambda("The new quantity is: ${ pos.quantity }") // <------
notifyItemChanged(position)
}
...
class PosActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pos)
...
val adapterr = ArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line,
productNames) {
someTextView.text = it // <------
}
autoCompleteTextView.setAdapter(adapterr)
...
Of course, you can use just one lambda for all buttons if all you want to do is to change the text of the TextView.

BLE RSSI real time value update Kotlin

I need help with this project, i use BLE and connect it to smartphone and i can get the RSSI value by "ScanResult" in the ScannerFragment but its a static value in the recyclerview, i dont know what to do to make the RSSI value change in real time as i move my phone away/ closer to the BLE device, so it would jump for example from -50dBm to -60dBm as i move the smartphone away from the BLE device
ScannerFragment
import android.Manifest
import android.app.AlertDialog
import android.bluetooth.*
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.support.annotation.RequiresApi
import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import java.util.*
import kotlin.collections.HashSet
class ScannerFragment : Fragment() {
private lateinit var startButton: Button
private lateinit var stopButton: Button
private lateinit var multilateration: TextView
private lateinit var recyclerView: RecyclerView
private lateinit var linearLayoutManager: LinearLayoutManager
private var btManager: BluetoothManager? = null
private var btAdapter: BluetoothAdapter? = null
private var btScanner: BluetoothLeScanner? = null
var beaconSet: HashSet<Beacon> = HashSet()
var beaconAdapter: BeaconsAdapter? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_scanner, container, false)
initViews(view)
setUpBluetoothManager()
return view
}
companion object {
private const val REQUEST_ENABLE_BT = 1
private const val PERMISSION_REQUEST_COARSE_LOCATION = 1
}
private fun initViews(view: View) {
startButton = view.findViewById(R.id.startButton)
stopButton = view.findViewById(R.id.stopButton)
recyclerView = view.findViewById(R.id.recyclerView)
startButton.setOnClickListener { onStartScannerButtonClick() }
stopButton.setOnClickListener { onStopScannerButtonClick() }
linearLayoutManager = LinearLayoutManager(context)
recyclerView.layoutManager = linearLayoutManager
beaconAdapter = BeaconsAdapter(beaconSet.toList())
recyclerView.adapter = beaconAdapter
multilateration = view.findViewById(R.id.multilateration)
}
private fun onStartScannerButtonClick() {
startButton.setBackgroundColor(Color.GREEN)
startButton.visibility = View.GONE
stopButton.visibility = View.VISIBLE
beaconSet.clear()
btScanner?.startScan(leScanCallback)
}
private fun onStopScannerButtonClick() {
stopButton.setBackgroundColor(Color.RED)
stopButton.visibility = View.GONE
startButton.visibility = View.VISIBLE
//beaconAdapter?.beaconList?.clear()
beaconSet.clear()
btScanner?.stopScan(leScanCallback)
}
private fun setUpBluetoothManager() {
btManager = activity?.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
btAdapter = btManager!!.adapter
btScanner = btAdapter?.bluetoothLeScanner
if (btAdapter != null && !btAdapter!!.isEnabled) {
val enableIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableIntent, REQUEST_ENABLE_BT)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkForLocationPermission()
}
}
#RequiresApi(Build.VERSION_CODES.M)
private fun checkForLocationPermission() {
// Make sure we have access coarse location enabled, if not, prompt the user to enable it
if (requireActivity().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
val builder = AlertDialog.Builder(activity)
builder.setTitle("This app needs location access")
builder.setMessage("Please grant location access so this app can detect the BLE.")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener {
requestPermissions(
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
PERMISSION_REQUEST_COARSE_LOCATION
)
}
builder.show()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>, grantResults: IntArray
) {
when (requestCode) {
PERMISSION_REQUEST_COARSE_LOCATION -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
println("coarse location permission granted")
} else {
val builder = AlertDialog.Builder(activity)
builder.setTitle("Functionality limited")
builder.setMessage("Since location access has not been granted, this app will not be able to discover BLE beacons")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener { }
builder.show()
}
return
}
}
}
private val leScanCallback: ScanCallback = object : ScanCallback() {
#RequiresApi(Build.VERSION_CODES.O)
override fun onScanResult(callbackType: Int, result: ScanResult) {
val scanRecord = result.scanRecord
val beacon = Beacon(result.rssi)
beacon.manufacturer = result.device.name
beacon.macAddress = result.device.address
beacon.rssi = result.rssi
if (scanRecord != null) {
val iBeaconManufactureData = scanRecord.getManufacturerSpecificData(0X004c)
if (iBeaconManufactureData != null && iBeaconManufactureData.size >= 23) {
val iBeaconUUID = Utility.toHexString(iBeaconManufactureData.copyOfRange(2, 18))
val major = Integer.parseInt(
Utility.toHexString(
iBeaconManufactureData.copyOfRange(
18,
20
)
), 16
)
val minor = Integer.parseInt(
Utility.toHexString(
iBeaconManufactureData.copyOfRange(
20,
22
)
), 16
)
beacon.type = Beacon.BeaconType.iBeacon
beacon.name = beacon.manufacturer
beacon.uuid = iBeaconUUID
beacon.major = major
beacon.txPower = result.txPower
beacon.minor = minor
Log.e("BeaconID", "iBeaconUUID:$iBeaconUUID major:$major minor:$minor")
}
if(beacon.name == "Beacon_1" || beacon.name == "Beacon_2" || beacon.name == "Beacon_3" || beacon.name == "Beacon_4" ) {
beaconSet.add(beacon)
}
(recyclerView.adapter as BeaconsAdapter).updateData(beaconSet.toList())
}
}
override fun onScanFailed(errorCode: Int) {
Log.e("Failed", errorCode.toString())
}
}
}
BeaconsAdapter
import android.os.Build
import android.support.annotation.RequiresApi
import android.support.v4.content.ContextCompat
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import java.util.*
class BeaconsAdapter(beacons: List<Beacon>) :
RecyclerView.Adapter<BeaconsAdapter.BeaconHolder>() {
var beaconList: MutableList<Beacon> = beacons.toMutableList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BeaconHolder {
val inflater = LayoutInflater.from(parent.context)
return BeaconHolder(inflater, parent)
}
override fun onBindViewHolder(holder: BeaconHolder, pos: Int) {
val beacon: Beacon = beaconList[pos]
holder.bind(beacon)
}
override fun getItemCount() = beaconList.size
#RequiresApi(Build.VERSION_CODES.N)
fun updateData(data: List<Beacon>) {
beaconList.clear()
beaconList.addAll(data)
notifyDataSetChanged()
}
class BeaconHolder(inflater: LayoutInflater, parent: ViewGroup) :
RecyclerView.ViewHolder(inflater.inflate(R.layout.scan_result_items, parent, false)) {
private var image: ImageView? = null
private var mac: TextView? = null
private var name: TextView? = null
private var instanceMajorMinor: TextView? = null
private var namespaceUUID: TextView? = null
private var beaconRSSI: TextView? = null
private val context = parent.context
init {
image = itemView.findViewById(R.id.beacon_image)
mac = itemView.findViewById(R.id.beacon_mac)
name = itemView.findViewById(R.id.beacon_name)
instanceMajorMinor = itemView.findViewById(R.id.beacon_instance_major_minor)
beaconRSSI = itemView.findViewById(R.id.beacon_rssi)
}
fun bind(beacon: Beacon) {
mac?.text = String.format(
context.getString(R.string.mac),
beacon.macAddress
)
beaconRSSI?.text = String.format(
context.getString(R.string.rssi),
beacon.rssi
)
if (beacon.type == Beacon.BeaconType.iBeacon) {
namespaceUUID?.text = String.format(context.getString(R.string.uuid), beacon.uuid)
name?.text = String.format(context.getString(R.string.name), beacon.name)
//namespace
instanceMajorMinor?.text = String.format(
context.getString(R.string.major_minor),
beacon.major,
beacon.minor
)
image?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ibeacon))
instanceMajorMinor?.visibility = View.VISIBLE
namespaceUUID?.visibility = View.VISIBLE
}
}
}
}
Beacon
class Beacon(rssi: Int?) {
enum class BeaconType {
iBeacon
}
var macAddress : String? = null
var manufacturer: String? = null
var type: BeaconType = BeaconType.iBeacon
var uuid: String? = null
var name: String? = null
var major: Int? = null
var minor: Int? = null
var txPower: Int? = null
var rssi = rssi
override fun equals(other: Any?): Boolean{
if(this === other) return true
if(other !is Beacon) return false
if(macAddress != other.macAddress) return false
return true
}
override fun hashCode(): Int {
return macAddress?.hashCode() ?:0
}
}

How to send a variable to an Adapter to send it through an Intent to another activity?

I have an adapter for my RecyclerView where I program that when I click on the element (of my RecyclerView) it executes an Intent with a putExtra to take me to another activity, the variable that contains my putExtra comes from the element that I clicked, but now I need to add a More variable that comes from the activity. The issue is that I don't know how to send it from the adapter.
this is my adapter.
package com.example.atipicoapp
import android.app.Activity
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.list_item.view.*
class MyAdapter(private val platoList : ArrayList<Plato>
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter.MyViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
itemView.platoTouch.setOnClickListener(View.OnClickListener { v: View ->
})
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
val plato: Plato = platoList[position]
holder.platoName.text = plato.platoName
holder.platoDescription.text = plato.platoDescription
holder.platoPrecio.text = plato.platoPrecio.toString()
holder.platoCantidad.text = plato.platoCantidad.toString()
when(holder){
is MyViewHolder -> {
holder.bind(platoList[position])
}
}
}
override fun getItemCount(): Int {
return platoList.size
}
public class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val platoName: TextView = itemView.findViewById(R.id.platoNombre)
val platoDescription: TextView = itemView.findViewById(R.id.platoDescripcion)
val platoPrecio: TextView = itemView.findViewById(R.id.platoPrecio)
val platoTouch: LinearLayout = itemView.findViewById(R.id.platoTouch)
val platoCantidad: TextView = itemView.findViewById(R.id.platoCant)
private val mActivity = itemView.context as Activity
private val intent = Intent(mActivity,SlotActivity::class.java)
fun bind(plato: Plato){
platoTouch.setOnClickListener{
intent.putExtra("id", platoName.text.toString())
mActivity.startActivity(intent)
}
}
}
}
And this is my Activity which contains my RecyclerView and the variable I want to send.
package com.example.atipicoapp
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.firestore.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_menu_atipico.*
class MenuAtipicoActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var platoArrayList: ArrayList<Plato>
private lateinit var myAdapter: MyAdapter
private lateinit var db: FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu_atipico)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
platoArrayList = arrayListOf()
myAdapter = MyAdapter(platoArrayList)
recyclerView.adapter = myAdapter
pedidoId = intent.extras?.getString("pedidoId") //This is the variable I need to send
EventChangeListener()
Setup()
}
private fun EventChangeListener() {
db = FirebaseFirestore.getInstance()
db.collection("Platos").addSnapshotListener(object : EventListener<QuerySnapshot> {
override fun onEvent(
value: QuerySnapshot?,
error: FirebaseFirestoreException?
) {
if (error != null) {
Log.e("Firestore Error", error.message.toString())
return
}
for (dc: DocumentChange in value?.documentChanges!!) {
if (dc.type == DocumentChange.Type.ADDED) {
platoArrayList.add(dc.document.toObject(Plato::class.java))
}
}
myAdapter.notifyDataSetChanged()
}
})
}
private fun Setup() {
botonAceptar.setOnClickListener {
val SlotIntent = Intent(this, SlotActivity::class.java).apply {
}
startActivity(SlotIntent)
}
}
}
How can I send the variable if the Intent is executed from the Adapter?
Or... If it is not recommended to send intent from my Adapter, how can I send them from the activity?
Knowing that I have to carry a variable that is in the item of the RecyclerView.
Thanks for your help <3
Firstly, create a MyAdapter constructor where you pass arrayList as well as pedidoId like, your MyAdapter should be something like below:
MyAdapter.class
class MyAdapter(private val platoList : ArrayList<Plato>, val pedidoId:String
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
........
.....
....
//in your bind(..) method
fun bind(plato: Plato){
platoTouch.setOnClickListener{
intent.putExtra("id", platoName.text.toString())
intent.putExtra("pedidoId", pedidoId)
mActivity.startActivity(intent)
}
}
}
And, in your MenuAtipicoActivity you need to do something like:
MenuAtipicoActivity
class MenuAtipicoActivity : AppCompatActivity() {
...............
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu_atipico)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
platoArrayList = arrayListOf()
pedidoId = intent.extras?.getString("pedidoId") //This is the variable I need to send
myAdapter = MyAdapter(platoArrayList,pedidoId)
recyclerView.adapter = myAdapter
EventChangeListener()
Setup()
}
..........
........
}

Add markers to a map with Firebase

I want to make an application with Kotlin and Google Maps in which the user can add markers on the Google Map and that these markers are sent to Firebase and other users can see those same markers on the map.
This is what I have done but it is not working well for me.
package com.racrapa.displayinglocationapp
import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.annotation.NonNull
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.firebase.database.*
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
private const val TAG = "MapsActivity"
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
public lateinit var databaseRef: DatabaseReference
private lateinit var database: DatabaseReference
private var markers: MutableList<Marker> = mutableListOf()
private var postListener: ValueEventListener? = null
var mDatabase: DatabaseReference? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
databaseRef = Firebase.database.reference
mDatabase = FirebaseDatabase.getInstance().reference.child("userlocation")
database = Firebase.database.reference
}
This is to get the data from Firebase
public override fun onStart() {
super.onStart()
var postListener: ValueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val locationlogging = dataSnapshot.child("userlocation").getValue(LocationLogging::class.java)
var driverLat=locationlogging?.Latitude
var driverLong=locationlogging?.Longitude
if (driverLat != null && driverLong != null) {
val driverLoc = LatLng(driverLat, driverLong)
val markerOptions = MarkerOptions().position(driverLoc).title("Driver")
mMap.addMarker(markerOptions)
Toast.makeText(applicationContext, "Locations accessed from the database", Toast.LENGTH_LONG).show()
}
}
}
override fun onCancelled(error: DatabaseError) {}
}
databaseRef.addValueEventListener(postListener)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
mMap.setOnMapLongClickListener { latLng ->
Log.i(TAG, "onMapLongClickListener")
setMapLongClick(latLng)
}
}
This is the function of sending coordinates to Firebase
private fun setMapLongClick(latLng: LatLng) {
if (latLng != null) {
Log.e("Latitude: ", latLng.latitude.toString() + "longitude: " + latLng.longitude)
val latlang: MutableMap<String, Double> = HashMap()
latlang["latitude"] = latLng.latitude
latlang["longitude"] = latLng.longitude
mDatabase!!.child("userlocation").push().setValue(latlang)
onStart()
}
}
}

Retrieve display profiles using UID on a FirestoreRecycler Adapter using Kotlin?

I am having difficulties retrieving the information correctly from Firebase Firestore for my Recycler Adapter. I am not sure what I might be doing wrong but I used a Document Reference to get the required field but now it seems to just copy the same thing over and over, I want it to display each created users profile and display it on my RecyclerAdapter but am not sure what I should do and have tried different methods but get a
"No setter/field error" on my Model Class "Users".
This is my Firebase Schema
This is what it is outputting
This is what I have my code as so far
[Update]
This is what I have imported
import Models.User
import android.content.Intent
import android.content.res.Configuration
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.android.material.navigation.NavigationView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.*
import com.squareup.picasso.Picasso
import de.hdodenhof.circleimageview.CircleImageView
import kotlinx.android.synthetic.main.all_nearby_users.*
import kotlinx.android.synthetic.main.toolbar_layout.*
Oncreate
auth = FirebaseAuth.getInstance()
val customUserId = auth.currentUser!!.uid
val db = FirebaseFirestore.getInstance()
val userRef = db.collection("sUsers").document(customUserId)
val userQuery = db.collection("sUsers").orderBy("Full Name", Query.Direction.DESCENDING).limit(10)
//User List Layout
all_users_nearby_list.layoutManager = LinearLayoutManager(this)
//Firestore
val firestoreRecyclerOptions: FirestoreRecyclerOptions<Users> = FirestoreRecyclerOptions.Builder<Users>()
.setQuery(userQuery, Users::class.java)
.build()
adapter = UserFirestoreRecyclerAdapter(firestoreRecyclerOptions)
all_users_nearby_list.adapter = adapter
Firestore Recycler Adapter
private inner class UserFirestoreRecyclerAdapter internal constructor
(firestoreRecyclerOptions: FirestoreRecyclerOptions<Users>): FirestoreRecyclerAdapter<Users, UserViewHolder>(firestoreRecyclerOptions) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val userView = LayoutInflater.from(parent.context)
.inflate(R.layout.display_users_profile, parent, false)
return UserViewHolder(userView)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int, model: Users) {
holder.setFullname(model.fullname)
holder.setProfileimage(model.profileImage)
}
}
UserViewHolder
private inner class UserViewHolder internal constructor (private val pView: View) : RecyclerView.ViewHolder(pView) {
internal fun setFullname(fullname: String) {
val username = pView.findViewById<TextView>(R.id.usernameTextView)
val db = FirebaseFirestore.getInstance()
val docRef = db.collection("sUsers").document(auth.currentUser!!.uid)
docRef.get()
.addOnSuccessListener { document ->
if (document != null) {
Log.d("HomeActivity", "DocumentSnapshot data: ${document.data}")
username.text = document.getString("Full Name")
} else {
Log.d("HomeActivity", "No such document")
}
}
.addOnFailureListener { exception ->
Log.d("HomeActivity", "get failed with ", exception)
}
username.text = fullname
Log.d("HomeActivity", "Current Data: " + fullname)
}
internal fun setProfileimage(profileImage: String) {
val userProfileImage = pView.findViewById<CircleImageView>(R.id.profileUserImage)
Picasso.get().load(profileImage).into(userProfileImage)
}
}
Model Class
package Models
class Users(
var fullname: String= "",
var profileImage: String= "",
var uid: String? = "",
var haircut: Boolean? = null,
var waxing: Boolean? = null,
var nails: Boolean? = null,
var profileRatingBar: Float? = 1.0f
)
My onStart and onStop
override fun onStart() {
super.onStart()
adapter!!.startListening()
}
override fun onStop() {
super.onStop()
if (adapter != null) {
adapter!!.stopListening()
}
}
This is how I would write your RecyclerView. Key points:
Don't make a 2nd FireStore query inside the ViewHolder
Your Firestore schema must exactly match your model
Use lifecycle owner instead of onStart/onStop
Firebase UI doesn't capture the uid; so do this manually (see apply)
ViewHolder must "hold" the views as fields (to avoid calling find every time)
Model represents 1 object, so I name it "User" not "Users"
Set layoutManager in XML to reduce boilerplate in onCreate
Layout XML
<androidx.recyclerview.widget.RecyclerView
...
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="5"
tools:listitem="#layout/display_users_profile"
... />
Activity onCreate
val query = FirebaseFirestore.getInstance()
.collection("sUsers") // Why not "users" ?
.orderBy("fullname", Query.Direction.DESCENDING)
.limit(10)
val options = FirestoreRecyclerOptions.Builder<User>()
.setLifeCycleOwner(this)
.setQuery(query) { it.toObject(User::class.java)!!.apply { uid = it.id } }
.build()
all_users_nearby_list.adapter = UserFirestoreRecyclerAdapter(options)
Adapter
internal class UserFirestoreRecyclerAdapter(options: FirestoreRecyclerOptions<User>) :
FirestoreRecyclerAdapter<User, UserViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
LayoutInflater.from(parent.context)
.inflate(R.layout.display_users_profile, parent, false)
.let { UserViewHolder(it) }
override fun onBindViewHolder(holder: UserViewHolder, position: Int, model: Users) =
holder.bind(model)
}
ViewHolder
internal class UserViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
// Hold view refs
private val usernameTextView: TextView = itemView.userNameTextView
private val profileUserImage: ImageView = itemView.profileUserImage
internal fun bind(model: User) {
model.apply {
usernameTextView.text = fullname
Picasso.get().load(profileImage).into(profileUserImage)
}
}
}
Model
// Set sensible defaults here (or null if no sensible default)
data class User(
var uid: String = "",
var fullname: String= "",
var profileImage: String= "",
var haircut: Boolean = false,
var waxing: Boolean = false,
var nails: Boolean = false,
var profileRatingBar: Float? = null
)