Realtime database not stored data - kotlin

l cant save data Firebase realtime database no error code. auth create user but database not stored user data inside app. l change database rules
{
"rules": {
".read": true,
".write": true
}
}
l close firewall , try to test another app,I deleted the application completely from firebase and re-created it and downloaded the google-services.json file again. but can't solve problem.I tried a lot of different code structures, none of them worked this is my signup activity code block last version
class SignUpActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.sign_up_activity)
signInView.setOnClickListener {
startActivity(Intent(this, SignInActivity::class.java))
}
sign_up_btn.setOnClickListener {
createAccount()
}
}
private fun createAccount() {
val fullname = fullNameSignUp.text.toString()
val username = userNameSignUp.text.toString()
val email = emailSignUp.text.toString()
val password = passwordSignUp.text.toString()
when{
TextUtils.isEmpty(fullname) -> Toast.makeText(this,"full name is required.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(username) -> Toast.makeText(this,"user name is required.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(email) -> Toast.makeText(this,"email is required.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(password) -> Toast.makeText(this,"password is required.", Toast.LENGTH_LONG).show()
else -> {
/*
val alert = AlertDialog.Builder(this)
alert.setTitle("SignUp")
alert.setMessage("Please wait, this may take a while...")
alert.setCancelable(false)
alert.show()
*/
val progressDialog = ProgressDialog(this#SignUpActivity)
progressDialog.setTitle("SignUp")
progressDialog.setMessage("Please wait, this may take a while...")
progressDialog.setCanceledOnTouchOutside(false)
progressDialog.show()
val mAuth: FirebaseAuth = FirebaseAuth.getInstance()
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
saveUserInfo(fullname, username, email,progressDialog)
progressDialog.dismiss()
// AlertDialog.Builder(this)
// finish()
} else {
val message = task.exception!!.toString()
Toast.makeText(this, "Error: $message", Toast.LENGTH_LONG).show()
mAuth.signOut()
progressDialog.dismiss()
// AlertDialog.Builder(this)
// finish()
}
}
}
}
}
private fun saveUserInfo(fullname: String, username: String, email: String,progressDialog:ProgressDialog) {
val currentUserID = FirebaseAuth.getInstance().currentUser!!.uid
val usersRef = FirebaseDatabase.getInstance().reference.child("Users")
val userMap = HashMap<String,Any>()
userMap["uid"] = currentUserID
userMap["fullname"] = fullname
userMap["username"] = username
userMap["email"] = email
userMap["bio"] = ""
userMap["image"] = "gs://fart-me-ae78f.appSpot.com/Default Images/profile.png"
// db = FirebaseFirestore.getInstance()
// val usersRef = db.collection("Users").add(userMap)
// usersRef.addOnCompleteListener { task ->
usersRef.child("Users").child(currentUserID).setValue(userMap)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
Toast.makeText(this, "Account has been created successfully.", Toast.LENGTH_LONG).show()
progressDialog.dismiss()
val intent = Intent(this#SignUpActivity, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
// AlertDialog.Builder(this)
// finish()
} else {
val message = task.exception!!.toString()
Toast.makeText(this, "Error: $message", Toast.LENGTH_LONG).show()
FirebaseAuth.getInstance().signOut()
progressDialog.dismiss()
//AlertDialog.Builder(this)
// finish()
}
}
}
}
The solutions found by those with the same problem did not work for me. I would be glad if anyone can help me solve this problem

Related

realtime database child won't showing because permission denied

i want to create child name 'Posts' in addpostactivity by adding data to the firebase. my application running well, it also shows " uploaded successfully ". it just that in my database there's nothing added with the data i already input from my app. i upload image while create the data it's successfully stored in storage firebase, but in realtime database, there's still nothing showing the added data even the 'Posts' child it self
my logchat shows this line.
2023-02-08 12:07:36.353 16589-16674/com.isjieman.ocion W/RepoOperation: updateChildren at /Posts/-NNjQ5njDqkVSZYUIZ-V failed: DatabaseError: Permission denied
2023-02-08 12:07:41.351 16589-16653/com.isjieman.ocion V/FA: Inactivity, disconnecting from the service
here's my database security rules
{
"rules": {
"User" : {
"$uid" : {
".read" : "$uid === auth.uid",
".write" : "$uid === auth.uid",
}
}
}
}
and here's the database structure.
{
"User": {
"6FzpJ2sQC9gewbUIGHB8hiNWK1z2": {
"background_image": "https://firebasestorage.googleapis.com/v0/b/final-project-idn.appspot.com/o/Default%20Images%2Fimg_background.png?alt=media&token=b51e7cf5-2015-4cc4-9583-159373d081e2",
"bio": "Member of NCT",
"email": "mark#gmail.com",
"link": "",
"profile_image": "https://firebasestorage.googleapis.com/v0/b/final-project-idn.appspot.com/o/Profile%20Pictures%2F6FzpJ2sQC9gewbUIGHB8hiNWK1z2.jpg?alt=media&token=17d71d89-353d-44fa-8f06-e33716de0611",
"uid": "6FzpJ2sQC9gewbUIGHB8hiNWK1z2",
"userName": "marklee"
}
}
}
i think it's because of my database security. but i don't really know about how should i change the rules safely.
here's my AddPostActivity.kt
class AddPostActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var firebaseUser: FirebaseUser
private lateinit var addPostBinding: ActivityAddPostBinding
private var checker = ""
private var myUrl = ""
private var imageUri: Uri? = null
private var storagePostImageRef: StorageReference? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPostBinding = ActivityAddPostBinding.inflate(layoutInflater)
setContentView(addPostBinding.root)
supportActionBar?.hide()
//Dropdown item adapter
val itemCategory = listOf("Art", "Writing", "Application", "Design")
val adapterCategory = ArrayAdapter(this, R.layout.item_dropdown, itemCategory)
addPostBinding.acChooseCategory.setAdapter(adapterCategory)
val itemPriceRange = listOf("Rp 0 - 10.000", "Rp 10.000 - 50.000", "Rp 50.000 - 100.000")
val adapterPriceRange = ArrayAdapter(this, R.layout.item_dropdown, itemPriceRange)
addPostBinding.acPriceRange.setAdapter(adapterPriceRange)
firebaseUser = FirebaseAuth.getInstance().currentUser!!
storagePostImageRef = FirebaseStorage.getInstance().reference.child("Posts Pictures")
addPostBinding.btnAddImage.setOnClickListener(this)
addPostBinding.btnSavePost.setOnClickListener(this)
}
override fun onClick(v: View) {
when(v.id){
R.id.btnAddImage -> addImagePost()
R.id.btnSavePost -> savePost()
}
}
private fun savePost() {
if (checker == "clicked")
{
uploadPostWithImage()
}
else
{
uploadPost()
}
}
private fun uploadPost() {
when{
TextUtils.isEmpty(addPostBinding.etTitlePost.text.toString()) -> Toast.makeText(this, "Please add Title Post.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.etDescPost.text.toString()) -> Toast.makeText(this, "Please add Description.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.acChooseCategory.text.toString()) -> Toast.makeText(this, "Please Choose Category.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.acPriceRange.text.toString()) -> Toast.makeText(this, "Please Choose Price Range.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.etDurationPost.text.toString()) -> Toast.makeText(this, "Please add Duration Time.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.etPaymentMethods.text.toString()) -> Toast.makeText(this, "Please add Payment Methods.", Toast.LENGTH_LONG).show()
else -> {
val ref = FirebaseDatabase.getInstance().reference.child("Posts")
val postId = ref.push().key
val postMap = HashMap<String, Any>()
postMap["postId"] = postId!!
postMap["title"] = addPostBinding.etTitlePost.text.toString()
postMap["description"] = addPostBinding.etDescPost.text.toString()
postMap["category"] = addPostBinding.acChooseCategory.text.toString()
postMap["priceRange"] = addPostBinding.acPriceRange.text.toString()
postMap["duration"] = addPostBinding.etDurationPost.text.toString()
postMap["paymentMethods"] = addPostBinding.etPaymentMethods.text.toString()
postMap["publisher"] = FirebaseAuth.getInstance().currentUser!!.uid
ref.child(postId).updateChildren(postMap)
Toast.makeText(this, "Post Uploaded successfully.", Toast.LENGTH_LONG).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
}
}
private fun uploadPostWithImage() {
when{
imageUri == null -> Toast.makeText(this, "Please select image first.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.etTitlePost.text.toString()) -> Toast.makeText(this, "Please add Title Post.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.etDescPost.text.toString()) -> Toast.makeText(this, "Please add Description.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.acChooseCategory.text.toString()) -> Toast.makeText(this, "Please Choose Category.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.acPriceRange.text.toString()) -> Toast.makeText(this, "Please Choose Price Range.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.etDurationPost.text.toString()) -> Toast.makeText(this, "Please add Duration Time.", Toast.LENGTH_LONG).show()
TextUtils.isEmpty(addPostBinding.etPaymentMethods.text.toString()) -> Toast.makeText(this, "Please add Payment Methods.", Toast.LENGTH_LONG).show()
else -> {
val progressDialog = ProgressDialog(this)
progressDialog.setTitle("Adding New Post")
progressDialog.setMessage("Please wait, we are Uploading your Post...")
progressDialog.show()
val fileRef = storagePostImageRef!!.child(System.currentTimeMillis().toString() + ".jpg")
val uploadTask: StorageTask<*>
uploadTask = fileRef.putFile(imageUri!!)
uploadTask.continueWithTask(Continuation <UploadTask.TaskSnapshot, Task<Uri>>{ task ->
if (!task.isSuccessful)
{
task.exception?.let {
throw it
progressDialog.dismiss()
}
}
return#Continuation fileRef.downloadUrl
}).addOnCompleteListener (OnCompleteListener<Uri> { task ->
if (task.isSuccessful)
{
val downloadUrl = task.result
myUrl = downloadUrl.toString()
val ref = FirebaseDatabase.getInstance().reference.child("Posts")
val postId = ref.push().key
val postMap = HashMap<String, Any>()
postMap["postId"] = postId!!
postMap["title"] = addPostBinding.etTitlePost.text.toString()
postMap["description"] = addPostBinding.etDescPost.text.toString()
postMap["category"] = addPostBinding.acChooseCategory.text.toString()
postMap["priceRange"] = addPostBinding.acPriceRange.text.toString()
postMap["duration"] = addPostBinding.etDurationPost.text.toString()
postMap["paymentMethods"] = addPostBinding.etPaymentMethods.text.toString()
postMap["post_image"] = myUrl
postMap["publisher"] = FirebaseAuth.getInstance().currentUser!!.uid
ref.child(postId).updateChildren(postMap)
Toast.makeText(this, "Post Uploaded successfully.", Toast.LENGTH_LONG).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
progressDialog.dismiss()
}
else
{
progressDialog.dismiss()
}
})
}
}
}
private fun addImagePost() {
checker = "clicked"
CropImage.activity()
.setAspectRatio(2, 1)
.start(this)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null)
{
val result = CropImage.getActivityResult(data)
imageUri = result.uri
addPostBinding.btnAddImage.setImageURI(imageUri)
}
}
}
Add rules for posts too.
{
"rules": {
"User" : {
"$uid" : {
".read" : "$uid === auth.uid",
".write" : "$uid === auth.uid",
}
}
"Posts" : {
"$uid" : {
".read" : "$uid === auth.uid",
".write" : "$uid === auth.uid",
}
}
}
}

Error While Upload Image From Galley Using Drjacky Image Picker And Retrofit 2

hi guys I got an error like the one below when trying to upload an image from the galley:
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{efed650 15275:app.fadlyproject.com/u0a158} (pid=15275, uid=10158) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
the error comes from this line of code:
val parcelFileDescriptor =
contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return
I'm using 3rd party libraries namely DrJacky and Retrofit 2. I've added some necessary things to the manifest as below:
Dependencies :
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.github.Drjacky:ImagePicker:2.3.19'
Manifest :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
image_view = findViewById(R.id.image_view)
button_upload = findViewById(R.id.button_upload)
image_view!!.setOnClickListener {
openImageChooser()
}
button_upload!!.setOnClickListener {
uploadImage()
}
}
private val profileLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
val uri = it.data?.data!!
selectedImageUri = uri
image_view!!.setImageURI(selectedImageUri)
} else parseError(it)
}
private fun openImageChooser() {
ImagePicker.with(this)
.provider(ImageProvider.BOTH)
.setDismissListener {
Log.d("ImagePicker", "onDismiss");
}
.createIntentFromDialog { profileLauncher.launch(it) }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
REQUEST_CODE_PICK_IMAGE -> {
selectedImageUri = data?.data
image_view!!.setImageURI(selectedImageUri)
}
}
}
}
private fun uploadImage() {
if (selectedImageUri == null) {
layout_root!!.snackbar("Select an Image First")
return
}
val parcelFileDescriptor =
contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return
val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
val file = File(cacheDir, contentResolver.getFileName(selectedImageUri!!))
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
progress_bar!!.progress = 0
val body = UploadRequestBody(file, "image", this)
MyAPI().uploadImage(
MultipartBody.Part.createFormData(
"file",
file.name,
body
),
RequestBody.create(MediaType.parse("multipart/form-data"), "json")
).enqueue(object : Callback<UploadResponse> {
override fun onFailure(call: Call<UploadResponse>, t: Throwable) {
layout_root!!.snackbar(t.message!!)
progress_bar!!.progress = 0
}
override fun onResponse(
call: Call<UploadResponse>,
response: Response<UploadResponse>
) {
response.body()?.let {
layout_root!!.snackbar(it.message)
progress_bar!!.progress = 100
classes!!.text = it.data.classes
layout!!.visibility = View.VISIBLE
Glide.with(this#MainActivity).load("http://167.172.72.26:1337/"+ it.data.image_after_preprocessing).into(
image_view!!
)
}
}
})
}
override fun onProgressUpdate(percentage: Int) {
progress_bar!!.progress = percentage
}
companion object {
const val REQUEST_CODE_PICK_IMAGE = 101
}
This answer is late but it might help others.
I just added .crop() to it like this.
ImagePicker.with(this)
.crop()
.provider(ImageProvider.BOTH)
.setDismissListener {
Log.d("ImagePicker", "onDismiss");
}
.createIntentFromDialog { profileLauncher.launch(it) }
I noticed that the error only persist when using the gallery and adding the .crop() is the only solution to it.
In case you don't use Crop option, you just need to add:
mGalleryUri?.let { galleryUri ->
contentResolver.takePersistableUriPermission(
galleryUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
}
https://developer.android.com/training/data-storage/shared/photopicker#persist-media-file-access
I'll change ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT on the next update.
[And if I could find a way to have both worlds(having crop and let developer use or not use takePersistableUriPermission, I'll update again.]

RecyclerView and OnItemClick: No value passed for parameter 'click' in Fragment

I'm trying to implement an OnClick listener for specific items in a recyclerview. I've done it before with activities, but now I want to do this in a fragment and I've run into a problem. I'm getting the error No value passed for parameter 'click'. This is the line of code that gives that error:
recyclerAdapterAbstract = abstractList.let {AbstractAdapter(requireActivity(),it)}
This the only error Android Studio is currently showing me. The logcat doesn't show any error. Only the Build Output shows what's wrong and it's exactly what I said earlier
Fragment Class
#Suppress("UNREACHABLE_CODE")
class AbstractWallpapers: Fragment(), PurchasesUpdatedListener, AbstractAdapter.OnItemClickListenerAbstract {
private lateinit var subscribeAbstract: Button
private var billingClient: BillingClient? = null
lateinit var recyclerView: RecyclerView
lateinit var abstractList: ArrayList<Abstract>
private var recyclerAdapterAbstract: AbstractAdapter? = null
private var myRef3: DatabaseReference? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_abstract_wallpaper, container, false)
recyclerView = requireActivity().findViewById(R.id.abstract_recyclerView)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.abstract_recyclerView)
val layoutManager = GridLayoutManager(requireContext(), 2)
recyclerView.layoutManager = layoutManager
recyclerView.setHasFixedSize(true)
myRef3 = FirebaseDatabase.getInstance().reference
abstractList = ArrayList()
ClearAll()
GetDataFromFirebase()
subscribeAbstract = view.findViewById(R.id.abstract_subscribe_btn)
subscribeAbstract.setOnClickListener {
subscribeAbstract()
}
//Establish connection to billing client
//check subscription status from google play store cache
//to check if item is already Subscribed or subscription is not renewed and cancelled
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val queryPurchase = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val queryPurchases = queryPurchase.purchasesList
if (queryPurchases != null && queryPurchases.size > 0) {
handlePurchases(queryPurchases)
} else {
saveSubscribeValueToPref(false)
}
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected", Toast.LENGTH_SHORT).show()
}
})
//item subscribed
if (subscribeValueFromPref) {
subscribeAbstract.visibility = View.GONE
} else {
subscribeAbstract.visibility = View.VISIBLE
}
}
// Code relating to my Firebase storage
#SuppressLint("NotifyDataSetChanged")
private fun GetDataFromFirebase() {
val query: Query = myRef3!!.child("Abstract")
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (dataSnapshot: DataSnapshot in snapshot.children) {
val abstract = Abstract()
abstract.abstract = dataSnapshot.child("abstract").value.toString()
abstractList.add(abstract)}
recyclerAdapterAbstract = abstractList.let {AbstractAdapter(requireActivity(),it)}
recyclerView.adapter = recyclerAdapterAbstract
recyclerAdapterAbstract!!.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {}
})
if (recyclerAdapterAbstract != null) recyclerAdapterAbstract!!.notifyDataSetChanged()
}
private fun ClearAll() {
abstractList.clear()
abstractList = ArrayList()
}
private val preferenceObject: SharedPreferences
get() = requireActivity().getSharedPreferences(PREF_FILE, 0)
private val preferenceEditObject: SharedPreferences.Editor
get() {
val pref = requireActivity().getSharedPreferences(PREF_FILE, 0)
return pref.edit()
}
private val subscribeValueFromPref: Boolean
get() = preferenceObject.getBoolean(SUBSCRIBE_KEY, false)
private fun saveSubscribeValueToPref(value: Boolean) {
preferenceEditObject.putBoolean(SUBSCRIBE_KEY, value).commit()
}
//initiate purchase on button click
fun subscribeAbstract() {
//check if service is already connected
if (billingClient!!.isReady) {
initiatePurchase()
} else {
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
initiatePurchase()
} else {
Toast.makeText(requireActivity(), "Error " + billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected ", Toast.LENGTH_SHORT).show()
}
})
}
}
private fun initiatePurchase() {
val skuList: MutableList<String> = ArrayList()
skuList.add(ITEM_SKU_SUBSCRIBE)
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS)
val billingResult = billingClient!!.isFeatureSupported(BillingClient.FeatureType.SUBSCRIPTIONS)
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
billingClient!!.querySkuDetailsAsync(params.build()
) { billingResult, skuDetailsList ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
if (skuDetailsList != null && skuDetailsList.size > 0) {
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList[0])
.build()
billingClient!!.launchBillingFlow(requireActivity(), flowParams)
} else {
//try to add subscription item "sub_example" in google play console
Toast.makeText(requireActivity(), "Item not Found", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(requireActivity(),
" Error " + billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(requireActivity(),
"Sorry Subscription not Supported. Please Update Play Store", Toast.LENGTH_SHORT).show()
}
}
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
//if item subscribed
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
handlePurchases(purchases)
}
else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
val queryAlreadyPurchasesResult = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
alreadyPurchases?.let { handlePurchases(it) }
}
else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
Toast.makeText(requireActivity(), "Purchase Canceled", Toast.LENGTH_SHORT).show()
}
else {
Toast.makeText(requireActivity(), "Error " + billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
fun handlePurchases(purchases: List<Purchase>) {
for (purchase in purchases) {
//if item is purchased
if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
// Invalid purchase
// show error to user
Toast.makeText(requireActivity(), "Error : invalid Purchase", Toast.LENGTH_SHORT).show()
return
}
// else purchase is valid
//if item is purchased and not acknowledged
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient!!.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
} else {
// Grant entitlement to the user on item purchase
// restart activity
if (!subscribeValueFromPref) {
saveSubscribeValueToPref(true)
Toast.makeText(requireActivity(), "Item Purchased", Toast.LENGTH_SHORT).show()
recreate(requireActivity())
}
}
} else if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
Toast.makeText(requireActivity(),
"Purchase is Pending. Please complete Transaction", Toast.LENGTH_SHORT).show()
} else if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
saveSubscribeValueToPref(false)
subscribeAbstract.visibility = View.VISIBLE
Toast.makeText(requireActivity(), "Purchase Status Unknown", Toast.LENGTH_SHORT).show()
}
}
}
var ackPurchase = AcknowledgePurchaseResponseListener { billingResult ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
//if purchase is acknowledged
// Grant entitlement to the user. and restart activity
saveSubscribeValueToPref(true)
recreate(requireActivity())
}
}
/**
* Verifies that the purchase was signed correctly for this developer's public key.
*
* Note: It's strongly recommended to perform such check on your backend since hackers can
* replace this method with "constant true" if they decompile/rebuild your app.
*
*/
private fun verifyValidSignature(signedData: String, signature: String): Boolean {
return try {
// To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
val base64Key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhBlajrk5nNjpRTPJjDtGxgtgAeKijz3Wc0KrRKKSCxxsViHl7DhsI+sUZfk4Y1jxSg4/3W1uRo/0UASM77XfJIq34bK9KYgoSAGYSuH8Z+4fK/MrPz7dHhsljkAi4GZkv8x9VhZdDdpn2GSHVFaxs8c+HBOFp9aWAErHrQhi9/7fYf39pQSTC3WkVcy9xNDZxiiKTfDN3dyEvS0XQ617ZJwqDuRdkU5Aw9+R8r+oXyURV/ekgCQkWfCUaTp/jWdySOIcR87Bde24lQAXbvJaL5uAYI4zPwO4sIP1AbXLuDtv3N2rFVmP/1cML/NHDcfI5FOoStz88jzJU26Ngpqu1QIDAQAB"
Security.verifyPurchase(base64Key, signedData, signature)
} catch (e: IOException) {
false
}
}
override fun onDestroy() {
super.onDestroy()
if (billingClient != null) {
billingClient!!.endConnection()
}
}
companion object {
const val PREF_FILE = "MyPref"
const val SUBSCRIBE_KEY = "subscribe"
const val ITEM_SKU_SUBSCRIBE = "abstract_wallpapers"
}
override fun onItemClick(item: String) {
}
}
Adapter class
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>, private val click: OnItemClickListenerAbstract ) :
RecyclerView.Adapter<AbstractAdapter.ViewHolder>() {
interface OnItemClickListenerAbstract{
fun onItemClick(item:String)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.abstract_image_view, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Glide.with(mContext)
.load(abstractList[position].abstract)
.into(holder.imageView)
holder.imageView.setOnClickListener {
val intent = Intent(mContext, AbstractPreview::class.java)
intent.putExtra("abstract", abstractList[position].abstract.toString())
Toast.makeText(mContext, "Fullscreen view", Toast.LENGTH_SHORT).show()
mContext.startActivity(intent)
}
holder.downloadBtn.setOnClickListener {
abstractList.get(position).abstract?.let { it1 -> click.onItemClick(it1) }
}
}
override fun getItemCount(): Int {
return abstractList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.abstractImageView)
val downloadBtn: Button = itemView.findViewById(R.id.abstractDownloadBtn)
}
companion object
}
You have 3 parameters for the class AbstractAdapter
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>, private val click: OnItemClickListenerAbstract )
but you are instantiating the object with only two parameters
AbstractAdapter(requireActivity(),it)
It's expecting the third parameter for the clickListener
AbstractAdapter(requireActivity(),it,this)
(send the Fragment as the third param)

kotlin quiz i can't color answer because don't run ContextCompat

Could you help me with the following code, I can't get it to paint the correct option green, or show the animation, of the CorrectResponse function.
If I delete the defaultColors() function, the green color is shown, but it remains in the next question.
when I write the default function it doesn't execute the code:
tv_option_one.background = ContextCompat.getDrawable(this, R.drawable.correct_option_border_bg)
I have tried to insert a sleep to defaultColors() to see the color correct_option_border_bg(green) but it is not displayed.
Any advice?
class QuestionActivity : AppCompatActivity() {
var quizzes: MutableList<Quiz>? = null
var contadorPregunta = 0
var questions: MutableMap<String, Question>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_question)
// VISUALIZACION PREGUNTAS
private fun bindViews() {
if (contadorPregunta == questions!!.size) { // last question
Toast.makeText(this, "HAS COMPLETADO TODAS LAS PREGUNTAS", Toast.LENGTH_SHORT).show()
val intent = Intent(this, ResultActivity::class.java)
startActivity(intent)
}
else{
defaultColors()
}
val pregunta = indicePreguntas[contadorPregunta]
val question = questions!!["question$pregunta"]
question?.let {
tvDescription.text = it.description
tv_option_one.text = it.option1
tv_option_two.text = it.option2
tv_option_three.text = it.option3
tv_option_four.text = it.option4
val respuesta = it.answer
tv_option_one.setOnClickListener {
if (tv_option_one.text == respuesta) {
Toast.makeText(this, "RESPUESTA CORRECTA", Toast.LENGTH_SHORT).show()
tv_option_one.background = ContextCompat.getDrawable(this, R.drawable.correct_option_border_bg)
respuestaCorrecta()
} else {
tv_option_one.background = ContextCompat.getDrawable(this, R.drawable.wrong_option_border_bg)
respuestaFallada()
}
}
tv_option_two.setOnClickListener {
if (tv_option_two.text == respuesta) {
Toast.makeText(this, "RESPUESTA CORRECTA", Toast.LENGTH_SHORT).show()
tv_option_two.background = ContextCompat.getDrawable(this, R.drawable.correct_option_border_bg)
respuestaCorrecta()
} else {
tv_option_two.background = ContextCompat.getDrawable(this, R.drawable.wrong_option_border_bg)
respuestaFallada()
}
}
tv_option_three.setOnClickListener {
if (tv_option_three.text == respuesta) {
Toast.makeText(this, "RESPUESTA CORRECTA", Toast.LENGTH_SHORT).show()
tv_option_three.background = ContextCompat.getDrawable(this, R.drawable.correct_option_border_bg)
contadorPregunta++
indicePreguntas[contadorPregunta]
} else {
tv_option_three.background = ContextCompat.getDrawable(this, R.drawable.wrong_option_border_bg)
respuestaFallada()
}
}
tv_option_four.setOnClickListener {
if (tv_option_four.text == respuesta) {
Toast.makeText(this, "RESPUESTA CORRECTA", Toast.LENGTH_SHORT).show()
tv_option_four.background = ContextCompat.getDrawable(this, R.drawable.correct_option_border_bg)
} else {
tv_option_four.background = ContextCompat.getDrawable(this, R.drawable.wrong_option_border_bg)
respuestaFallada()
}
}
}
}
private fun defaultColors() {
tv_option_one.background = ContextCompat.getDrawable(this, R.drawable.default_option_border_bg)
tv_option_two.background = ContextCompat.getDrawable(this, R.drawable.default_option_border_bg)
tv_option_three.background = ContextCompat.getDrawable(this, R.drawable.default_option_border_bg)
tv_option_four.background = ContextCompat.getDrawable(this, R.drawable.default_option_border_bg)
ivAcierto.visibility = View.INVISIBLE
}
private fun respuestaCorrecta() {
// Ver animacion
ivAcierto.visibility = View.VISIBLE
ivAcierto.animate().apply {
duration=1000
rotationYBy(1400f)
}.start()
contadorPregunta++
indicePreguntas[contadorPregunta]
Thread.sleep(2_000)
bindViews()
}
private fun respuestaFallada() {
//Thread.sleep(1_000)
// FALLO EN EL TEST
val dialog = AlertDialog.Builder(this)
.setTitle(R.string.dialog_one_style_title)
.setMessage(R.string.dialog_one_style_message)
.setPositiveButton(R.string.dialog_one_style_positive_btn) { view, _ ->
view.dismiss()
val intent = Intent(this, ResultActivity::class.java)
val json = Gson().toJson(quizzes!![0])
intent.putExtra("QUIZ", json)
startActivity(intent)
}
.setCancelable(false)
.create()
dialog.show()
}
}
I would like to give a couple of notes here: please use English when you write code, cause I have no idea what "pregunta" is and don't do this !! ... find other way to deal with nullables.
In respuestaCorrecta you call bindViews, which calls defaultColors and your correct color is getting overrided. As I can see, you want to delay calling bindViews by adding 2 sec sleep...
This is a bad idea. See your code runs in a main thread, in the same thread where rendering of Android Views happens... So making it sleep for 2 sec will make sure that no view will render for this period of time, and a user will not see anything in the app - no animation, no color changes, etc.
Thread.sleep cannot be used within main thread. However, if you want something to change after 2 sec, you can post an update. Like this:
tv_option_one.postDelayed({
bindViews()
}, 2000)
lambda is what will be called after a delay
2000 is a delay in millis

How should write the findViewById pass data to Fragment page from Activity page using kotlin

This is my activity page:
override fun receiveDetections(detections: Detector.Detections) {
val barcodes = detections.detectedItems
if (barcodes.size() == 1) {
scannedValue = barcodes.valueAt(0).rawValue
runOnUiThread {
cameraSource.stop()
toastText = scannedValue
Toast.makeText(this#InsertStockInActivity, toastText, Toast.LENGTH_SHORT).show()
val i = Intent(this#InsertStockInActivity, InputStockInActivity::class.java)
i.putExtra("key", toastText)
startActivity(i)
finish()
}
}else
{
Toast.makeText(this#InsertStockInActivity, "value- else", Toast.LENGTH_SHORT).show()
}
}
This is my Fragment Page, I using requireActivity().getIntent(), how can I show the "key" data?
val value = requireActivity().intent.getStringExtra("key") ?: ""
binding.edtId.findViewById<EditText>(R.id.value)
The binding.edtId.find.......... it got error, how should I write for this line ?