From 98bd66ad148b45c590b430cf8b09051bb51128d6 Mon Sep 17 00:00:00 2001 From: irgendeinich Date: Thu, 30 Jan 2020 16:26:42 +0100 Subject: [PATCH 1/5] Add new showSettingsMenu and customTitle options to configuration prop Add new showBackButtonInToolbar and onNavigationButtonClicked props to PSPDFKitView --- .../pspdfkit/react/ConfigurationAdapter.java | 22 ++++++- .../pspdfkit/react/ReactPdfViewManager.java | 5 ++ .../PdfViewNavigationButtonClickedEvent.java | 31 +++++++++ ...igurationChangeReportingPdfUiFragment.java | 33 ---------- .../main/java/com/pspdfkit/views/PdfView.java | 66 +++++++++++++------ .../pspdfkit/views/ReactPdfUiFragment.java | 60 +++++++++++++++++ .../drawable/pspdf__ic_navigation_arrow.xml | 9 +++ index.js | 21 +++++- samples/Catalog/Catalog.android.js | 13 ++-- 9 files changed, 197 insertions(+), 63 deletions(-) create mode 100644 android/src/main/java/com/pspdfkit/react/events/PdfViewNavigationButtonClickedEvent.java delete mode 100644 android/src/main/java/com/pspdfkit/views/ConfigurationChangeReportingPdfUiFragment.java create mode 100644 android/src/main/java/com/pspdfkit/views/ReactPdfUiFragment.java create mode 100644 android/src/main/res/drawable/pspdf__ic_navigation_arrow.xml diff --git a/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java b/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java index 48894693..a632ef9e 100644 --- a/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java +++ b/android/src/main/java/com/pspdfkit/react/ConfigurationAdapter.java @@ -32,8 +32,6 @@ import com.pspdfkit.configuration.page.PageScrollMode; import com.pspdfkit.configuration.sharing.ShareFeatures; -import java.util.EnumSet; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -84,6 +82,8 @@ public class ConfigurationAdapter { private static final String AUTOSAVE_DISABLED = "disableAutomaticSaving"; private static final String ANNOTATION_EDITING_ENABLED = "enableAnnotationEditing"; private static final String EDITABLE_ANNOTATION_TYPES = "editableAnnotationTypes"; + private static final String SHOW_SETTINGS_MENU = "showSettingsMenu"; + private static final String CUSTOM_TITLE = "customTitle"; private final PdfActivityConfiguration.Builder configuration; @@ -174,6 +174,12 @@ public ConfigurationAdapter(@NonNull Context context, ReadableMap configuration) if (configuration.hasKey(EDITABLE_ANNOTATION_TYPES)) { configureEditableAnnotationTypes(configuration.getArray(EDITABLE_ANNOTATION_TYPES)); } + if (configuration.hasKey(SHOW_SETTINGS_MENU)) { + configureSettingsMenuShown(configuration.getBoolean(SHOW_SETTINGS_MENU)); + } + if (configuration.hasKey(CUSTOM_TITLE)) { + configureCustomTitle(configuration.getString(CUSTOM_TITLE)); + } } } @@ -396,6 +402,18 @@ private void configureEditableAnnotationTypes(@Nullable final ReadableArray edit configuration.editableAnnotationTypes(parsedTypes); } + private void configureSettingsMenuShown(final boolean settingsMenuShown) { + if (settingsMenuShown) { + configuration.showSettingsMenu(); + } else { + configuration.hideSettingsMenu(); + } + } + + private void configureCustomTitle(@Nullable final String customTitle) { + configuration.title(customTitle); + } + public PdfActivityConfiguration build() { return configuration.build(); } diff --git a/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java b/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java index 0ccdf097..2e0a0db1 100644 --- a/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java +++ b/android/src/main/java/com/pspdfkit/react/ReactPdfViewManager.java @@ -148,6 +148,11 @@ public void setMenuItemGrouping(PdfView view, @NonNull ReadableArray menuItemGro view.setMenuItemGroupingRule(groupingRule); } + @ReactProp(name = "showBackButtonInToolbar") + public void setShowBackButtonInToolbar(@NonNull final PdfView view, final boolean showBackButtonInToolbar) { + view.setShowBackButtonInToolbar(showBackButtonInToolbar); + } + @Nullable @Override public Map getExportedCustomDirectEventTypeConstants() { diff --git a/android/src/main/java/com/pspdfkit/react/events/PdfViewNavigationButtonClickedEvent.java b/android/src/main/java/com/pspdfkit/react/events/PdfViewNavigationButtonClickedEvent.java new file mode 100644 index 00000000..26fa5f06 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/react/events/PdfViewNavigationButtonClickedEvent.java @@ -0,0 +1,31 @@ +package com.pspdfkit.react.events; + +import androidx.annotation.IdRes; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.uimanager.events.Event; +import com.facebook.react.uimanager.events.RCTEventEmitter; + +/** + * Event sent by the {@link com.pspdfkit.views.PdfView} when navigation button was clicked. + */ +public class PdfViewNavigationButtonClickedEvent extends Event { + + public static final String EVENT_NAME = "pdfViewNavgigationButtonClicked"; + + public PdfViewNavigationButtonClickedEvent(@IdRes int viewId) { + super(viewId); + } + + @Override + public String getEventName() { + return EVENT_NAME; + } + + @Override + public void dispatch(RCTEventEmitter rctEventEmitter) { + WritableMap eventData = Arguments.createMap(); + rctEventEmitter.receiveEvent(getViewTag(), getEventName(), eventData); + } +} diff --git a/android/src/main/java/com/pspdfkit/views/ConfigurationChangeReportingPdfUiFragment.java b/android/src/main/java/com/pspdfkit/views/ConfigurationChangeReportingPdfUiFragment.java deleted file mode 100644 index 10e6bc1d..00000000 --- a/android/src/main/java/com/pspdfkit/views/ConfigurationChangeReportingPdfUiFragment.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.pspdfkit.views; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.pspdfkit.configuration.activity.PdfActivityConfiguration; -import com.pspdfkit.ui.PdfUiFragment; - -/** This {@link PdfUiFragment} reports when the {@link PdfActivityConfiguration} was changed. */ -public class ConfigurationChangeReportingPdfUiFragment extends PdfUiFragment { - - @Nullable private OnConfigurationChangedListener onConfigurationChangedListener; - - public void setOnConfigurationChangedListener(@Nullable OnConfigurationChangedListener listener) { - this.onConfigurationChangedListener = listener; - } - - @Override - public void performApplyConfiguration(@NonNull PdfActivityConfiguration configuration) { - super.performApplyConfiguration(configuration); - - if (this.onConfigurationChangedListener != null) { - onConfigurationChangedListener.onConfigurationChanged(); - } - } - - /** Listener that is notified when the user changes the configuration (scroll direction etc.) via the UI. */ - public interface OnConfigurationChangedListener { - - /** Called when the configuration changed, reset your {@link com.pspdfkit.ui.PdfFragment} listeners in here. */ - void onConfigurationChanged(); - } -} diff --git a/android/src/main/java/com/pspdfkit/views/PdfView.java b/android/src/main/java/com/pspdfkit/views/PdfView.java index 65d4b0bf..3d0363f9 100644 --- a/android/src/main/java/com/pspdfkit/views/PdfView.java +++ b/android/src/main/java/com/pspdfkit/views/PdfView.java @@ -34,11 +34,11 @@ import com.pspdfkit.react.events.PdfViewDocumentLoadFailedEvent; import com.pspdfkit.react.events.PdfViewDocumentSaveFailedEvent; import com.pspdfkit.react.events.PdfViewDocumentSavedEvent; +import com.pspdfkit.react.events.PdfViewNavigationButtonClickedEvent; import com.pspdfkit.react.events.PdfViewStateChangedEvent; import com.pspdfkit.react.helper.DocumentJsonDataProvider; import com.pspdfkit.ui.DocumentDescriptor; import com.pspdfkit.ui.PdfFragment; -import com.pspdfkit.ui.PdfUi; import com.pspdfkit.ui.PdfUiFragment; import com.pspdfkit.ui.PdfUiFragmentBuilder; import com.pspdfkit.ui.toolbar.grouping.MenuItemGroupingRule; @@ -50,6 +50,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -97,7 +98,9 @@ public class PdfView extends FrameLayout { @Nullable private PdfUiFragment fragment; - private BehaviorSubject pdfUiFragmentGetter = BehaviorSubject.create(); + + /** We wrap the fragment in a list so we can have a state that encapsulates no element being set. */ + private BehaviorSubject> pdfUiFragmentGetter = BehaviorSubject.createDefault(Collections.emptyList()); /** An internal id we generate so we can track if fragments found belong to this specific PdfView instance. */ private int internalId; @@ -219,6 +222,14 @@ public void setMenuItemGroupingRule(@NonNull MenuItemGroupingRule groupingRule) pdfViewModeController.setMenuItemGroupingRule(groupingRule); } + public void setShowBackButtonInToolbar(final boolean showBackButtonInToolbar) { + pendingFragmentActions.add(getCurrentPdfUiFragment() + .observeOn(Schedulers.io()) + .subscribe(pdfUiFragment -> { + ((ReactPdfUiFragment) pdfUiFragment).setShowBackButtonInToolbar(showBackButtonInToolbar); + })); + } + private void setupFragment() { if (fragmentTag != null && configuration != null && document != null) { PdfUiFragment pdfFragment = (PdfUiFragment) fragmentManager.findFragmentByTag(fragmentTag); @@ -235,7 +246,7 @@ private void setupFragment() { if (pdfFragment == null) { pdfFragment = PdfUiFragmentBuilder.fromDocumentDescriptor(getContext(), DocumentDescriptor.fromDocument(document)) .configuration(configuration) - .fragmentClass(ConfigurationChangeReportingPdfUiFragment.class) + .fragmentClass(ReactPdfUiFragment.class) .build(); // We put our internal id so we can track if this fragment belongs to us, used to handle orphaned fragments after hot reloads. pdfFragment.getArguments().putInt(ARG_ROOT_ID, internalId); @@ -249,7 +260,7 @@ private void setupFragment() { // The document changed create a new PdfFragment. pdfFragment = PdfUiFragmentBuilder.fromDocumentDescriptor(getContext(), DocumentDescriptor.fromDocument(document)) .configuration(configuration) - .fragmentClass(ConfigurationChangeReportingPdfUiFragment.class) + .fragmentClass(ReactPdfUiFragment.class) .build(); prepareFragment(pdfFragment); } else if (fragmentView != null && fragmentView.getParent() != this) { @@ -266,7 +277,7 @@ private void setupFragment() { } fragment = pdfFragment; - pdfUiFragmentGetter.onNext(fragment); + pdfUiFragmentGetter.onNext(Collections.singletonList(pdfFragment)); } } @@ -279,9 +290,17 @@ private void prepareFragment(final PdfUiFragment pdfUiFragment) { pdfUiFragment.setOnContextualToolbarLifecycleListener(pdfViewModeController); pdfUiFragment.getPSPDFKitViews().getFormEditingBarView().addOnFormEditingBarLifecycleListener(pdfViewModeController); - ((ConfigurationChangeReportingPdfUiFragment) pdfUiFragment).setOnConfigurationChangedListener(() -> { - // If the configuration was changed from the UI a new fragment will be created, reattach our listeners. - preparePdfFragment(pdfUiFragment.getPdfFragment()); + ((ReactPdfUiFragment) pdfUiFragment).setReactPdfUiFragmentListener(new ReactPdfUiFragment.ReactPdfUiFragmentListener() { + @Override + public void onConfigurationChanged(@NonNull PdfUiFragment pdfUiFragment) { + // If the configuration was changed from the UI a new fragment will be created, reattach our listeners. + preparePdfFragment(pdfUiFragment.getPdfFragment()); + } + + @Override + public void onNavigationButtonClicked(@NonNull PdfUiFragment pdfUiFragment) { + eventDispatcher.dispatchEvent(new PdfViewNavigationButtonClickedEvent(getId())); + } }); // After attaching the PdfUiFragment we can access the PdfFragment. @@ -315,14 +334,14 @@ public void removeFragment(boolean makeInactive) { // Clear everything. isActive = false; document = null; + + pendingFragmentActions.dispose(); + pendingFragmentActions = new CompositeDisposable(); } fragment = null; - pdfUiFragmentGetter.onComplete(); - pdfUiFragmentGetter = BehaviorSubject.create(); - pendingFragmentActions.dispose(); - pendingFragmentActions = new CompositeDisposable(); + pdfUiFragmentGetter.onNext(Collections.emptyList()); } void manuallyLayoutChildren() { @@ -622,9 +641,15 @@ public Maybe setFormFieldValue(@NonNull String formElementName, @NonNul /** Returns the {@link PdfFragment} hosted in the current {@link PdfUiFragment}. */ private Observable getCurrentPdfFragment() { + return getPdfFragment() + .take(1); + } + + /** Returns the {@link PdfUiFragment}. */ + private Observable getCurrentPdfUiFragment() { return pdfUiFragmentGetter - .filter(pdfUiFragment -> pdfUiFragment.getPdfFragment() != null) - .map(PdfUiFragment::getPdfFragment) + .filter(pdfUiFragments -> !pdfUiFragments.isEmpty()) + .map(pdfUiFragments -> pdfUiFragments.get(0)) .take(1); } @@ -642,18 +667,15 @@ public Maybe getActivePdfFragment() { */ public Observable getPdfFragment() { return pdfUiFragmentGetter + .filter(pdfUiFragments -> !pdfUiFragments.isEmpty()) + .map(pdfUiFragments -> pdfUiFragments.get(0)) .filter(pdfUiFragment -> pdfUiFragment.getPdfFragment() != null) .map(PdfUiFragment::getPdfFragment); } - /** Returns the current fragment if it is set. */ - public Maybe getFragment() { - return pdfUiFragmentGetter.firstElement().map(PdfUi::getPdfFragment); - } - /** Returns the event registration map for the default events emitted by the {@link PdfView}. */ public static Map> createDefaultEventRegistrationMap() { - return MapBuilder.of(PdfViewStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onStateChanged"), + Map> map = MapBuilder.of(PdfViewStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onStateChanged"), PdfViewDocumentSavedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onDocumentSaved"), PdfViewAnnotationTappedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onAnnotationTapped"), PdfViewAnnotationChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onAnnotationsChanged"), @@ -661,5 +683,9 @@ public static Map> createDefaultEventRegistrationMa PdfViewDocumentSaveFailedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onDocumentSaveFailed"), PdfViewDocumentLoadFailedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onDocumentLoadFailed") ); + + map.put(PdfViewNavigationButtonClickedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onNavigationButtonClicked")); + + return map; } } diff --git a/android/src/main/java/com/pspdfkit/views/ReactPdfUiFragment.java b/android/src/main/java/com/pspdfkit/views/ReactPdfUiFragment.java new file mode 100644 index 00000000..8e27f001 --- /dev/null +++ b/android/src/main/java/com/pspdfkit/views/ReactPdfUiFragment.java @@ -0,0 +1,60 @@ +package com.pspdfkit.views; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; + +import com.pspdfkit.configuration.activity.PdfActivityConfiguration; +import com.pspdfkit.react.R; +import com.pspdfkit.ui.PdfUiFragment; + +/** This {@link PdfUiFragment} reports when the {@link PdfActivityConfiguration} was changed and allows a navigation icon to be shown and hidden. */ +public class ReactPdfUiFragment extends PdfUiFragment { + + @Nullable private ReactPdfUiFragmentListener reactPdfUiFragmentListener; + + void setReactPdfUiFragmentListener(@Nullable ReactPdfUiFragmentListener listener) { + this.reactPdfUiFragmentListener = listener; + } + + @Override + public void performApplyConfiguration(@NonNull PdfActivityConfiguration configuration) { + super.performApplyConfiguration(configuration); + + if (this.reactPdfUiFragmentListener != null) { + reactPdfUiFragmentListener.onConfigurationChanged(this); + } + } + + + /** When set to true will add a navigation arrow to the toolbar. */ + void setShowBackButtonInToolbar(final boolean showBackButtonInToolbar) { + if (getView() == null) { + return; + } + Toolbar toolbar = getView().findViewById(R.id.pspdf__toolbar_main); + if (showBackButtonInToolbar) { + toolbar.setNavigationIcon(R.drawable.pspdf__ic_navigation_arrow); + toolbar.setNavigationOnClickListener(v -> { + if (reactPdfUiFragmentListener != null) { + reactPdfUiFragmentListener.onNavigationButtonClicked(this); + } + }); + } else { + toolbar.setNavigationIcon(null); + toolbar.setNavigationOnClickListener(null); + } + } + + /** + * Listener that notifies of actions taken directly in the PdfUiFragment. + */ + public interface ReactPdfUiFragmentListener { + + /** Called when the configuration changed, reset your {@link com.pspdfkit.ui.PdfFragment} listeners in here. */ + void onConfigurationChanged(@NonNull PdfUiFragment pdfUiFragment); + + /** Called when the back navigation button was clicked. */ + void onNavigationButtonClicked(@NonNull PdfUiFragment pdfUiFragment); + } +} diff --git a/android/src/main/res/drawable/pspdf__ic_navigation_arrow.xml b/android/src/main/res/drawable/pspdf__ic_navigation_arrow.xml new file mode 100644 index 00000000..e669aa94 --- /dev/null +++ b/android/src/main/res/drawable/pspdf__ic_navigation_arrow.xml @@ -0,0 +1,9 @@ + + + diff --git a/index.js b/index.js index 23760132..bea5404f 100644 --- a/index.js +++ b/index.js @@ -38,6 +38,7 @@ class PSPDFKitView extends React.Component { onDocumentLoadFailed={this._onDocumentLoadFailed} onAnnotationTapped={this._onAnnotationTapped} onAnnotationsChanged={this._onAnnotationsChanged} + onNavigationButtonClicked={this._onNavigationButtonClicked} onDataReturned={this._onDataReturned} /> ); @@ -82,6 +83,12 @@ class PSPDFKitView extends React.Component { } }; + _onNavigationButtonClicked = event => { + if (this.props.onNavigationButtonClicked) { + this.props.onNavigationButtonClicked(event.nativeEvent); + } + }; + _onDataReturned = event => { let { requestId, result, error } = event.nativeEvent; let promise = this._requestMap[requestId]; @@ -639,7 +646,19 @@ PSPDFKitView.propTypes = { * * @platform ios */ - toolbarTitle: PropTypes.string + toolbarTitle: PropTypes.string, + /** + * showBackButtonInToolbar: When set to true the toolbar integrated into the PSPDFKitView will display a back button in the top left corner. + * + * @platform android + */ + showBackButtonInToolbar: PropTypes.bool, + /** + * onNavigationButtonClicked: When showBackButtonInToolbar is set to true this will notify you when the back button is clicked. + * + * @platform android + */ + onNavigationButtonClicked: PropTypes.func }; if (Platform.OS === "ios" || Platform.OS === "android") { diff --git a/samples/Catalog/Catalog.android.js b/samples/Catalog/Catalog.android.js index 49aa6716..4d4dc175 100644 --- a/samples/Catalog/Catalog.android.js +++ b/samples/Catalog/Catalog.android.js @@ -272,13 +272,8 @@ class PdfViewScreen extends Component<{}> { const params = navigation.state.params || {}; return { - title: "PDF", - headerRight: ( -