/* * Copyright © 2016 TIBCO Software,Inc.All rights reserved. * http://community.jaspersoft.com/project/jaspermobile-android * * Unless you have purchased a commercial license agreement from TIBCO Jaspersoft, * the following license terms apply: * * This program is part of TIBCO Jaspersoft Mobile for Android. * * TIBCO Jaspersoft Mobile is free software:you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation,either version 3of the License,or * (at your option)any later version. * * TIBCO Jaspersoft Mobile is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY;without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with TIBCO Jaspersoft Mobile for Android.If not,see * <http://www.gnu.org/licenses/lgpl>. */ package com.jaspersoft.android.jaspermobile.ui.view.fragment; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.webkit.ConsoleMessage; import android.webkit.WebView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.jaspersoft.android.jaspermobile.Analytics; import com.jaspersoft.android.jaspermobile.R; import com.jaspersoft.android.jaspermobile.activities.inputcontrols.InputControlsActivity; import com.jaspersoft.android.jaspermobile.activities.inputcontrols.InputControlsActivity_; import com.jaspersoft.android.jaspermobile.activities.save.SaveReportActivity_; import com.jaspersoft.android.jaspermobile.activities.share.AnnotationActivity_; import com.jaspersoft.android.jaspermobile.dialog.NumberDialogFragment; import com.jaspersoft.android.jaspermobile.dialog.NumberPickerDialogFragment; import com.jaspersoft.android.jaspermobile.dialog.ProgressDialogFragment; import com.jaspersoft.android.jaspermobile.dialog.SimpleDialogFragment; import com.jaspersoft.android.jaspermobile.domain.JasperServer; import com.jaspersoft.android.jaspermobile.domain.ScreenCapture; import com.jaspersoft.android.jaspermobile.domain.executor.PostExecutionThread; import com.jaspersoft.android.jaspermobile.internal.di.components.ReportRestViewerComponent; import com.jaspersoft.android.jaspermobile.ui.contract.RestReportContract; import com.jaspersoft.android.jaspermobile.ui.model.visualize.VisualizeViewModel; import com.jaspersoft.android.jaspermobile.ui.model.visualize.WebViewConfiguration; import com.jaspersoft.android.jaspermobile.ui.page.ReportPageState; import com.jaspersoft.android.jaspermobile.ui.presenter.ReportViewPresenter; import com.jaspersoft.android.jaspermobile.ui.view.activity.schedule.NewScheduleActivity_; import com.jaspersoft.android.jaspermobile.util.FavoritesHelper; import com.jaspersoft.android.jaspermobile.util.print.ReportPrintJob; import com.jaspersoft.android.jaspermobile.util.print.ResourcePrintJob; import com.jaspersoft.android.jaspermobile.util.resource.JasperResource; import com.jaspersoft.android.jaspermobile.util.resource.viewbinder.JasperResourceConverter; import com.jaspersoft.android.jaspermobile.webview.JasperChromeClientListener; import com.jaspersoft.android.jaspermobile.webview.SystemChromeClient; import com.jaspersoft.android.jaspermobile.webview.SystemWebViewClient; import com.jaspersoft.android.jaspermobile.webview.WebViewEnvironment; import com.jaspersoft.android.jaspermobile.widget.AbstractPaginationView; import com.jaspersoft.android.jaspermobile.widget.JSWebView; import com.jaspersoft.android.jaspermobile.widget.PaginationBarView; import com.jaspersoft.android.sdk.client.oxm.resource.ResourceLookup; import com.jaspersoft.android.sdk.util.FileUtils; import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.FragmentArg; import org.androidannotations.annotations.InstanceState; import org.androidannotations.annotations.OnActivityResult; import org.androidannotations.annotations.OptionsItem; import org.androidannotations.annotations.OptionsMenu; import org.androidannotations.annotations.OptionsMenuItem; import org.androidannotations.annotations.ViewById; import java.io.File; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import rx.Subscription; import rx.functions.Action1; /** * @author Tom Koptel * @since 2.3 */ @EFragment(R.layout.report_html_viewer) @OptionsMenu({ R.menu.report_filter_manager_menu, R.menu.webview_menu, R.menu.retrofit_report_menu, R.menu.print_menu, R.menu.report_schedule }) public class ReportViewFragment extends BaseFragment implements RestReportContract.View, NumberPickerDialogFragment.NumberDialogClickListener, NumberDialogFragment.NumberDialogClickListener { public static final String TAG = "report-view"; private static final String MIME = "text/html"; private static final String UTF_8 = "utf-8"; private static final int REQUEST_INITIAL_REPORT_PARAMETERS = 100; private static final int REQUEST_NEW_REPORT_PARAMETERS = 200; @FragmentArg protected ResourceLookup resource; @ViewById protected JSWebView webView; @ViewById(android.R.id.empty) protected TextView errorView; @ViewById protected ProgressBar progressBar; @ViewById protected PaginationBarView paginationControl; @OptionsMenuItem protected MenuItem saveReport; @OptionsMenuItem(R.id.printAction) protected MenuItem printReport; @OptionsMenuItem protected MenuItem showFilters; @OptionsMenuItem protected MenuItem favoriteAction; @OptionsMenuItem protected MenuItem aboutAction; @Inject protected FavoritesHelper favoritesHelper; @Inject protected JasperServer mServer; @Inject protected ReportViewPresenter mPresenter; @Inject protected RestReportContract.Action mActionListener; @Inject protected PostExecutionThread mPostExecutionThread; @Inject protected ResourcePrintJob mResourcePrintJob; @Inject protected Analytics mAnalytics; @Inject protected JasperResourceConverter mJasperResourceConverter; @InstanceState protected ReportPageState mReportPageState; private Toast mToast; protected boolean filtersMenuItemVisibilityFlag, saveMenuItemVisibilityFlag; private Subscription onPageChangeSubscription; private ProgressDialogFragment.CycleManager mProgressManager; private VisualizeViewModel visualizeViewModel; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); if (mReportPageState == null) { mReportPageState = new ReportPageState(); } mToast = Toast.makeText(getActivity(), "", Toast.LENGTH_LONG); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { favoritesHelper.updateFavoriteIconState(favoriteAction, resource.getUri()); saveReport.setVisible(saveMenuItemVisibilityFlag); showFilters.setVisible(filtersMenuItemVisibilityFlag); if (printReport != null) { printReport.setVisible(saveMenuItemVisibilityFlag); } } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mProgressManager = ProgressDialogFragment.builder(getFragmentManager()) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { getActivity().finish(); } }).buildManager(); injectComponents(); setupWebView(); setupPaginationControl(); runReport(); } private void setupPaginationControl() { onPageChangeSubscription = paginationControl.toRx() .pagesChangeEvents() .debounce(500, TimeUnit.MILLISECONDS) .observeOn(mPostExecutionThread.getScheduler()) .subscribe(new Action1<Integer>() { @Override public void call(Integer currentPage) { mActionListener.loadPage(String.valueOf(currentPage)); } }); paginationControl.setOnPickerSelectedListener(new AbstractPaginationView.OnPickerSelectedListener() { @Override public void onPagePickerRequested() { if (paginationControl.isTotalPagesLoaded()) { NumberPickerDialogFragment.createBuilder(getFragmentManager()) .setMinValue(1) .setCurrentValue(paginationControl.getCurrentPage()) .setMaxValue(paginationControl.getTotalPages()) .setTargetFragment(ReportViewFragment.this) .show(); } else { NumberDialogFragment.createBuilder(getFragmentManager()) .setMaxValue(Integer.MAX_VALUE) .setTargetFragment(ReportViewFragment.this) .show(); } } }); } private void runReport() { mPresenter.init(); } private void injectComponents() { getComponent(ReportRestViewerComponent.class).inject(this); mPresenter.injectView(this); } @Override public void onResume() { super.onResume(); mProgressManager.resume(getActivity()); mPresenter.resume(); } @Override public void onPause() { super.onPause(); mProgressManager.pause(getActivity()); mPresenter.pause(); } @Override public void onDestroy() { super.onDestroy(); mPresenter.destroy(); } @Override public void onDestroyView() { super.onDestroyView(); onPageChangeSubscription.unsubscribe(); mToast.cancel(); favoritesHelper.getToast().cancel(); } @OnActivityResult(REQUEST_INITIAL_REPORT_PARAMETERS) final void onInitialsParametersResult(int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { mActionListener.runReport(); } else { getActivity().finish(); } } @OnActivityResult(REQUEST_NEW_REPORT_PARAMETERS) final void onNewParametersResult(int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { boolean isNewParamsEqualOld = data.getBooleanExtra( InputControlsActivity.RESULT_SAME_PARAMS, false); if (!isNewParamsEqualOld) { mActionListener.updateReport(); } } } private void setupWebView() { progressBar.setVisibility(View.VISIBLE); SystemWebViewClient webViewClient = new SystemWebViewClient.Builder().build(); SystemChromeClient chromeClient = new SystemChromeClient.Builder(getActivity()) .withDelegateListener(new JasperChromeClientListener() { @Override public void onProgressChanged(WebView webView, int progress) { int maxProgress = progressBar.getMax(); if (progress == maxProgress) { progressBar.setVisibility(View.GONE); webView.setVisibility(View.VISIBLE); } else { progressBar.setVisibility(View.VISIBLE); webView.setVisibility(View.GONE); } } @Override public void onConsoleMessage(ConsoleMessage consoleMessage) { } }) .build(); WebViewEnvironment.configure(webView) .withDefaultSettings() .withChromeClient(chromeClient) .withWebClient(webViewClient); WebViewConfiguration configuration = new WebViewConfiguration(webView, mServer.getBaseUrl()); configuration.setSystemChromeClient(chromeClient); configuration.setSystemWebViewClient(webViewClient); visualizeViewModel = VisualizeViewModel.newModel(configuration); } @Override public void showLoading() { mProgressManager.show(); } @Override public void hideLoading() { mProgressManager.hide(getActivity()); } @Override public void showError(String message) { errorView.setVisibility(View.VISIBLE); errorView.setText(message); } @Override public void showNotification(String message) { mToast.setText(message); mToast.show(); } @Override public void hideError() { errorView.setVisibility(View.INVISIBLE); } @Override public void setFilterActionVisibility(boolean visibilityFlag) { filtersMenuItemVisibilityFlag = visibilityFlag; } @Override public void setSaveActionVisibility(boolean visibilityFlag) { saveMenuItemVisibilityFlag = visibilityFlag; } @Override public void reloadMenu() { getActivity().supportInvalidateOptionsMenu(); } @Override public void showInitialFiltersPage() { InputControlsActivity_.intent(this) .reportUri(resource.getUri()) .startForResult(REQUEST_INITIAL_REPORT_PARAMETERS); } @Override public void showPage(String pageContent) { webView.loadDataWithBaseURL(mServer.getBaseUrl(), pageContent, MIME, UTF_8, null); } @Override public void showPaginationControl(boolean visibility) { paginationControl.setVisibility(visibility ? View.VISIBLE : View.GONE); } @Override public void resetPaginationControl() { paginationControl.updateTotalCount(AbstractPaginationView.UNDEFINED_PAGE_NUMBER); } @Override public void showTotalPages(int totalPages) { paginationControl.updateTotalCount(totalPages); } @Override public void showCurrentPage(int page) { paginationControl.updateCurrentPage(page); } @Override public void showPageOutOfRangeError() { showNotification(getString(R.string.rv_out_of_range)); } @Override public void showEmptyPageMessage() { showError(getString(R.string.rv_error_empty_report)); } @Override public void showReloadMessage() { showNotification("Restoring report"); } @Override public void showProgress() { mProgressManager.show(); } @Override public void showPageLoader(boolean visibility) { progressBar.setVisibility(visibility ? View.VISIBLE : View.GONE); } @Override public ReportPageState getState() { return mReportPageState; } @Override public void showWebView(boolean visibility) { webView.setVisibility(visibility ? View.VISIBLE : View.GONE); } @Override public VisualizeViewModel getVisualize() { return visualizeViewModel; } @Override public void navigateToAnnotationPage(File file) { Intent intent = AnnotationActivity_.intent(getContext()) .imageUri(Uri.fromFile(file)) .get(); startActivity(intent); } @OptionsItem final void saveReport() { if (FileUtils.isExternalStorageWritable()) { int pages = getPaginationTotalPages(); SaveReportActivity_.intent(this) .resource(resource) .pageCount(pages) .start(); } else { Toast.makeText(getActivity(), R.string.rv_t_external_storage_not_available, Toast.LENGTH_SHORT).show(); } } @Override public int getPaginationTotalPages() { boolean isTotalPagesDefined = paginationControl.getTotalPages() != AbstractPaginationView.UNDEFINED_PAGE_NUMBER; return isTotalPagesDefined ? paginationControl.getTotalPages() : AbstractPaginationView.FIRST_PAGE; } @OptionsItem public void showFilters() { InputControlsActivity_.intent(this) .reportUri(resource.getUri()) .startForResult(REQUEST_NEW_REPORT_PARAMETERS); } @OptionsItem(R.id.newSchedule) final void scheduleAction() { JasperResource reportResource = mJasperResourceConverter.convertToJasperResource(resource); NewScheduleActivity_.intent(getActivity()) .jasperResource(reportResource) .start(); } @OptionsItem final void printAction() { mAnalytics.sendEvent( Analytics.EventCategory.RESOURCE.getValue(), Analytics.EventAction.PRINTED.getValue(), Analytics.EventLabel.REPORT.getValue() ); Bundle args = new Bundle(); args.putString(ReportPrintJob.REPORT_URI_KEY, resource.getUri()); args.putInt(ReportPrintJob.TOTAL_PAGES_KEY, getPaginationTotalPages()); args.putString(ResourcePrintJob.PRINT_NAME_KEY, resource.getLabel()); mResourcePrintJob.printResource(args); } @OptionsItem final void favoriteAction() { favoritesHelper.switchFavoriteState(resource, favoriteAction); } @OptionsItem final void aboutAction() { SimpleDialogFragment.createBuilder(getActivity(), getFragmentManager()) .setTitle(resource.getLabel()) .setMessage(resource.getDescription()) .setNegativeButtonText(R.string.ok) .setTargetFragment(this) .show(); } @OptionsItem final void refreshAction() { mActionListener.refresh(); } @OptionsItem final void shareAction() { ScreenCapture reportScreenCapture = ScreenCapture.Factory.capture(webView); mActionListener.shareReport(reportScreenCapture); } @Override public void onNumberPicked(int page, int requestCode) { updatePage(page); } @Override public void onNumberSubmit(int page, int requestCode) { updatePage(page); } private void updatePage(int page) { mActionListener.loadPage(String.valueOf(page)); } }