Skip to content

Commit fc6c37f

Browse files
committed
Release 5.4.0
1 parent 3fe46b2 commit fc6c37f

File tree

70 files changed

+5844
-831
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+5844
-831
lines changed

CHANGELOG.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
## 5.4.0 - 18 Feb 2026
2+
3+
- [**Beta**] Adds federated plugin architecture with platform-specific packages (`nutrient_flutter_platform_interface`, `nutrient_flutter_android`, `nutrient_flutter_ios`, `nutrient_flutter_web`) for native SDK bindings via JNI (Android), FFI (iOS), and `dart:js_interop` (Web). Refer to the [platform adapters](/guides/flutter/platform-adapters/) guide for details. (J#HYB-895)
4+
- [**Beta**] Adds platform adapter APIs (`NutrientPlatformAdapter`, `NutrientController`, `NutrientViewHandle`), enabling direct native SDK access alongside the existing Pigeon-based API. (J#HYB-895)
5+
- Adds platform adapter examples demonstrating native SDK customization, event handling, and UI configuration. (J#HYB-895)
6+
- Adds the `ThemeConfiguration` class to `PdfConfiguration` for configuring the viewer’s theme, including support for light, dark, and custom themes. (J#HYB-947)
7+
- Updates web conditional exports to use `dart.library.js_interop`, replacing the deprecated `dart.library.html`. (J#HYB-895)
8+
- Fixes an Android crash when using the `startPage` configuration option. (J#HYB-948)
9+
- Fixes an iOS issue where `iOSRightBarButtonItems` and `iOSLeftBarButtonItems` weren’t displayed. (J#HYB-948)
10+
11+
112
## 5.3.1 - 26 Jan 2026
213

3-
- Fixes an Android crash when adding image annotations with the `annotationsCreated` event listener active. (#50400)
4-
- Fixes a type cast error when parsing `GoToAction` link annotations with integer parameters.
14+
- Fixes an Android crash when adding image annotations with the `annotationsCreated` event listener active. (#50437)
15+
- Fixes a type cast error when parsing `GoToAction` link annotations with integer parameters. (#50437)
516

617
## 5.3.0 — 22 Jan 2026
718

@@ -19,6 +30,7 @@
1930
- Updates to Nutrient iOS SDK 26.4.0.
2031
- Updates to Nutrient Android SDK 10.10.1.
2132
- Fixes an Android issue where the PDF view was hidden behind the keyboard when editing form fields. (J#HYB-929)
33+
- Adds `enableFormEditing` configuration option to `PdfConfiguration` for controlling form field editing independently from annotation editing on iOS and Android. (J#HYB-925)
2234

2335
## 5.2.0 - 13 Oct 2025
2436

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ You can include the Nutrient Web SDK using either CDN or local installation:
9292
Add the following script to your `web/index.html` file:
9393

9494
```html
95-
<script src="https://cdn.cloud.pspdfkit.com/pspdfkit-web@1.1.0/nutrient-viewer.js"></script>
95+
<script src="https://cdn.cloud.pspdfkit.com/pspdfkit-web@1.10.0/nutrient-viewer.js"></script>
9696
```
9797

98-
**Note:** Replace `1.1.0` with the latest version of Nutrient Web SDK. Check the [latest releases][web changelog] for the current version.
98+
**Note:** Replace `1.10.0` with the latest version of Nutrient Web SDK. Check the [latest releases][web changelog] for the current version.
9999

100100
#### Option 2: Local Installation
101101

android/src/main/java/com/pspdfkit/flutter/pspdfkit/ConfigurationAdapter.java

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class ConfigurationAdapter {
9191

9292
// Annotation, Forms and Bookmark Options
9393
private static final String ENABLE_ANNOTATION_EDITING = "enableAnnotationEditing";
94+
private static final String ENABLE_FORM_EDITING = "enableFormEditing";
9495
private static final String SHOW_ANNOTATION_LIST_ACTION = "showAnnotationListAction";
9596
private static final String SHOW_ANNOTATION_CREATION_ACTION = "showAnnotationCreationAction";
9697

@@ -208,6 +209,9 @@ class ConfigurationAdapter {
208209

209210
private static final String ENABLE_AI_ASSISTANT = "enableAiAssistant";
210211

212+
// Theme Configuration
213+
private static final String THEME_CONFIGURATION = "themeConfiguration";
214+
211215
private static final Map<String, SignatureSavingStrategy> signatureSavingStrategyMap = new HashMap<>(){{
212216
put("alwaysSave", SignatureSavingStrategy.ALWAYS_SAVE);
213217
put("saveIfSelected", SignatureSavingStrategy.SAVE_IF_SELECTED);
@@ -222,6 +226,8 @@ class ConfigurationAdapter {
222226
private String password = null;
223227
private boolean enableInstantComments = false;
224228
private boolean hideAnnotationCreationButton = false;
229+
@Nullable
230+
private HashMap<String, Integer> themeColors = null;
225231

226232
ConfigurationAdapter(@NonNull Context context,
227233
@Nullable HashMap<String, Object> configurationMap) {
@@ -270,9 +276,9 @@ class ConfigurationAdapter {
270276
if (key != null) {
271277
configureUserInterfaceViewMode((String) configurationMap.get(key));
272278
}
273-
key = getKeyOfType(configurationMap, START_PAGE, Integer.class);
279+
key = getKeyOfType(configurationMap, START_PAGE, Long.class);
274280
if (key != null) {
275-
configureStartPage((Integer) configurationMap.get(key));
281+
configureStartPage(((Long) configurationMap.get(key)).intValue());
276282
}
277283
key = getKeyOfType(configurationMap, SHOW_SEARCH_ACTION, Boolean.class);
278284
if (key != null) {
@@ -330,6 +336,10 @@ class ConfigurationAdapter {
330336
if (key != null) {
331337
configureEnableAnnotationEditing((Boolean) configurationMap.get(key));
332338
}
339+
key = getKeyOfType(configurationMap, ENABLE_FORM_EDITING, Boolean.class);
340+
if (key != null) {
341+
configureEnableFormEditing((Boolean) configurationMap.get(key));
342+
}
333343
key = getKeyOfType(configurationMap, SHOW_SHARE_ACTION, Boolean.class);
334344
if (key != null) {
335345
configureShowShareAction((Boolean) configurationMap.get(key));
@@ -446,6 +456,10 @@ class ConfigurationAdapter {
446456
if (key != null) {
447457
configureAiAssistant((Boolean) configurationMap.get(key));
448458
}
459+
key = getKeyOfType(configurationMap, THEME_CONFIGURATION, Map.class);
460+
if (key != null) {
461+
parseThemeConfiguration((HashMap<String, Object>) configurationMap.get(key));
462+
}
449463
}
450464
}
451465

@@ -731,6 +745,10 @@ private void configureEnableAnnotationEditing(boolean enableAnnotationEditing) {
731745
configuration.annotationEditingEnabled(enableAnnotationEditing);
732746
}
733747

748+
private void configureEnableFormEditing(boolean enableFormEditing) {
749+
configuration.formEditingEnabled(enableFormEditing);
750+
}
751+
734752
private void configureShowShareAction(boolean showShareAction) {
735753
if (showShareAction) {
736754
configuration.setEnabledShareFeatures(EnumSet.allOf(ShareFeatures.class));
@@ -878,6 +896,113 @@ private void configureAiAssistant(Boolean aBoolean) {
878896
configuration.setAiAssistantEnabled(aBoolean);
879897
}
880898

899+
/**
900+
* Parses the theme configuration from the configuration map and extracts color values.
901+
* Creates a flat map with dot-notation keys for easy access.
902+
*
903+
* @param themeConfig The theme configuration map from Flutter
904+
*/
905+
private void parseThemeConfiguration(HashMap<String, Object> themeConfig) {
906+
if (themeConfig == null || themeConfig.isEmpty()) {
907+
return;
908+
}
909+
910+
themeColors = new HashMap<>();
911+
912+
try {
913+
// Parse top-level colors
914+
parseColor(themeConfig, "backgroundColor", "backgroundColor");
915+
parseColor(themeConfig, "separatorColor", "separatorColor");
916+
917+
// Parse toolbar colors
918+
@SuppressWarnings("unchecked")
919+
HashMap<String, Object> toolbar = (HashMap<String, Object>) themeConfig.get("toolbar");
920+
if (toolbar != null) {
921+
parseColor(toolbar, "backgroundColor", "toolbar.backgroundColor");
922+
parseColor(toolbar, "iconColor", "toolbar.iconColor");
923+
parseColor(toolbar, "activeIconColor", "toolbar.activeIconColor");
924+
parseColor(toolbar, "titleColor", "toolbar.titleColor");
925+
parseColor(toolbar, "statusBarColor", "toolbar.statusBarColor");
926+
}
927+
928+
// Parse annotation toolbar colors
929+
@SuppressWarnings("unchecked")
930+
HashMap<String, Object> annotationToolbar = (HashMap<String, Object>) themeConfig.get("annotationToolbar");
931+
if (annotationToolbar != null) {
932+
parseColor(annotationToolbar, "backgroundColor", "annotationToolbar.backgroundColor");
933+
parseColor(annotationToolbar, "iconColor", "annotationToolbar.iconColor");
934+
parseColor(annotationToolbar, "activeIconColor", "annotationToolbar.activeIconColor");
935+
parseColor(annotationToolbar, "activeToolBackgroundColor", "annotationToolbar.activeToolBackgroundColor");
936+
}
937+
938+
// Parse navigation tab colors
939+
@SuppressWarnings("unchecked")
940+
HashMap<String, Object> navigationTab = (HashMap<String, Object>) themeConfig.get("navigationTab");
941+
if (navigationTab != null) {
942+
parseColor(navigationTab, "backgroundColor", "navigationTab.backgroundColor");
943+
parseColor(navigationTab, "iconColor", "navigationTab.iconColor");
944+
parseColor(navigationTab, "selectedIconColor", "navigationTab.selectedIconColor");
945+
}
946+
947+
// Parse search colors
948+
@SuppressWarnings("unchecked")
949+
HashMap<String, Object> search = (HashMap<String, Object>) themeConfig.get("search");
950+
if (search != null) {
951+
parseColor(search, "backgroundColor", "search.backgroundColor");
952+
parseColor(search, "highlightColor", "search.highlightColor");
953+
}
954+
955+
// Parse thumbnail bar colors
956+
@SuppressWarnings("unchecked")
957+
HashMap<String, Object> thumbnailBar = (HashMap<String, Object>) themeConfig.get("thumbnailBar");
958+
if (thumbnailBar != null) {
959+
parseColor(thumbnailBar, "backgroundColor", "thumbnailBar.backgroundColor");
960+
}
961+
962+
// Parse selection colors
963+
@SuppressWarnings("unchecked")
964+
HashMap<String, Object> selection = (HashMap<String, Object>) themeConfig.get("selection");
965+
if (selection != null) {
966+
parseColor(selection, "textHighlightColor", "selection.textHighlightColor");
967+
parseColor(selection, "textHandleColor", "selection.textHandleColor");
968+
parseColor(selection, "annotationBorderColor", "selection.annotationBorderColor");
969+
}
970+
971+
// Parse dialog colors
972+
@SuppressWarnings("unchecked")
973+
HashMap<String, Object> dialog = (HashMap<String, Object>) themeConfig.get("dialog");
974+
if (dialog != null) {
975+
parseColor(dialog, "backgroundColor", "dialog.backgroundColor");
976+
}
977+
978+
Log.d(LOG_TAG, "Parsed theme configuration with " + themeColors.size() + " colors");
979+
} catch (Exception e) {
980+
Log.e(LOG_TAG, "Error parsing theme configuration", e);
981+
themeColors = null;
982+
}
983+
}
984+
985+
/**
986+
* Helper method to parse a color from a map and add it to the themeColors map.
987+
*
988+
* @param map The map containing the color value
989+
* @param key The key to look up in the map
990+
* @param dotNotationKey The dot-notation key to use in the flat themeColors map
991+
*/
992+
private void parseColor(HashMap<String, Object> map, String key, String dotNotationKey) {
993+
Object colorObj = map.get(key);
994+
if (colorObj instanceof String) {
995+
String colorHex = (String) colorObj;
996+
try {
997+
int color = ColorUtil.extractColor(colorHex);
998+
themeColors.put(dotNotationKey, color);
999+
Log.d(LOG_TAG, "Parsed color " + dotNotationKey + ": " + colorHex);
1000+
} catch (Exception e) {
1001+
Log.w(LOG_TAG, "Failed to parse color for " + dotNotationKey + ": " + colorHex, e);
1002+
}
1003+
}
1004+
}
1005+
8811006
private <T> boolean containsKeyOfType(@NonNull HashMap<String, Object> configurationMap,
8821007
@NonNull String key,
8831008
@NonNull Class<T> clazz) {
@@ -1029,6 +1154,16 @@ String getPassword() {
10291154
return password;
10301155
}
10311156

1157+
/**
1158+
* Gets the parsed theme colors as a flat map with dot-notation keys.
1159+
*
1160+
* @return The theme colors map, or null if no theme configuration was provided
1161+
*/
1162+
@Nullable
1163+
public HashMap<String, Integer> getThemeColors() {
1164+
return themeColors;
1165+
}
1166+
10321167
PdfActivityConfiguration build() {
10331168
// Turn on Instant comments;
10341169
if (enableInstantComments) {

0 commit comments

Comments
 (0)