Confirmation, ConfirmationDelegate

Hi,

This ConfirmationDelegate and Confirmation class from Ui... I essentially want to use it's "yes/no" functionality to query the user if they want to quit...

If I was using a more simple language it would be as easy as
if (ConfirmationDialog("Do you want to quit?") == true)
{
if (ConfirmationDialog("Do you want to save?") == true)
{
//save
}
return false; // let connectIQ handle the key (and exit)
}
else
{
return true; // handle the key and do not exit
}


But in monkeyC it seems much harder... I'm making ConfirmationDelegate's and initializing a Confirmation class with my message "Do you want to quit?"...

And deep in the "onReponse" function inside my ConfirmationDelegate class, I have it modify a global variable "globalUserWantsToQuit"... and I test the value of that global variable in my main function to see if the user wants to quit or not... and it's not working after all that...



Tell me; is there ANY easier (i.e. less roundabout) way to ask the user for simple input and carry on? I feel like I'm building an entire garage for where a simple door would do. Thanks in advance.

==================================================================
Oh yeah, below is the code that it seems connectIQ would have me write (I'm having it ask two questions, one for if the user wants to quit, and second if the user wants to save):
var globalUserWantsToQuit;
var globalUserWantsToSave;

class ConfirmExitDelegate extends Ui.ConfirmDelegate
{
function onResponse(value) {
if (value == 0) { globalUserWantsToQuit = false; }
else { globalUserWantsToQuit = true; }
}
}
class ConfirmSaveDelegate extends Ui.ConfirmDelegate
{
function onResponse(value) {
if (value == 0) { globalUserWantsToSave = false; }
else { globalUserWantsToSave = true; }
}
}

//... main InputDelegate class onKey function below:
var thisConfirmExit;
var thisConfirmSave;
//...
if( KEY_ESC == evt.getKey() )
{
Sys.println("ESC Button Pressed");

globalUserWantsToQuit = false; // default
thisConfirmExit = new Ui.Confirmation("do you want to exit?");
Ui.pushView( thisConfirmExit, new ConfirmExitDelegate(), Ui.SLIDE_RIGHT );
if (globalUserWantsToQuit == true)
{

globalUserWantsToSave = true; // default
thisConfirmSave = new Ui.Confirmation("do you want to save?");
Ui.pushView( thisConfirmSave, new ConfirmSaveDelegate(), Ui.SLIDE_RIGHT );
if (globalUserWantsToSave == true)
{
Sys.println("Saving Record");
}

Sys.println("Exiting");
return false; // let Garmin handle ESC input (and exit)
}

Sys.println("Not exiting");
return true; // handled ESC input
}


One easier way might be to not use global variables, and create those subvariables inside the classes. I'm just not too familiar with the "best" way to do this, in MonkeyC. I just wanted to make it work first of all, and haven't had luck yet.

Also, I believe that traditionally whenever you use "new" keyword, as in when I made those Ui.Confirmation classes, it allocates memory. I am not familiar with the details, but shouldn't I try to null these out afterwards? Should I be concerned about how long they stay alive for? Thanks...
  • in easier words...

    .in easier words...

    What is the simplest way to solicit yes/no input from a user, and then ask the user another yes/no question, and use those inputs to change the flow of the app (i.e., save or not save, and exit or not exit)

    user hits ESC --> presented with Yes/No question --> User hits no --> Returns to normal app
    --> User hits yes
    -
    --> presented with another Yes/No question --> User hits no --> quits without saving
    --> Quits with saving


    Where do you store the variable, and what structure do you use?
  • The reason you can't write that simple code is that MonkeyC only has a single thread of execution, if you go and block that waiting for user input, the system won't be able to continue doing all of the other things it does in the background. So the system has to delegate to you and you have to return back to it.

    The problem that you're running into is here...

    Ui.pushView( thisConfirmExit, new ConfirmExitDelegate(), Ui.SLIDE_RIGHT );
    if (globalUserWantsToQuit == true)
    {


    At the point you check the flag, the confirmation probably hasn't even fully appeared on screen yet. You're pretty close though.

    For every confirmation and delegate that you push, you need to let the system take over. When the user provides some input to the confirmation, your delegate will be called, and you can respond appropriately. Something like this...

    class ConfirmSaveDelegate extends Ui.ConfirmDelegate
    {
    function onResponse(value) {
    if (value == CONFIRM_YES) {
    Sys.println("Saving Record");
    }

    return true;
    }
    }

    class ConfirmExitDelegate extends Ui.ConfirmDelegate
    {
    function onResponse(value) {
    if (value == CONFIRM_YES) {
    Ui.pushView( new Ui.Confirmation("do you want to save?"), new ConfirmSaveDelegate(), Ui.SLIDE_RIGHT );
    }

    return true;
    }
    }

    // probably in your top-level delegate
    class MyTopLevelDelegate extends Ui.InputDelegate {

    function onKey(evt) {

    if( KEY_ESC == evt.getKey() ) {
    Ui.pushView( new Ui.Confirmation("do you want to exit?"), new ConfirmExitDelegate(), Ui.SLIDE_RIGHT );
    return true; // handled ESC input
    }

    return false;
    }
    }


    Now, if you press the escape key, you get an exit confirmation. If you confirm you want to exit, you get a save confirmation. If you accept the save confirmation, you print your message. If you want to exit the application from here, you've got to figure out how to do it properly.

    In the past I've had problems using confirmations in situations where the application would need to manage the view stack from within the confirmation. Theoretically, if you've got the main view and you want to exit the app from the save confirmation delegate, you'd just have to call Ui.popView() once. The confirmation will pop itself, and you'd be popping the main view (and exiting the application automatically). I think that you should be able to exit the app completely by calling Sys.exit() from ConfirmSaveDelegate.onResponse().

    Does all this make sense?
  • Depending on what you're asking you may not need any kind of a variable.

    For example, on "Exit? yes/no", if "yes" is selected, you could go ahead and exit the app (popview, etc), and "no, you don't have to do anything.

    For other things, I use an app global.

    For example, If I'm doing a fit recording, I'll have a global variable "var session=null", which becomes non null when the recording is started.

    Then in something like a "Save? yes/no", in the delegate for that, I do the proper action right there, and set "session=null" again if the recording is ended.
  • reply

    Simply put, I understand all this, and I really appreciate it! This makes a lot of sense. (... why didn't I think of this!!)

    I now understand that it's likely ConfirmationDelegate pop's the ConfirmationView once it has successfully handled input... and if I wanted to pop the underlying view then it might result in exiting the app, or I could just call the exit function.

    Thanks a lot
  • One thing to keep in mind, is that for a confirmation dialog, there are 3 responses, and not just 2!

    With that screen, you can select yes or no, but you can also hit the "back" button, so that's something to plan for.
  • reply

    Okay... a few things:

    (1) regarding the above implementation of pushView'ing a second view from within a first confirmationview. It worked on the simulator, but did not work on my FR630.


    (2) I was eventually able to get the implementation to work on my FR630, but utilizing some work-arounds. From within my mainDelegate function, the initial pushView to Confirmation "Do you want to exit" did work. However from within that ConfirmationDelegate, it was unable to pushView another confirmation dialog.

    I used a Timer.start method to periodically call an "Exit" function, which did work. Likewise, I used another Timer.start method to periodically call a "Do you want to save" function (which pushView'ed another confirmation dialog), and now it works...
    ...(in other words, the popView function works from my timer-message initiated exit function, not from within the ConfirmationDelegate function). Perhaps this is because of resource/thread management, or time management, or something else entirely. I also tried to pushView the Save confirmation dialog in an more expedient manner and it wouldn't work so I think it has to do with resource/thread management. Thanks for reminding me that these devices, like some computers, are single threaded...
  • regarding the above implementation of pushView'ing a second view from within a first confirmationview. It worked on the simulator, but did not work on my FR630.

    I've never tried to do a confirmation from a confirmation, but I do know that the confirmation dialog is unique in that it automatically calls popView when the user input is handled. I've run into a lot of problems trying to get flows that work using the confirmation, menu, progress bar, ... It is a pain.

    It might help to simply re-think the behavior of your application so you can avoid the need for nested confirmations. For instance, if the user presses KEY_ESC and there is no recording session active, you can prompt to exit (or just exit). If there is a recording session active, you can prompt to save/discard/cancel. If the user chooses to cancel, you do nothing, otherwise you save/discard and then exit. This is consistent with the behavior of the built-in apps and doesn't require the user to confirm twice when they want to exit.

    Travis