I have a checbox. If the user tries to uncheck it, a popup should appear to get approval. How can I show a popup and wait for its response?
This code is in viewmodel:
fun stateChanged(check: Boolean){
if(check)
{
//make it checked
}
else{
//popup should appear to get approval then uncheck the checkbox.
}
}
I think I should create the popup in the fragment. But how can I observe the result from viewmodel?
Related
I am showing a custom dialog when there is no internet connectivity. I want to do some handling when the user presses the back button while the dialog is visible.
BackHandler inside the parent screen nor within the dialog itself is working in this scenario.
Thank you
Use the onDismiss callback and disable automatic dismissal when the user taps outside the dialog. This way you can ensure that the dismiss request originated from a back press. This is a workaround, of sorts, since an out-of-the-box API is not yet bundled with Compose.
Just define the BackHandler function inside the Dialog:
val shouldShowDialog = remember { mutableStateOf(true) }
if (shouldShowDialog.value) {
Dialog(onDismissRequest = { shouldShowDialog.value = false }) {
Button(onClick = {shouldShowDialog.value = false}){
Text("Close")
}
BackHandler {
// your action
}
}
}
I am uploading data to a webserver. On my fragment I have a button to start the upload. There are two phases what I am trying to have the user notification done via a none-cancellable AlertDialog solution.
When I am pressing the upload button, preparation for the upload is starting I am setting up the AlertDialog and presenting it. Once the physical upload is starting, I am using the same AlertDialog, but changing the message in it to show the progress of the upload.
***** Now the issue is the following ******
When I setup the AlertDialog and call the Show method, it does not display the AlertDialog. But once the upload is started and the progress is updated I just call the setMessage method and at this point the AlertDialog appears.
The relevant codes are the followings:
The submitbutton.setOnClickLictener is in the onViewCreated()
submitbutton.setOnClickListener {
requireActivity().runOnUiThread {
SubmitAd()
}
}
I have tried here the run the SubmitAd() on the UIThread, if it helps, but it is the same without it.
SubmitAd is showing the Dialog. (Actually at this point nothing is shown.
fun SubmitAd() {
var addInApp: Boolean = false
ToBePurchased = 0
if (CheckCanUpload()) {
var AlertView = AlertDialog.Builder(requireActivity())
AlertView.setTitle("Hirdetés feltöltés")
AlertView.setMessage("A feltöltés előkészítése hosszabb ideig is eltarhat, kérjük várjon!")
AlertView.setCancelable(false)
DialogToShow = AlertView.create()
DialogToShow!!.show()
purchaseLoop = 0
UploadWithPurchase()
} else {
var AlertView = AlertDialog.Builder(requireActivity())
AlertView.setTitle("Hirdetés hiba")
AlertView.setMessage("A hirdetése hiányos. Kérjük töltse ki az összes mezőt és csatoljon fotót a hirdetéséhez!")
AlertView.setPositiveButton("Ok") { dialog, which ->
dialog.dismiss()
}
DialogToShow = AlertView.create()
DialogToShow!!.show()
}
}
In UploadWithPurchase() the Playstore purchase handling is done, but if there is no purchase at all, it is just going through a loop, which calls UploadWithPurchase() recursively until all possible purchases are checked, then it goes to the real Upload() which calls an Http request to upload the data and reports back via an interface the progress of the upload process.
The Webhelper returns the progress like this:
override fun WebHelperProgress(id: String, progress: Float) {
if (DialogToShow != null) {
DialogToShow!!.setMessage("Feltöltés folyamatban. Kérem várjon! ... ${progress.toInt()}%")
}
}
When this method is called, the AlertDialog appears.
Whatever I have tried, does not help. AlertDialog does not show up at the first call, but no clue why.
EDIT later: I have figured out that the AlertDialog is actually appears once it comes out from the recursive loop, but I do not know how to force it to be displayed before it starts the loop. That would be my aim to notify the user that a longer process is starting. It meaningless to start the process and the user does not know what is happening.
Finally I could solve it by putting the purchaseLoop to a separate Thread like this.
fun SubmitAd() {
var addInApp: Boolean = false
ToBePurchased = 0
if (CheckCanUpload()) {
var AlertView = AlertDialog.Builder(requireActivity())
AlertView.setTitle("Hirdetés feltöltés")
AlertView.setMessage("A feltöltés előkészítése hosszabb ideig is eltarhat, kérjük várjon!")
AlertView.setCancelable(false)
DialogToShow = AlertView.create()
DialogToShow!!.show()
purchaseLoop = 0
******** SOLUTION HERE ********
Thread {
UploadWithPurchase()
}.start()
*******************************
} else {
var AlertView = AlertDialog.Builder(requireActivity())
AlertView.setTitle("Hirdetés hiba")
AlertView.setMessage("A hirdetése hiányos. Kérjük töltse ki az összes mezőt és csatoljon fotót a hirdetéséhez!")
AlertView.setPositiveButton("Ok") { dialog, which ->
dialog.dismiss()
}
DialogToShow = AlertView.create()
DialogToShow!!.show()
}
}
Is there a way to capture the back button click listener from Google Places Address Search (AutocompleteSupportFragment)
val btnBackClick =
autocompleteFragment?.view?.findViewById(R.id.places_autocomplete_back_button) as androidx.appcompat.widget.AppCompatImageButton
btnBackClick.setOnClickListener {
Log.e("AutoComplete", "Address Search Back")
}
Tried this leading to crash "java.lang.IllegalStateException: Places must be initialized."
I've tried to get the back button the same way you did on my end, but you are right, that View returns null even though it apparently exists: R.id.places_autocomplete_back_button.
Update: At the moment it is not currently possible to get this View, so I recommend you file a feature request for this in Google's Issue Tracker in case Google Engineers are able to consider adding this capability.
Hope this helps!
I had the same problem. I couldn't get a reference through neither the back button of the AutocompleteSupportFragment / onBackPressed listener / onBackPressedDispatcher from the activity, so I went on and used the error status instead.
// Assuming "autocompleteFragment" is the view name in your XML file
val fragment = supportFragmentManager.findFragmentById(R.id.autocompleteFragment) as AutocompleteSupportFragment
// ...
fragment.setOnPlaceSelectedListener(object : PlaceSelectionListener {
override fun onPlaceSelected(place: Place) {
// Handle the result like usual
}
override fun onError(status: Status) {
// Check if the user tapped the back button
if (status == Status.RESULT_CANCELED) {
// Do what you want to do when back button is pressed
}
}
}
Technically a workaround, but it does capture the back button flow.
I am using BiometricPrompt in my application. It works well and shows the dialog when call the authenticate() method. But this dialog gets closing when I click outside the dialog. How to prevent it? How to make BiometricPrompt's dialog non-cancelable? Here is no method like biometricPrompt.setCancelable(false).
BiometricPrompt does not allow that. So you won't be able to make the system-provided biometric prompt non-cancelable. But you can detect whenever user cancels the dialog.
So an option would be, to show again the biometric prompt after user cancel it (which I think would be a bad user experience) or use alternate user authentication:
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
if (errorCode == BiometricConstants.ERROR_USER_CANCELED) {
// User canceled the operation
// you can either show the dialog again here
// or use alternate authentication (e.g. a password) - recommended way
}
}
check it out
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
supportFragmentManager.fragments.forEach {
if(it is DialogFragment) {
it.dialog?.setCanceledOnTouchOutside(false)
}
}
}
There are some devices that still have this issue. An work around will be to get root view and add an overlay view with clickable method set to false.
ViewGroup viewGroup = ((ViewGroup) yourActivity.findViewById(android.R.id.content)).getChildAt(0);
//create your view
Display display = mActivity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
View view = new View(yourActivity);
view.setId(R.id.overlay_view);
view.setLayoutParams(new ViewGroup.LayoutParams(size.x, size.y));
view.setBackgroundColor(ContextCompat.getColor(yourActivity, R.color.black));
view.setOnClickListener(v -> {
//do nothing prevent click under this overlay
});
//add your view on top of the screen
viewGroup.addView(view);
//call your biometric dialog
....
//on callbacks even if it is error or success call remove view
viewGroup.removeView(view);
You have to use the version 1.0.0-beta01 or later.
Now it is the default behavior:
Touches outside no longer cancel authentication. Back button cancel authentication still.
You can see the changelog:
Changed behavior to not allow BiometricPrompt to be cancelled by a touch event outside the prompt.
You can check also the rewiew report.
No new API.
I'm trying to create a listener for the clear button that comes from google's Place Autocomplete API. i called my clearButton() method in my fragment's onViewCreated method
clearButton()
placeAutocompleteFragment?.view?.findViewById<View>(R.id.place_autocomplete_clear_button)
?.setOnClickListener {
View.OnClickListener {
Log.d(TAG, "Cleared")
it?.findViewById<EditText>(R.id.place_autocomplete_search_input)?.setText("")
it?.visibility = View.GONE
}
}
now when i click on the clear button icon, the text doesn't get erased, nothing happens. I can still type in a new location though, but i can't clear it. my Log.d isn't getting displayed either.
I don't have android studio on this machine now to try, but I guess you can do something like
place_autocomplete_clear_button.onClick { place_autocomplete_search_input.text = "" }
where place_autocomplete_clear_button can be static import and onClick might be from anko
Figured it out. I had the method calls set up all wrong.
Here's how it should look like:
private fun clearButton() {
placeAutocompleteFragment?.view?.findViewById<View>(R.id.place_autocomplete_clear_button)?.setOnClickListener {
Log.d(TAG, "Cleared Button Clicked")
it.visibility = View.GONE
//do something
}
}