5

I'm build my app with Mortar + Flow. I'm trying to figure out the correct way to show a popup that requests some text from the user. I've created this popup class:

public class SavedPageTitleInputPopup implements Popup<SavedPageTitleInput, Optional<String>> {

private final Context context;

private AlertDialog dialog;

public SavedPageTitleInputPopup(Context context) {
    this.context = context;
}

@Override public Context getContext() {
    return context;
}

@Override
public void show(final SavedPageTitleInput info, boolean withFlourish,
                 final PopupPresenter<SavedPageTitleInput, Optional<String>> presenter) {
    if (dialog != null) throw new IllegalStateException("Already showing, can't show " + info);

    final EditText input = new EditText(context);
    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                                                                 LinearLayout.LayoutParams.MATCH_PARENT);
    input.setLayoutParams(lp);
    input.setText(info.savedPage.getName());

    dialog = new AlertDialog.Builder(context).setTitle(info.title)
                                             .setView(input)
                                             .setMessage(info.body)
                                             .setPositiveButton(info.confirm, new DialogInterface.OnClickListener() {
                                                 @Override public void onClick(DialogInterface d, int which) {
                                                     dialog = null;
                                                     final String newTitle = Strings.emptyToNull(String.valueOf(input.getText()));
                                                     presenter.onDismissed(Optional.fromNullable(newTitle));
                                                 }
                                             })
                                             .setNegativeButton(info.cancel, new DialogInterface.OnClickListener() {
                                                 @Override public void onClick(DialogInterface d, int which) {
                                                     dialog = null;
                                                     presenter.onDismissed(Optional.<String>absent());
                                                 }
                                             })
                                             .setCancelable(true)
                                             .setOnCancelListener(new DialogInterface.OnCancelListener() {
                                                 @Override public void onCancel(DialogInterface d) {
                                                     dialog = null;
                                                     presenter.onDismissed(Optional.<String>absent());
                                                 }
                                             })
                                             .show();
}

@Override public boolean isShowing() {
    return dialog != null;
}

@Override public void dismiss(boolean withFlourish) {
    dialog.dismiss();
    dialog = null;
}
}

This class works as expected. It uses the SavedPage to figure out what to display in the dialog and it returns the users input to the PopupPresenter using PopupPresenter#onDismissed when the correct button is pressed.

My problem is writing the PopupPresenter subclass used to present the dialog and process the input. This is what I have right now:

new PopupPresenter<SavedPage, Optional<String>>() {
  @Override protected void onPopupResult(Optional<String> result) {
    if (result.isPresent()) {
      // The user entered something, so update the API 
      // Oh wait, I don't have a reference to the SavedPage
      // that was displayed in the dialog!
    }
  }
}

As the comments say, I don't have a reference to the SavedPage that was displayed in the dialog. It was stored in the whatToShow field in PopupPresenter, but this field is nulled out right before onPopupResult is called. It seems like I would be unnecessarily repeating myself to keep an additional copy of the SavedPage.

Edward Dale
  • 29,597
  • 13
  • 90
  • 129

1 Answers1

0

There isn't a lot of documentation yet on PopupPresenter and Popup. The only thing I have seen is a basic example in the sample project. They create a ConfirmerPopup based on data within the Confirmation object. The purpose of the ConfirmerPopup is to capture a boolean decision from the user based on the title/body given to the Confirmation object as seen by the class declaration.

public class ConfirmerPopup implements Popup<Confirmation, Boolean> {

In your case you want to capture additional user inputted text from the user. When PopupPresenter#onPopupResult is called the result object should contain all of the data needed from SavedPageTitleInputPopup. Modify your SavedPageTitleInputPopup as follows

public class SavedPageTitleInputPopup implements Popup<SavedPage, SavedPageResults> {
  private final Context context;
  private AlertDialog dialog;

  public SavedPageTitleInputPopup(Context context) {
    this.context = context;
  }

  @Override public Context getContext() {
    return context;
  }

  @Override
  public void show(SavedPage info, boolean withFlourish, final PopupPresenter<SavedPage, SavedPageResults> presenter) {
    if (dialog != null) throw new IllegalStateException("Already showing, can't show " + info);
    // Create your Dialog but scrape all user data within OnClickListeners
    final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    //Anything else you need to do... .setView() or .setTitle() for example
    builder.setPositiveButton(info.confirm, new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface d, int which) {
        dialog = null;
        //Save data to SavedPageResults
        final SavedPageResults results = new SavedPageResults():
        presenter.onDismissed(results);
      }
    });
    builder.setNegativeButton(info.cancel, new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface d, int which) {
        dialog = null;
        final SavedPageResults results = new SavedPageResults();
        presenter.onDismissed(results);
      }
    });
    dialog = builder.show();
  }

  @Override public boolean isShowing() {
    return dialog != null;
  }

  @Override public void dismiss(boolean withFlourish) {
    dialog.dismiss();
    dialog = null;
  }
}  

Your PopupPresenter doesn't need to know anything about the Dialog's implementation now.

new PopupPresenter<SavedPage, SavedPageResults>() {
  @Override protected void onPopupResult(SavedPageResults result) {
    if (result.isPresent()) {
      updateUi(result.getSavedText());  
    }
  }
}
Alex
  • 98
  • 7
  • Thanks for the answer. I've already seen the `ConfirmerPopup` example and modified it so that my dialog is displayed like I want it. As I mentioned in the question, my problem has to do with keeping a reference to the `whatToShow` field in the `PopupPresenter`. I don't think you answered that. – Edward Dale May 06 '14 at 02:00
  • You shouldn't need a reference to `whatToShow`. What do you need to access in `onPopupResult` that you can't get within the `OnClickListener`? – Alex May 06 '14 at 11:34
  • @scompt.com if you update your question with your full `SavedPageTitleInputPopup` and `popup.xml` I will show you what I mean. – Alex May 06 '14 at 18:03
  • I've added the full `SavedPageTitleInputPopup`. I would like a reference to the `SavedPageTitleInput` instance that I pass to `show`, but it's nulled out before the `onPopupResult` call is made. – Edward Dale May 07 '14 at 03:19
  • Thanks @scompt.com. What is the reason behind needing a reference to SavedPageTitleInput? What are you trying to do? – Alex May 07 '14 at 10:50