Hi everyone,
I have a requirement for my apps whenever user access from mobile, I must switch the view to mobile version while still using the same presenter for the desktop version. Basically, my apps have one main module which contains of :
/*----- IMainEventBus.java ------- */
@Events(startPresenter = MainPresenter.class, historyOnStart = true, ginModules = Mvp4gGinModule.class)
@Debug(logLevel = LogLevel.SIMPLE, logger = CustomLogger.class)
@ChildModules({
@ChildModule(moduleClass = ICustomModule.class, async = true, autoDisplay = false)
})
@PlaceService(CustomPlaceService.class)
public interface IMainEventBus extends EventBusWithLookup {
@Event(forwardToModules = ICustomModule.class, historyConverter = MainHistoryConverter.class, name = "custom", navigationEvent = true)
void goToCustom();
@Event(handlers = MainPresenter.class)
void changeBody(IsWidget body);
@LoadChildModuleError
@Event(handlers = MainPresenter.class)
void errorOnLoad(Throwable reason);
@BeforeLoadChildModule
@Event(handlers = MainPresenter.class)
void beforeLoad();
@AfterLoadChildModule
@Event(handlers = MainPresenter.class)
void afterLoad();
@InitHistory
@Event(handlers = MainPresenter.class)
void start();
}
/*--------- IMainView.java -------------*/
public interface IMainView extends ReverseViewInterface<IMainView.IMainPresenter> {
public interface IMainPresenter {
}
void setBody(IsWidget body);
public void maskLoading(boolean isMask);
public void maskError(boolean isMask, String errorMessage);
}
/*-------- MainPresenter.java ---------*/
@Presenter(view = MainView.class)
public class MainPresenter extends BasePresenter<IMainView, IMainEventBus> implements IMainPresenter {
public void onStart() {
eventBus.setApplicationHistoryStored(true);
}
public void onChangeBody(IsWidget body) {
view.setBody(body);
}
public void onErrorOnLoad(Throwable reason) {
view.maskError(true, "Error Message : " + reason.getMessage());
}
public void onBeforeLoad() {
view.maskLoading(true);
}
public void onAfterLoad() {
view.maskLoading(false);
}
}
/*---------- MainView.java -------------*/
public class MainView extends SimplePanel implements IMainView {
private IMainPresenter presenter;
private final PopupPanel popup = new PopupPanel(false, true); // Create a modal dialog box that will not auto-hide
private final PopupPanel popupError = new PopupPanel(false, true); // Create a modal dialog box that will not auto-hide
private final Label errorLabel = new Label();
public MainView() {
super();
popup.add(new Label("Please wait"));
popup.setGlassEnabled(true); // Enable the glass panel
popupError.add(errorLabel);
popupError.setGlassEnabled(true); // Enable the glass panel
}
public void setBody(IsWidget body) {
setWidget(body);
}
@Override
public void setPresenter(IMainPresenter _presenter) {
this.presenter = _presenter;
}
@Override
public IMainPresenter getPresenter() {
return this.presenter;
}
public void maskLoading(boolean isMask) {
if (isMask)
popup.center(); // Center the popup and make it visible
else
popup.hide();
}
public void maskError(boolean isMask, String errorMessage) {
if (isMask) {
errorLabel.setText(errorMessage);
popupError.center();
}
else
popupError.hide();
}
}
/*------- Mvp4gGinModule.java -------*/
public class Mvp4gGinModule extends AbstractGinModule {
@Override
protected void configure() {
}
}
/*------- end of main module --------*/
Then I have one child module consists of these:
/*------- ICustomModule.java ------------*/
@HistoryName("custom")
public interface ICustomModule extends Mvp4gModule {
}
/*----- ICustomEventBus.java -------*/
@Events(startPresenter = CustomPresenter.class, module = ICustomModule.class, ginModuleProperties = "ginModule")
public interface ICustomEventBus extends EventBus {
@Event(forwardToParent = true)
void changeBody(IsWidget body);
@Event(handlers = CustomPresenter.class, navigationEvent = true)
void goToCustom();
}
/*----- ICustomView.java --------*/
public interface ICustomView extends IsWidget, LazyView, ReverseViewInterface<ICustomView.ICustomPresenter> {
public interface ICustomPresenter {
public Integer getSecretNumber();
}
}
/*---- CustomPresenter.java -----*/
@Presenter(view = CustomView.class)
public class CustomPresenter extends LazyPresenter<ICustomView, ICustomEventBus> implements ICustomPresenter {
private Integer secretNumber = 88;
@Override
public void setView(ICustomView view) {
GWT.log("setView");
String ua = Navigator.getUserAgent().toLowerCase();
if (ua.indexOf("iphone") != -1) {
// iPhone device
} else if (ua.indexOf("android") != -1) {
// android device
this.view = new CustomMobileView();
} else {
// not mobile device
this.view = new CustomView();
}
this.view.setPresenter(this);
}
@Override
public void bindView() {
GWT.log("bindView");
}
public void onGoToCustom() {
eventBus.changeBody(view);
}
@Override
public Integer getSecretNumber() {
return secretNumber;
}
}
/*----- CustomView.java --------*/
public class CustomView extends Composite implements ICustomView {
private ICustomPresenter presenter;
@Override
public void createView() {
Button btn = new Button("Desktop Web Button");
btn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
Window.alert("Greetings from desktop web! Here is our secret number: "+presenter.getSecretNumber());
}
});
initWidget(btn);
}
public void setPresenter(ICustomPresenter presenter) {
this.presenter = presenter;
}
@Override
public ICustomPresenter getPresenter() {
return this.presenter;
}
}
/*-------- CustomMobileView.java ------*/
public class CustomMobileView extends Composite implements ICustomView {
private ICustomPresenter presenter;
@Override
public void createView() {
AnimationHelper animationHelper = new AnimationHelper();
RootPanel.get().add(animationHelper);
RootFlexPanel rootFlexPanel = new RootFlexPanel();
Button button = new Button("Hello mgwt");
button.addTapHandler(new TapHandler() {
@Override
public void onTap(TapEvent event) {
AlertDialog dialog = new AlertDialog("Information", "Hello there! Here is our secret number: "+presenter.getSecretNumber());
dialog.show();
}
});
rootFlexPanel.add(button);
animationHelper.goTo(rootFlexPanel, Animations.SLIDE);
}
public void setPresenter(ICustomPresenter presenter) {
this.presenter = presenter;
}
@Override
public ICustomPresenter getPresenter() {
return this.presenter;
}
}
/*------- end of custom module --------*/
Then here are my questions:
- What is the pros and cons of my technique? From what I learn at mvp4g group, this technique was called mvp4g technique.
- Is there any better solution beside this technique, because somehow I just felt it's a little bit clumsy. I read about the GIN technique from here: https://code.google.com/p/mvp4g/wiki/GinIntegration#Setting_GIN_module_for_multiple_devices. I have tried it but still failed because the child module extends Mvp4gModule and not AbstractGinModule. I don't know how to do it for the child module, and the example Mvp4gModules just show it for parent module. Could someone help me implement this gin technique?
- It is a good thing to use single presenter with switchable view? I choose this technique because I want to reuse the business logic inside my presenter instead of creating two presenter, is this the right way? Any thought or share will be appreciated.
- What I need is using single presenter and the view was depend on user browser, if it is mobile web browser, the mobile view was selected, if it was desktop browser, the desktop view was selected. Am I on the right track to achieve my goal?
Thanks & Regards.