diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/event/LoadingEvent.java b/www-client/src/main/java/fr/agrometinfo/www/client/event/LoadingEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..cf3f91c50b4530c71707ae17a232dc92a9f6b188 --- /dev/null +++ b/www-client/src/main/java/fr/agrometinfo/www/client/event/LoadingEvent.java @@ -0,0 +1,71 @@ +package fr.agrometinfo.www.client.event; + +import org.gwtproject.event.shared.Event; + +/** + * Event for data loading: start and end. + * + * @author Olivier Maury + */ +public final class LoadingEvent extends Event<LoadingHandler> { + /** + * Start and end. + */ + public enum LoadingEventType { + /** + * When data is loaded. + */ + END, + /** + * Before retrieving data. + */ + START; + } + + /** + * Event type. + */ + public static final Type<LoadingHandler> TYPE = new Type<>(); + + /** + * Builder. + * + * @param eventType start or end of data loading + * @return built event + */ + public static LoadingEvent of(final LoadingEventType eventType) { + final LoadingEvent event = new LoadingEvent(); + event.setEventType(eventType); + return event; + } + + /** + * Start or end of data loading. + */ + private LoadingEventType eventType; + + @Override + protected void dispatch(final LoadingHandler handler) { + handler.onLoading(this); + } + + @Override + public Type<LoadingHandler> getAssociatedType() { + return TYPE; + } + + /** + * @return Start or end of data loading. + */ + public LoadingEventType getEventType() { + return eventType; + } + + /** + * @param type Start or end of data loading. + */ + public void setEventType(final LoadingEventType type) { + this.eventType = type; + } +} + diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/event/LoadingHandler.java b/www-client/src/main/java/fr/agrometinfo/www/client/event/LoadingHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..830753365612aa78a436369ee9a2404e9a70bfe3 --- /dev/null +++ b/www-client/src/main/java/fr/agrometinfo/www/client/event/LoadingHandler.java @@ -0,0 +1,13 @@ +package fr.agrometinfo.www.client.event; + +/** + * Handler for {@link LoadingEvent}. + * + * @author Olivier Maury + */ +public interface LoadingHandler { + /** + * @param event event with type + */ + void onLoading(LoadingEvent event); +} diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index 322575e2c1e8d130694174dd8622b192268d1019..d4201d6ef6814789b0b0aef16bc9bbf90aa06c65 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -153,6 +153,12 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo @DefaultStringValue("Documentation") String documentation(); + /** + * @return translation + */ + @DefaultStringValue("decouvrir.html") + String documentationPath(); + /** * @return translation */ @@ -177,12 +183,6 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo @DefaultStringValue("HTTP status text:") String failureStatusText(); - /** - * @return translation - */ - @DefaultStringValue("guide.html") - String guidePath(); - /** * @return translation */ diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/MapPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/MapPresenter.java index 0a74e37f38a0d1bbe1fbf984f62851117d49cb2a..bf9e4c236064870129291cd135369938c46346f9 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/MapPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/MapPresenter.java @@ -13,6 +13,8 @@ import com.google.gwt.core.client.GWT; import elemental2.dom.HTMLDivElement; import fr.agrometinfo.www.client.App; import fr.agrometinfo.www.client.event.FeatureSelectEvent; +import fr.agrometinfo.www.client.event.LoadingEvent; +import fr.agrometinfo.www.client.event.LoadingEvent.LoadingEventType; import fr.agrometinfo.www.client.i18n.AppConstants; import fr.agrometinfo.www.client.i18n.AppMessages; import fr.agrometinfo.www.client.util.ApplicationUtils; @@ -112,10 +114,16 @@ public final class MapPresenter implements Presenter { } request.addQueryParam("year", String.valueOf(choice.getYear())); request.addQueryParam("comparison", String.valueOf(choice.getComparison())); + request.onError(throwable -> { + App.getEventBus().fireEvent(LoadingEvent.of(LoadingEventType.END)); + }); request.onSuccess(response -> { view.setGeoJson(response.getBodyAsString(), indicator); view.setTitle(titleLines); - }).send(); + App.getEventBus().fireEvent(LoadingEvent.of(LoadingEventType.END)); + }); + App.getEventBus().fireEvent(LoadingEvent.of(LoadingEventType.START)); + request.send(); } /** @@ -138,7 +146,7 @@ public final class MapPresenter implements Presenter { public void start() { GWT.log("MapPresenter.start()"); IndicatorServiceFactory.INSTANCE.getLastModification() - .onSuccess(date -> lastModification = MSGS.computedOn(date)).send(); + .onSuccess(date -> lastModification = MSGS.computedOn(date)).send(); view = new MapView(container); view.setPresenter(this); view.init(); diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/RightPanelPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/RightPanelPresenter.java index 385f1a1ec04137b9a1843c27420f401a8dffd10a..48b585e05ab497ccacef6dd88ec170cf49dacc27 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/RightPanelPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/RightPanelPresenter.java @@ -9,6 +9,8 @@ import elemental2.dom.HTMLElement; import fr.agrometinfo.www.client.App; import fr.agrometinfo.www.client.event.FeatureSelectEvent; import fr.agrometinfo.www.client.event.FeatureSelectHandler; +import fr.agrometinfo.www.client.event.LoadingEvent; +import fr.agrometinfo.www.client.event.LoadingEvent.LoadingEventType; import fr.agrometinfo.www.client.view.BaseView; import fr.agrometinfo.www.client.view.LayoutView; import fr.agrometinfo.www.client.view.RightPanelView; @@ -91,10 +93,12 @@ public final class RightPanelPresenter implements FeatureSelectHandler, Presente currentChoice = c; periodName = pName; view.setPeriodName(pName); + App.getEventBus().fireEvent(LoadingEvent.of(LoadingEventType.START)); IndicatorServiceFactory.INSTANCE .getSummary(c.getIndicator(), c.getPeriod(), c.getLevel(), c.getFeatureId(), c.getYear()) // - .onSuccess(view::setSummary)// - .onFailed(layoutView::failureNotification)// + .onSuccess(view::setSummary) // + .onFailed(layoutView::failureNotification) // + .onComplete(() -> App.getEventBus().fireEvent(LoadingEvent.of(LoadingEventType.END))) // .send(); // Do not automatically open the panel on mobile or if it is closed if (DomGlobal.screen.width > LayoutView.MIN_WIDTH_FOR_PANELS && view.isVisible()) { diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java index 0b20040c7b73b3d54997ad04715ae455f9f24594..b806d53b9591cebd0e4d36913a1c42d079072aef 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java @@ -17,6 +17,8 @@ import org.dominokit.domino.ui.grid.flex.FlexItem; import org.dominokit.domino.ui.icons.Icons; import org.dominokit.domino.ui.icons.MdiIcon; import org.dominokit.domino.ui.layout.Layout; +import org.dominokit.domino.ui.loaders.Loader; +import org.dominokit.domino.ui.loaders.LoaderEffect; import org.dominokit.domino.ui.menu.Menu; import org.dominokit.domino.ui.menu.MenuItem; import org.dominokit.domino.ui.notifications.Notification; @@ -37,6 +39,9 @@ import elemental2.dom.HTMLAnchorElement; import elemental2.dom.HTMLDivElement; import elemental2.dom.HTMLElement; import elemental2.dom.MouseEvent; +import fr.agrometinfo.www.client.App; +import fr.agrometinfo.www.client.event.LoadingEvent; +import fr.agrometinfo.www.client.event.LoadingHandler; import fr.agrometinfo.www.client.i18n.AppConstants; import fr.agrometinfo.www.client.i18n.AppMessages; import fr.agrometinfo.www.client.presenter.LayoutPresenter; @@ -55,7 +60,8 @@ import fr.agrometinfo.www.shared.dto.PeriodDTO; * * @author Olivier Maury */ -public final class LayoutView extends AbstractBaseView<LayoutPresenter> implements LayoutPresenter.View { +public final class LayoutView extends AbstractBaseView<LayoutPresenter> +implements LayoutPresenter.View, LoadingHandler { /** * I18N constants. */ @@ -149,6 +155,17 @@ public final class LayoutView extends AbstractBaseView<LayoutPresenter> implemen */ private Layout layout; + /** + * Modal to block interface until all data are loaded. + */ + private final HtmlContentBuilder<HTMLDivElement> loadingOverlay = div().css("modal-backdrop fade in"); + + /** + * Animation in modal. + */ + private final Loader loadingLoader = Loader.create(loadingOverlay, LoaderEffect.ROTATION) // + .setLoadingText(CSTS.applicationLoading()); + /** * Presenter for {@link MapView}. */ @@ -184,6 +201,11 @@ public final class LayoutView extends AbstractBaseView<LayoutPresenter> implemen */ private final Select<Entry<String, String>> yearSelect = Select.create(CSTS.chooseYear()); + /** + * Counter for loading events. + */ + private int loadingCounter = 0; + /** * @param text link text * @param callback {@link EventCallbackFn<MouseEvent>} to be added to the click @@ -225,6 +247,7 @@ public final class LayoutView extends AbstractBaseView<LayoutPresenter> implemen layout.getRightPanel().css("agrometinfo-rightsidebar"); layout.getNavigationBar().css("agrometinfo-navbar"); + initLoader(); initRibbon(); initTopBar(); initLeftPanel(); @@ -326,6 +349,14 @@ public final class LayoutView extends AbstractBaseView<LayoutPresenter> implemen layout.showLeftPanel(); } + /** + * Initialize the loading indicator. + */ + private void initLoader() { + DomGlobal.document.body.append(loadingOverlay.element()); + App.getEventBus().addHandler(LoadingEvent.TYPE, this); + } + private void initMapView() { GWT.log("LayoutView.initMapView()"); // remove spaces @@ -381,7 +412,7 @@ public final class LayoutView extends AbstractBaseView<LayoutPresenter> implemen layout.getTopBar().appendChild(DominoElement.of(li() // .css(Styles.pull_right) // .add(a() // - .on(EventType.click, e -> goToDocumentation(CSTS.guidePath())) // + .on(EventType.click, e -> goToDocumentation(CSTS.documentationPath())) // .title(CSTS.documentation()) // .add(Icons.ALL.book_open_page_variant_mdi().clickable()))) // .showOn(ScreenMedia.MEDIUM_AND_UP) // @@ -417,6 +448,28 @@ public final class LayoutView extends AbstractBaseView<LayoutPresenter> implemen onChoiceChange(); } + @Override + public void onLoading(final LoadingEvent event) { + switch (event.getEventType()) { + case END: + loadingCounter--; + break; + case START: + loadingCounter++; + break; + default: + break; + } + GWT.log("LayoutView.onLoading() " + event.getEventType() + " => " + loadingCounter); + if (loadingCounter > 0) { + loadingOverlay.hidden(false); + loadingLoader.start(); + } else { + loadingOverlay.hidden(true); + loadingLoader.stop(); + } + } + private void onPeriodChange(final String newValue) { GWT.log("LayoutView.onPeriodChange() " + newValue); choice.setPeriod(newValue); @@ -509,7 +562,7 @@ public final class LayoutView extends AbstractBaseView<LayoutPresenter> implemen addMenuItem(dotDropMenu, "Compile", Icons.ALL.code_parentheses_box_mdi(), compileUrl); } addMenuItem(dotDropMenu, CSTS.documentation(), Icons.ALL.book_open_page_variant_mdi(), - "../" + CSTS.guidePath()); + "../" + CSTS.documentationPath()); } /** diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index cc4d5a9db31d30237e846416bacdbd531d22dac2..9dffd12827e4fbdf55160bfc9a38bd074229d156 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -23,6 +23,8 @@ credits = Crédits creditsPath = credits.html dailyValues = Valeurs journalières downloadChart = Télécharger le graphique +documentation = Documentation +documentationPath = decouvrir.html failureBody = Corps : failureHeaders = Entêtes HTTP : failureStatusText = Texte d’état HTTP : @@ -31,7 +33,7 @@ legalNotice = Mentions légales legalNoticePath = legal-notice.html messageSent = Votre message a bien été envoyé à l’équipe d’AgroMetInfo. metropolitanFrance = France métropolitaine -no= Non +no = Non normalComparison= Comparaison à la normale normalComparisonTooltip= <b>La comparaison à la normale</b> se calcule en soustrayant <b>la moyenne de l’indicateur choisi</b> pour les trente dernières années (1990-2020) de <b>l’année sélectionnée</b>. otherAgroclimApps = Autres services et outils d’AgroClim @@ -40,4 +42,4 @@ releaseNotes = Notes de version releaseNotesPath = release-notes.html seePrivacyPolicy = Consultez le paragraphe « Données personnelles » dans les mentions légales. toggleRightPanel = Afficher / masquer le panneau de droite -yes= Oui +yes = Oui