A flaw inside app when using recyclerview to load documents from firestore in kotlin - firebase

I am using recycler view to load documents from firestore. Now my recycler view lists has three buttons. One of the button name is notify. When I click notify button(btn_notify) I want to make the button visibity to gone using holder.button.visibility = View.GONE. But what happens is that when I change the button visibility to gone, the clicked button visibility changes to gone. At the same time the other recycler view lists button visibility also changes to gone. Why this error is happening.
[![enter image description here][1]][1]
package com.example.bloodbankcompany.recyclerview
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
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 androidx.recyclerview.widget.RecyclerView
import com.example.bloodbankcompany.*
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.lang.Exception
const val TOPIC = "/topics/myTopic"
class MyAdapter2(private val userList: ArrayList<User2>): RecyclerView.Adapter<MyAdapter2.MyViewHolder>(){
var id: String = ""
private lateinit var userArrayList: ArrayList<User2>
private val mFireStore = FirebaseFirestore.getInstance()
val TAG = "MyAdapter2"
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter2.MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.list_item2,parent,false)
return MyViewHolder(itemView)
}
//
// interface OnItemClickListener {
// fun onItemClick(position: Int)
// }
override fun onBindViewHolder(holder: MyAdapter2.MyViewHolder, position: Int) {
// holder.bind( position ,onItemClickListener)
val user:User2 = userList[position]
holder.name.text= user.name
holder.phone.text= user.phone
holder.address.text =user.address
holder.bloodGroup.text= user.bloodgroup
holder.id.text = user.id
holder.status.text= user.status
holder.donatedby.text = user.donatedBy.toString()
val statust = user.status?.trim()
val requester_name = user.name
val requester_no = user.phone
holder.emailn.text= user.email
val idp: String? =user.id
val phonen: String? =user.phone
val emailt: String? = user.email
holder.button.setOnClickListener {
holder.button.visibility = View.GONE
val washingtonre = mFireStore.collection("applicationForm").document("$idp")
washingtonre.update("status","Verified").addOnCompleteListener {
holder.status.text = "Verified"
val title = "New blood donation request."
val message = "Please contact $requester_name at $requester_no."
//val recipientToken = etToken.text.toString()
if(title.isNotEmpty() && message.isNotEmpty()) {
PushNotificationNotif(
NotificationDataNotif(title, message),
TOPIC
// recipientToken
).also {
sendNotification(it)
}
}
}
}
holder.phonen.setOnClickListener {
val context=holder.button.context
val intent1 = Intent(Intent.ACTION_DIAL)
intent1.data = Uri.parse("tel:" + phonen)
context.startActivity(intent1)
}
holder.bemail.setOnClickListener {
val context1=holder.button.context
val intent= Intent(Intent.ACTION_SEND)
intent.data = Uri.parse("mailto:" + emailt)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_EMAIL, emailt)
intent.putExtra(Intent.EXTRA_SUBJECT, " ")
intent.putExtra(Intent.EXTRA_TEXT, " ")
intent.setType("message/rfc822")
try {
// context1.startActivity(Intent.createChooser(intent, "Choose email Client"))
context1.startActivity(intent)
} catch (e: Exception){
}
}
}
#SuppressLint("LongLogTag")
private fun sendNotification(notification: PushNotificationNotif) = CoroutineScope(
Dispatchers.IO).launch {
try {
val response = RetrofitInstanceNotif.api.postNotification(notification)
if(response.isSuccessful) {
Log.d(TAG, "Response: ${Gson().toJson(response)}")
} else {
Log.e(TAG, response.errorBody().toString())
}
} catch(e: Exception) {
Log.e(TAG, e.toString())
}
}
override fun getItemCount(): Int {
return userList.size
}
public class MyViewHolder(itemView : View): RecyclerView.ViewHolder(itemView){
// fun bind(position: Int, listener: OnItemClickListener) {
// button.setOnClickListener { v -> listener.onItemClick(position) }
// }
val name : TextView = itemView.findViewById(R.id.tvfirstname1)
val phone :TextView= itemView.findViewById(R.id.tvphone11)
val address : TextView= itemView.findViewById(R.id.tvaddress1)
val bloodGroup: TextView =itemView.findViewById(R.id.tvbloodg1)
val id: TextView = itemView.findViewById(R.id.tvid)
val status: TextView = itemView.findViewById(R.id.tvstatus1)
// val donationsta: TextView = itemView.findViewById(R.id.tvdonated1)
var io: String? = ""
val button: Button = itemView.findViewById(R.id.btn_notify)
val phonen: Button =itemView.findViewById(R.id.btn_phone1)
val emailn: TextView = itemView.findViewById(R.id.tvemail1)
val bemail: TextView = itemView.findViewById(R.id.btn_email1)
val donatedby: TextView=itemView.findViewById(R.id.tvdonated1)
}
} ```
/** This is the recyclerview activity code
package com.example.bloodbankcompany.recyclerview
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.WindowManager
import android.widget.Adapter
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.bloodbankcompany.MyAdapter
import com.example.bloodbankcompany.R
import com.example.bloodbankcompany.User1
import com.example.bloodbankcompany.User2
import com.google.firebase.firestore.*
import kotlinx.android.synthetic.main.activity_blood_application_form.*
import kotlinx.android.synthetic.main.activity_main2.*
import java.lang.NullPointerException
class MainActivity2 : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var userArrayList: ArrayList<User2>
private lateinit var myAdapter: MyAdapter2
private val mFireStore = FirebaseFirestore.getInstance()
var db = FirebaseFirestore.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
// setupActionBar()
recyclerView= findViewById(R.id.recyclerview)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
userArrayList= arrayListOf()
myAdapter =MyAdapter2(userArrayList)
recyclerView.adapter = myAdapter
EventChangeListener()
}
private fun EventChangeListener() {
try {
mFireStore.collection("applicationForm").addSnapshotListener(object :
EventListener<QuerySnapshot> {
override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
if (error != null) {
Log.e("firestore error", error.message.toString())
}
try {
for (dc: DocumentChange in value?.documentChanges!!) {
if (dc.type == DocumentChange.Type.ADDED) {
userArrayList.add(dc.document.toObject(User2::class.java))
}
// Toast.makeText(applicationContext,userArrayList.toString(), Toast.LENGTH_SHORT).show()
}
} catch (e:NullPointerException){
}
myAdapter.notifyDataSetChanged()
}
})
} catch (e:NullPointerException){
}
}
}
[1]: https://i.stack.imgur.com/loob8.jpg

Related

User does not have permission to access this object: Firebase error

I have an app in which the user can upload images to create a task list. But, whenever I upload the image and say "create", the onFailureListener is called and "User does not have permission to access this object" occurs.
My firebase rules:
// Allow read/write access on all documents to any user signed in to the application
service cloud.firestore {
match /databases/{database}/documents {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
I tried all the rules mentioned on User does not have permission to access this object . Firebase storage android
All of these result in another error which is "Error in updating Profile". This is the line I had added on the onFailureListener when the profile data is loaded initially.
Below is my CreateBoardActivity.kt class- when I upload an image and then click on the "btn_create" button, the error (User does not have permission to access this object) pops up. (I suppose the "uploadBoardImage()" method is called in this scenario)
package com.example.projectmanager.activities
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.bumptech.glide.Glide
import com.example.projectmanager.Firebase.FireStoreClass
import com.example.projectmanager.R
import com.example.projectmanager.models.Board
import com.example.projectmanager.utils.Constants
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import kotlinx.android.synthetic.main.activity_create_board.*
import java.io.IOException
class CreateBoardActivity : BaseActivity() {
private var mSelectedImageFileUri : Uri? = null
private lateinit var mUserName: String
private var mBoardImageURL : String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_board)
setUpActionBar()
if(intent.hasExtra(Constants.NAME)){
mUserName = intent.getStringExtra(Constants.NAME).toString()
}
iv_board_image.setOnClickListener{
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
Constants.showImageChooser(this)
}else{
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), Constants.READ_STORAGE_PERMISSION_CODE)
}
}
btn_create.setOnClickListener {
if(mSelectedImageFileUri != null){
uploadBoardImage()
}
else{
showProgressDialog(resources.getString(R.string.please_wait))
createBoard()
}
}
}
private fun createBoard(){
val assignedUsersArrayList: ArrayList<String> = ArrayList()
assignedUsersArrayList.add(getCurrentUserId())
val board = Board(et_board_name.text.toString(), mBoardImageURL, mUserName, assignedUsersArrayList)
FireStoreClass().createBoard(this, board)
}
private fun uploadBoardImage(){
showProgressDialog(resources.getString(R.string.please_wait))
val sRef : StorageReference = FirebaseStorage.getInstance().reference.child(
"BOARD_IMAGE" + System.currentTimeMillis() + "." + Constants.getFileExtension(this, mSelectedImageFileUri))
sRef.putFile(mSelectedImageFileUri!!).addOnSuccessListener {
taskSnapshot->
Log.i("Board Image URL", taskSnapshot.metadata!!.reference!!.downloadUrl.toString())
taskSnapshot.metadata!!.reference!!.downloadUrl.addOnSuccessListener {
uri->
Log.i("Downloadable Image URL", uri.toString())
mBoardImageURL = uri.toString()
createBoard()
}
}.addOnFailureListener{
exception->
Toast.makeText(this, exception.message, Toast.LENGTH_LONG).show()
hideProgressionDialog()
}
}
fun boardCreatedSuccessfully(){
hideProgressionDialog()
setResult(Activity.RESULT_OK)
finish()
}
private fun setUpActionBar(){
setSupportActionBar(toolbar_create_board_activity)
val actionBar = supportActionBar
if(actionBar!=null){
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setHomeAsUpIndicator(R.drawable.ic_black_color_white_24dp)
actionBar.title = resources.getString(R.string.create_board_title)
}
toolbar_create_board_activity.setNavigationOnClickListener { onBackPressed() }
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode== Constants.READ_STORAGE_PERMISSION_CODE){
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){
}
}else{
Toast.makeText(this, "You have denied the permission for storage. You can allow it from settings", Toast.LENGTH_LONG).show()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK && requestCode == Constants.PICK_IMAGE_REQUEST_CODE && data!!.data != null){
mSelectedImageFileUri = data.data
try{
Glide.with(this)
.load(mSelectedImageFileUri)
.centerCrop()
.placeholder(R.drawable.ic_board_place_holder)
.into(iv_board_image)
}catch(e: IOException){
e.printStackTrace()
}
}
}
}
Please do let me know what rules I should use to fix this issue.

updat listview in an activity after click update button in custom adapter

I have an activity (ProductList) contain listview to view all products in my database, and a custom adapter for the list (MyListAdapter) that contains update button when I click on it a dialoge open and update the product info.
I want that when I update the product info and close the dialog the listview updated in the same time.
ProductsList Activity
class ProductsList : AppCompatActivity() {
private lateinit var databaseHandler:DatabaseHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_products_list)
databaseHandler = DatabaseHandler(this)
val product: ArrayList<Product> = databaseHandler.listProduct()
val productArrayId = Array(product.size){"0"}
val productArrayName = Array(product.size){"null"}
val productArrayQuantity = Array(product.size){"null"}
val allInfo = Array(product.size){"null"}
for((index, e) in product.withIndex()){
productArrayId[index] = e.getProductID().toString()
productArrayName[index] = e.getProductName()
productArrayQuantity[index] = e.getProductQuantity().toString()
allInfo[index] = e.getProductID().toString() + " " + e.getProductName() + " " + e.getProductQuantity().toString()
}
var myListAdapter = MyListAdapter(this,product)
lv_products.adapter = myListAdapter
}
}
MyListAdapter class
class MyListAdapter(private val context: Activity, private val products: ArrayList<Product>) : BaseAdapter() {
private var databaseHandler = DatabaseHandler(this.context)
override fun getCount(): Int {
return products.size
}
override fun getItem(position: Int): Any {
return products[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
#SuppressLint("ViewHolder")
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val inflater = LayoutInflater.from(context)
val customView = inflater.inflate(R.layout.custom_list, parent, false)
customView.tv_product_id.text = products[position].getProductID().toString()
customView.tv_product_name.text = products[position].getProductName()
customView.tv_product_quantity.text = products[position].getProductQuantity().toString()
customView.btn_edit_product.setOnClickListener {
val layout = LayoutInflater.from(context)
val view = layout.inflate(R.layout.update_dialog, null)
view.et_product_id.setText(products[position].getProductID().toString())
view.et_product_name.setText(products[position].getProductName())
view.et_product_quantity.setText(products[position].getProductQuantity().toString())
AlertDialog.Builder(context).setView(view).setTitle("update product info")
.setPositiveButton("yes") { _, _ ->
val status = databaseHandler.updateProduct(
view.et_product_id.text.toString().toInt(),
view.et_product_name.text.toString(),
view.et_product_quantity.text.toString().toInt()
)
if (status > -1) {
Toast.makeText(this.context, "record updated", Toast.LENGTH_LONG).show()
this.notifyDataSetChanged()
} else {
Toast.makeText(this.context, "update error", Toast.LENGTH_LONG).show()
}
}
.setNegativeButton("no") { _, _ -> }
.setIcon(R.drawable.ic_baseline_warning_24)
.show()
this.notifyDataSetChanged()
}
return customView
}
}

How best to implement viewmodel with SwipeRefresh

I'm creating my model with modelview and services. This is the best way to create with swipeRefresh
I don't know if I'm doing it the right way so I'm asking for your help
who can give feedback thank you very much.
In fact everything is working perfectly I'm just in doubt about this part:
val viewModel: MyViewModel = viewModel()
val isRefreshing by viewModel.isRefreshing.collectAsState()
my method SwipeRefresh:
#Composable
fun SwipeRefresh( content: #Composable (lists:ArrayList<ShoppingCart>) -> Unit){
val viewModel: MyViewModel = viewModel()
val isRefreshing by viewModel.isRefreshing.collectAsState()
com.google.accompanist.swiperefresh.SwipeRefresh(
state = rememberSwipeRefreshState(isRefreshing),
onRefresh = { viewModel.refresh() },
indicator = { state, trigger ->
SwipeRefreshIndicator(
// Pass the SwipeRefreshState + trigger through
state = state,
refreshTriggerDistance = trigger,
// Enable the scale animation
scale = true,
// Change the color and shape
shape = MaterialTheme.shapes.small,
)
}
) {
if(isRefreshing){
if(tipos=="frutas"){
tipos = "fruta"
}
frutas.tipo=tipos
frutas.getFrutas()
when(tipos){
"saladas"->{
val s by frutas.saladasData.collectAsState(initial = emptyList())
list = ArrayList(s)
}
"fruta"->{
val f by frutas.frutaData.collectAsState(initial = emptyList())
list = ArrayList(f)
}
"temperos"->{
val t by frutas.temperosData.collectAsState(initial = emptyList())
list = ArrayList(t)
}
}
}
Log.i("LIST",list.toString())
val t = list.filter { it.product_title!="" }
if(list.isNotEmpty() && t.isNotEmpty()){
content(list)
}else{
helpers.loadingComponent()
}
}
}
My ViewModel:
package com.example.quitanda.models
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
class FrutasViewModel(
private val frutasServices: Services,
):ViewModel() {
private val _frutasData: MutableStateFlow<List<ShoppingCart>> = MutableStateFlow(listOf(ShoppingCart()))
val frutasData: StateFlow<List<ShoppingCart>>
get() = _frutasData
private val _frutaData: MutableStateFlow<List<ShoppingCart>> = MutableStateFlow(listOf(ShoppingCart()))
val frutaData: StateFlow<List<ShoppingCart>>
get() = _frutaData
private val _saladasData: MutableStateFlow<List<ShoppingCart>> = MutableStateFlow(listOf(ShoppingCart()))
val saladasData: StateFlow<List<ShoppingCart>>
get() = _saladasData
private val _temperosData: MutableStateFlow<List<ShoppingCart>> = MutableStateFlow(listOf(ShoppingCart()))
val temperosData: StateFlow<List<ShoppingCart>>
get() = _temperosData
lateinit var tipo:String
fun getFrutas(){
viewModelScope.launch {
try {
when(tipo){
"fruta"->{
val fruta = frutasServices.getFrutas1()
_frutaData.value = fruta
}
"frutas"->{
val frutas = frutasServices.getFruta()
_frutasData.value = frutas
}
"saladas"->{
val saladas = frutasServices.getSaladas()
_saladasData.value = saladas
}
"temperos"->{
val temperos = frutasServices.getTemperos()
_temperosData.value = temperos
}
}
}catch (e:Exception){
Log.d("Service error",e.toString())
}
}
}
}
Service:
package com.example.quitanda.models
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET
interface Services {
#GET("category/")
suspend fun getFruta(): List<ShoppingCart>
#GET("category/7")
suspend fun getFrutas1(): List<ShoppingCart>
#GET("category/8")
suspend fun getSaladas(): List<ShoppingCart>
#GET("category/9")
suspend fun getTemperos(): List<ShoppingCart>
}
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("http://192.168.2.157:4000/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
val frutasServices: Services = retrofit.create(Services::class.java)
My Activity:
package com.example.quitanda
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.ShoppingCart
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.compose.*
import com.example.quitanda.classes.EntryAbstract
import com.example.quitanda.classes.Helpers
import com.example.quitanda.models.FrutasViewModel
import com.example.quitanda.models.ShoppingCart
import com.example.quitanda.models.frutasServices
import com.google.accompanist.pager.ExperimentalPagerApi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
#Suppress("UNCHECKED_CAST")
#ExperimentalPagerApi
class MainActivity : ComponentActivity() {
private val entryAbstract = EntryAbstract()
private var counter = mutableStateOf(0)
private var ids = mutableStateListOf<ShoppingCart>()
private lateinit var listFrutas:ArrayList<ShoppingCart>
private lateinit var listSaladas:ArrayList<ShoppingCart>
private lateinit var listChas:ArrayList<ShoppingCart>
private val helpers = Helpers()
private val viewModel by viewModels<FrutasViewModel> {
object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return FrutasViewModel(frutasServices) as T
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent{
if(intent.hasExtra("produtos")) {
ids = remember { intent.getParcelableArrayListExtra<ShoppingCart>("produtos")!!
.toMutableStateList()}
if (ids.isNotEmpty()) {
val aray = ids.count()
counter.value = aray
}
}
viewModel.tipo="frutas"
viewModel.getFrutas()
val l by viewModel.frutasData.collectAsState(initial = emptyList())
if (l.isEmpty()) {
helpers.loadingComponent()
} else {
val i = l.filter { it.category_id==7 }
val o = l.filter { it.category_id==8 }
val p = l.filter { it.category_id==9 }
listFrutas = ArrayList(i)
listSaladas = ArrayList(o)
listChas = ArrayList(p)
entryAbstract.cart =ids
entryAbstract.ccounter =counter
entryAbstract.frutas = viewModel
MainContent()
}
}
}
ShoppingCart:
package com.example.quitanda.models
import android.os.Parcelable
import com.squareup.moshi.Json
import kotlinx.parcelize.Parcelize
#Parcelize
data class ShoppingCart(
var count:Int=0,
#field:Json(name="product_title")
var product_title:String="",
#field:Json(name="product_id")
var product_id:Int=0,
#field:Json(name="photo_photo")
var photo_photo:String="",
#field:Json(name="product_quant")
var product_quant:Int=0,
#field:Json(name="category_name")
var category_name:String="",
#field:Json(name="category_id")
var category_id:Int=0,
#field:Json(name="product_description")
var product_description:String="",
#field:Json(name="product_price_un")
var product_price_un:String?="",
#field:Json(name="product_price_kg")
var product_price_kg:String?="",
var tipos:String=""): Parcelable
I understand seeing my MyViewModel
class MyViewModel : ViewModel() {
private val _isRefreshing = MutableStateFlow(false)
val isRefreshing: StateFlow<Boolean>
get() = _isRefreshing.asStateFlow()
fun refresh() {
// This doesn't handle multiple 'refreshing' tasks, don't use this
viewModelScope.launch {
// A fake 2 second 'refresh'
_isRefreshing.emit(true)
delay(2000)
_isRefreshing.emit(false)
}
}
}
how I make a viewmodel with multiple returns is a little different

Kotlin searchView does not reload Firebase array

I have one activity with 2 recyclerViews, both recyclers are used with Firebase. One of the recyclers displays the results of a query, the other recycler has a listener that updates every time there is an update in Firebase. I added a searchView to filter the results from Firebase. The issue I'm having is when I'm trying to search the results from the Firebase query, when I start typing I see results but when I click the X to stop searching, the adapter does not reload the array and i don't see the list of items unless I reload the activity. I'm not sure what I'm missing here. Any help/suggestion is greatly appreciated. Here is my code:
Adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.eduardoz.ezmdapp.Model.Charges
import com.eduardoz.ezmdapp.R
class ChargesAdapter (private var charges: ArrayList<Charges>
, private var chargesAll: ArrayList<Charges>
, private val itemClick: (Charges) -> Unit)
: RecyclerView.Adapter<ChargesAdapter.ViewHolder>()
, Filterable {
inner class ViewHolder(itemView: View, val itemClick: (Charges) -> Unit) :
RecyclerView.ViewHolder(itemView) {
private val chargeCode = itemView.findViewById<TextView>(R.id.chargeCodeTxt)
private val chargeDescription = itemView.findViewById<TextView>(R.id.chargeDescriptionTxt)
fun bindCharges(charges: Charges) {
chargeCode?.text = charges.chargeCode
chargeDescription?.text = charges.chargeDescription
itemView.setOnClickListener { itemClick(charges) }
}
}
init {
this.charges = charges
chargesAll = java.util.ArrayList(charges)
}
override fun getItemCount(): Int {
return charges.count()
}
override fun onBindViewHolder(holder: ChargesAdapter.ViewHolder, position: Int) {
holder.bindCharges(charges[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChargesAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.charges_list, parent, false)
return ViewHolder(view, itemClick)
}
override fun getFilter(): Filter {
return searchFilter
}
private val searchFilter: Filter = object: Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList: ArrayList<Charges> = ArrayList()
if (constraint!!.isEmpty()) {
filteredList.addAll(chargesAll)
} else {
for(item in chargesAll) {
if
(item.chargeDescription.toLowerCase().contains(constraint.toString().toLowerCase())) {
filteredList.add(item)
}
}
}
val searchResults = FilterResults()
searchResults.values = filteredList
return searchResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
charges.clear()
charges.addAll(results!!.values as Collection<Charges>)
notifyDataSetChanged()
}
}
}
Activity
descriptionSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.isNotEmpty()) {
searchViewBar(newText)
} else {
if (newText.isEmpty()) { //I ADDED THIS TO RELOAD THE ADAPTER
charges.clear()
chargeList()
}
}
return false
}
})
private fun searchViewBar(newText: String) {
chargesListener = chargesCollectionRef
.whereGreaterThanOrEqualTo(CHARGE_DESCRIPTION, newText)
.whereLessThanOrEqualTo(CHARGE_DESCRIPTION, newText+"z")
.addSnapshotListener(this) { snapshot, exception ->
if (exception != null) {
println("error")
}
if (snapshot != null) {
charges.clear()
parseData(snapshot)
}
}
}
fun parseData(snapshot: QuerySnapshot) {
for (document in snapshot.documents) {
val data = document.data
val chargeCode = data!![CHARGE_CODE] as String
val chargeDescription = data[CHARGE_DESCRIPTION] as String
val chargeSpecialty = data[CHARGE_SPECIALTY] as String
val newChargeList = Charges(chargeCode, chargeDescription, chargeSpecialty)
charges.add(newChargeList)
}
chargesFromAdapter.notifyDataSetChanged()
}

Components details are not getting logged in my database when unpublishing the page using Tridion Deployer extension

I am trying to add the unpublished components entry in my custom storage extension. We know that we don't have any base class in Tridion for ComponentUndeploy as we have for deploy "ComponentDeploy", so I am trying to use ComponentPresentationUndeploy class to track the components which are getting and below is sample code how I am trying to track.
package com.tridion.custom.extensions;
import com.tridion.broker.StorageException;
import com.tridion.configuration.Configuration;
import com.tridion.configuration.ConfigurationException;
import com.tridion.deployer.DeploymentHandler;
import com.tridion.deployer.ProcessingException;
import com.tridion.deployer.Processor;
import com.tridion.deployer.modules.ComponentPresentationUndeploy;
import com.tridion.storage.ComponentMeta;
import com.tridion.storage.StorageManagerFactory;
import com.tridion.storage.StorageTypeMapping;
import com.tridion.storage.dao.ItemDAO;
import com.tridion.storage.dao.ItemTypeSelector;
import com.tridion.storage.dao.PublishAction;
import com.tridion.storage.dao.PublishActionDAO;
import com.tridion.storage.mapper.MapperFactory;
import com.tridion.transport.transportpackage.ComponentPresentationKey;
import com.tridion.transport.transportpackage.ProcessorInstructions;
import com.tridion.transport.transportpackage.TransportPackage;
import com.tridion.util.TCDURI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Iterator;
public class SearchComponentUndeployer extends ComponentPresentationUndeploy {
private static Logger log = LoggerFactory
.getLogger(SearchComponentUndeployer.class);
public SearchComponentUndeployer(Configuration paramConfiguration,
Processor paramProcessor) throws ConfigurationException {
super(paramConfiguration, paramProcessor);
}
#SuppressWarnings("rawtypes")
public void process(TransportPackage paramTransportPackage) throws ProcessingException
{
ProcessorInstructions localProcessorInstructions = paramTransportPackage.getProcessorInstructions();
try
{
Iterator localIterator = localProcessorInstructions.getArguments();
while (localIterator.hasNext())
{
Object localObject = localIterator.next();
if (localObject instanceof ComponentPresentationKey)
{
ComponentPresentationKey localComponentPresentationKey = (ComponentPresentationKey) localObject;
long[] arrayOfLong = new long[2];
arrayOfLong[0] = localComponentPresentationKey.getComponentKey().getId().getItemId();
arrayOfLong[1] = localComponentPresentationKey.getTemplateKey().getId().getItemId();
int PubID = localComponentPresentationKey.getComponentKey().getId().getPublicationId();
String tcmID = Integer.toString(localComponentPresentationKey.getComponentKey().getId().getItemId());
log.info("SearchComponentUndeployer -PubID" + PubID);
log.info("SearchComponentUndeployer -tcmID" + tcmID);
ItemDAO itemDAO = ((ItemDAO) StorageManagerFactory.getDAO(PubID, StorageTypeMapping.COMPONENT_META));
log.info("SearchComponentUndeployer -itemDAO"+ itemDAO.getStorageId());
ComponentMeta compObject = (ComponentMeta) MapperFactory.mapItemMetaInstance(itemDAO.findByPrimaryKey(PubID, localComponentPresentationKey.getComponentKey().getId().getItemId(),ItemTypeSelector.COMPONENT));
log.info("SearchComponentUndeployer -compObject"+ compObject.getTitle());
String formatTCMID = String.format("tcm:%d-%s-64", PubID,tcmID);
log.info("SearchComponentUndeployer - formatTCMID -"+ formatTCMID);
String strIgnorePubIds = "232,481";
String strPubId = Integer.toString(PubID);
Date lastPublishedDate = compObject.getLastPublishDate();
String schemaID = Integer.toString(compObject.getSchemaId());
if (!strIgnorePubIds.contains(strPubId))
{
PublishAction publishAction = new PublishAction();
publishAction.setAction("DEL");
publishAction.setTcmUri(formatTCMID);
publishAction.setItemType(16);
publishAction.setPublicationID(PubID);
publishAction.setLastPublishedDate(lastPublishedDate);
publishAction.setSchemaID(schemaID);
PublishActionDAO publishActionDAO = (PublishActionDAO) StorageManagerFactory.getDefaultDAO("PublishAction");
log.debug("SearchComponentUndeployer Going to Store bean -" + publishAction.toString());
publishAction = publishActionDAO.store(publishAction);
log.debug("SearchComponentUndeployer Stored bean -" + publishAction);
}
DeploymentHandler.undeploy(new TCDURI(PubID, 73014444080L, arrayOfLong));
}
}
}
catch (StorageException e)
{
log.error("Could not undeploy component presentation", e);
}
}
}
Any idea why I am not getting any entry for components in my database
Edit: Added sample code from PageUndeploy implementation done by me:
Object argument = iterator.next();
if (argument instanceof PageKey)
{
PageKey pageKey = (PageKey) argument;
TCDURI pageMetaURI = new TCDURI(pageKey.getId() .getPublicationId(), 1168231104576L, pageKey.getId().getItemId());
PageMeta pageMeta = this.pageMetaHome.findByPrimaryKey(pageMetaURI.getPublicationId(),(int) pageMetaURI.getItemId());
if (pageMeta == null)
{
DeploymentHandler.undeploy(pageMetaURI);
}
else
{
//Here I need to loop for componentpresentation and get component object
}
}
You can try this as I just taken class name from your input
List<ComponentPresentationMeta> lstCompObjects= pageMeta.getComponentPresentationMetas();
if(lstCompObjects != null && !lstCompObjects.isEmpty())
{
for(ComponentPresentationMeta compMeta : lstCompObjects)
{
String compID = Integer.toString(compMeta.getComponentId());
ItemDAO itemDAO = ((ItemDAO) StorageManagerFactory.getDAO(compMeta.getPublicationId(), StorageTypeMapping.COMPONENT_META));
ComponentMeta compObject = (ComponentMeta) MapperFactory.mapItemMetaInstance(itemDAO.findByPrimaryKey(compMeta.getPublicationId(), compMeta.getComponentId(),ItemTypeSelector.COMPONENT));
PublishAction compPublishAction = new PublishAction();
compPublishAction.setAction("DEL");
compPublishAction.setTcmUri(compID);
compPublishAction.setItemType(16);
compPublishAction.setPublicationID(compMeta.getPublicationId());
compPublishAction.setLastPublishedDate(compObject.getLastPublicationDate());
compPublishAction.setSchemaID(Integer.toString(compObject.getSchemaId()));
compPublishAction = publishActionDAO.store(compPublishAction);
}
}

Resources