Skip to content

Commit 0920a7c

Browse files
author
PSPDFKit
committed
Release 4.2.1
1 parent 1276506 commit 0920a7c

21 files changed

+1137
-10
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 4.2.1 - 10 Mar 2025
2+
3+
- Adds `enterAnnotationCreationMode` and `exitAnnotationCreationMode` APIs to `PspdfkitWidgetController`.
4+
- Updates base `Annotation` model class to make more base properties mutable.
5+
16
## 4.2.0 - 03 Mar 2025
27

38
- Adds `Annotation` model classes. (J#HYB-614)

android/src/main/java/com/pspdfkit/flutter/pspdfkit/PspdfkitViewImpl.kt

+93
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ import com.pspdfkit.document.processor.PdfProcessor
1515
import com.pspdfkit.document.processor.PdfProcessor.ProcessorProgress
1616
import com.pspdfkit.document.processor.PdfProcessorTask
1717
import com.pspdfkit.flutter.pspdfkit.AnnotationConfigurationAdaptor.Companion.convertAnnotationConfigurations
18+
import com.pspdfkit.flutter.pspdfkit.annotations.AnnotationUtils
1819
import com.pspdfkit.flutter.pspdfkit.annotations.FlutterAnnotationPresetConfiguration
1920
import com.pspdfkit.flutter.pspdfkit.api.AnnotationProcessingMode
21+
import com.pspdfkit.flutter.pspdfkit.api.AnnotationTool
2022
import com.pspdfkit.flutter.pspdfkit.api.AnnotationType
2123
import com.pspdfkit.flutter.pspdfkit.api.NutrientEvent
2224
import com.pspdfkit.flutter.pspdfkit.api.PdfRect
@@ -631,4 +633,95 @@ class PspdfkitViewImpl : PspdfkitWidgetControllerApi {
631633
override fun removeEventListener(event: NutrientEvent) {
632634
eventDispatcher?.removeEventListener(pdfUiFragment!!, event)
633635
}
636+
637+
override fun enterAnnotationCreationMode(
638+
annotationTool: AnnotationTool?,
639+
callback: (Result<Boolean?>) -> Unit
640+
) {
641+
val pdfFragment = pdfUiFragment?.pdfFragment
642+
if (pdfFragment == null) {
643+
callback(
644+
Result.failure(
645+
PspdfkitApiError(
646+
"Error entering annotation creation mode",
647+
"PDF fragment is null"
648+
)
649+
)
650+
)
651+
return
652+
}
653+
654+
try {
655+
// Convert the Flutter AnnotationTool to the corresponding Android AnnotationToolWithVariant
656+
val toolWithVariant = AnnotationUtils.getAndroidAnnotationToolWithVariantFromFlutterTool(annotationTool)
657+
658+
if (toolWithVariant != null) {
659+
// Enter annotation creation mode with the specific tool and variant
660+
val androidTool = toolWithVariant.annotationTool
661+
val variant = toolWithVariant.variant
662+
663+
if (variant != null) {
664+
// If we have both tool and variant, use them together
665+
pdfFragment.enterAnnotationCreationMode(androidTool, variant)
666+
} else {
667+
// If we only have the tool, use it without a variant
668+
pdfFragment.enterAnnotationCreationMode(androidTool)
669+
}
670+
callback(Result.success(true))
671+
} else if (annotationTool != null) {
672+
// If the tool was provided but couldn't be mapped, return an error
673+
callback(
674+
Result.failure(
675+
PspdfkitApiError(
676+
"Invalid annotation tool",
677+
"The annotation tool '$annotationTool' is not supported"
678+
)
679+
)
680+
)
681+
} else {
682+
// If no tool was provided, just enter annotation creation mode with default tool
683+
pdfFragment.enterAnnotationCreationMode()
684+
callback(Result.success(true))
685+
}
686+
} catch (e: Exception) {
687+
callback(
688+
Result.failure(
689+
PspdfkitApiError(
690+
"Error entering annotation creation mode",
691+
e.message ?: "Unknown error"
692+
)
693+
)
694+
)
695+
}
696+
}
697+
698+
override fun exitAnnotationCreationMode(callback: (Result<Boolean?>) -> Unit) {
699+
val pdfFragment = pdfUiFragment?.pdfFragment
700+
if (pdfFragment == null) {
701+
callback(
702+
Result.failure(
703+
PspdfkitApiError(
704+
"Error exiting annotation creation mode",
705+
"PDF fragment is null"
706+
)
707+
)
708+
)
709+
return
710+
}
711+
712+
try {
713+
// Exit annotation creation mode
714+
pdfFragment.exitCurrentlyActiveMode()
715+
callback(Result.success(true))
716+
} catch (e: Exception) {
717+
callback(
718+
Result.failure(
719+
PspdfkitApiError(
720+
"Error exiting annotation creation mode",
721+
e.message ?: "Unknown error"
722+
)
723+
)
724+
)
725+
}
726+
}
634727
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package com.pspdfkit.flutter.pspdfkit.annotations
2+
3+
import com.pspdfkit.ui.special_mode.controller.AnnotationTool
4+
import com.pspdfkit.ui.special_mode.controller.AnnotationToolVariant
5+
import com.pspdfkit.flutter.pspdfkit.api.AnnotationTool as FlutterAnnotationTool
6+
import com.pspdfkit.ui.special_mode.controller.AnnotationTool as AndroidAnnotationTool
7+
8+
/**
9+
* Data class representing an Android annotation tool with its optional variant.
10+
* Some annotation tools are represented by a combination of annotationTool and AnnotationToolVariant on Android.
11+
*/
12+
data class AnnotationToolWithVariant(val annotationTool: AndroidAnnotationTool, val variant: AnnotationToolVariant? = null)
13+
14+
/**
15+
* Utility class for annotation-related operations, including mapping between Flutter and Android annotation tools.
16+
*/
17+
object AnnotationUtils {
18+
19+
/**
20+
* Maps a Flutter AnnotationTool name to the corresponding Android AnnotationToolWithVariant.
21+
*
22+
* @param flutterToolName The name of the Flutter AnnotationTool enum value.
23+
* @return The corresponding Android AnnotationToolWithVariant, or null if no mapping exists.
24+
*/
25+
fun getAndroidAnnotationToolWithVariantFromFlutterName(flutterToolName: String?): AnnotationToolWithVariant? {
26+
if (flutterToolName == null) return null
27+
28+
// Try to find the matching Flutter enum value
29+
val flutterTool = FlutterAnnotationTool.values().find {
30+
it.name.equals(flutterToolName, ignoreCase = true) ||
31+
it.name.replace("_", "").equals(flutterToolName, ignoreCase = true)
32+
}
33+
return mapFlutterToolToAndroidToolWithVariant(flutterTool)
34+
}
35+
36+
/**
37+
* Maps a Flutter AnnotationTool to the corresponding Android AnnotationToolWithVariant.
38+
*
39+
* @param flutterTool The Flutter AnnotationTool enum value.
40+
* @return The corresponding Android AnnotationToolWithVariant, or null if no mapping exists.
41+
*/
42+
fun getAndroidAnnotationToolWithVariantFromFlutterTool(flutterTool: FlutterAnnotationTool?): AnnotationToolWithVariant? {
43+
return mapFlutterToolToAndroidToolWithVariant(flutterTool)
44+
}
45+
46+
/**
47+
* For backward compatibility - returns just the AnnotationTool without variant.
48+
*/
49+
fun getAndroidAnnotationToolFromFlutterName(flutterToolName: String?): AndroidAnnotationTool? {
50+
return getAndroidAnnotationToolWithVariantFromFlutterName(flutterToolName)?.annotationTool
51+
}
52+
53+
/**
54+
* For backward compatibility - returns just the AnnotationTool without variant.
55+
*/
56+
fun getAndroidAnnotationToolFromFlutterTool(flutterTool: FlutterAnnotationTool?): AndroidAnnotationTool? {
57+
return getAndroidAnnotationToolWithVariantFromFlutterTool(flutterTool)?.annotationTool
58+
}
59+
60+
/**
61+
* Maps a Flutter AnnotationTool to the corresponding Android AnnotationToolWithVariant.
62+
*
63+
* @param flutterTool The Flutter AnnotationTool enum value.
64+
* @return The corresponding Android AnnotationToolWithVariant, or null if no mapping exists.
65+
*/
66+
private fun mapFlutterToolToAndroidToolWithVariant(flutterTool: FlutterAnnotationTool?): AnnotationToolWithVariant? {
67+
return when (flutterTool) {
68+
// Ink tools with variants
69+
FlutterAnnotationTool.INK_PEN -> AnnotationToolWithVariant(AndroidAnnotationTool.INK, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.PEN))
70+
FlutterAnnotationTool.INK_MAGIC -> AnnotationToolWithVariant(AndroidAnnotationTool.MAGIC_INK)
71+
FlutterAnnotationTool.INK_HIGHLIGHTER -> AnnotationToolWithVariant(AndroidAnnotationTool.INK, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.HIGHLIGHTER))
72+
73+
// Free text tools with variants
74+
FlutterAnnotationTool.FREE_TEXT -> AnnotationToolWithVariant(AndroidAnnotationTool.FREETEXT)
75+
FlutterAnnotationTool.FREE_TEXT_CALL_OUT -> AnnotationToolWithVariant(AndroidAnnotationTool.FREETEXT_CALLOUT)
76+
77+
// Shape tools
78+
FlutterAnnotationTool.STAMP -> AnnotationToolWithVariant(AndroidAnnotationTool.STAMP)
79+
FlutterAnnotationTool.IMAGE -> AnnotationToolWithVariant(AndroidAnnotationTool.IMAGE)
80+
81+
// Text markup tools
82+
FlutterAnnotationTool.HIGHLIGHT -> AnnotationToolWithVariant(AndroidAnnotationTool.HIGHLIGHT)
83+
FlutterAnnotationTool.UNDERLINE -> AnnotationToolWithVariant(AndroidAnnotationTool.UNDERLINE)
84+
FlutterAnnotationTool.SQUIGGLY -> AnnotationToolWithVariant(AndroidAnnotationTool.SQUIGGLY)
85+
FlutterAnnotationTool.STRIKE_OUT -> AnnotationToolWithVariant(AndroidAnnotationTool.STRIKEOUT)
86+
87+
// Line tools
88+
FlutterAnnotationTool.LINE -> AnnotationToolWithVariant(AndroidAnnotationTool.LINE)
89+
FlutterAnnotationTool.ARROW -> AnnotationToolWithVariant(AndroidAnnotationTool.LINE, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.ARROW))
90+
91+
// Shape tools
92+
FlutterAnnotationTool.SQUARE -> AnnotationToolWithVariant(AndroidAnnotationTool.SQUARE)
93+
FlutterAnnotationTool.CIRCLE -> AnnotationToolWithVariant(AndroidAnnotationTool.CIRCLE)
94+
FlutterAnnotationTool.POLYGON -> AnnotationToolWithVariant(AndroidAnnotationTool.POLYGON)
95+
FlutterAnnotationTool.POLYLINE -> AnnotationToolWithVariant(AndroidAnnotationTool.POLYLINE)
96+
97+
// Other tools
98+
FlutterAnnotationTool.ERASER -> AnnotationToolWithVariant(AndroidAnnotationTool.ERASER)
99+
FlutterAnnotationTool.CLOUDY -> AnnotationToolWithVariant(AndroidAnnotationTool.SQUARE, AnnotationToolVariant.fromPreset(AnnotationToolVariant.Preset.CLOUDY))
100+
FlutterAnnotationTool.NOTE -> AnnotationToolWithVariant(AndroidAnnotationTool.NOTE)
101+
FlutterAnnotationTool.SOUND -> AnnotationToolWithVariant(AndroidAnnotationTool.SOUND)
102+
FlutterAnnotationTool.SIGNATURE -> AnnotationToolWithVariant(AndroidAnnotationTool.SIGNATURE)
103+
FlutterAnnotationTool.REDACTION -> AnnotationToolWithVariant(AndroidAnnotationTool.REDACTION)
104+
105+
// Measurement tools
106+
FlutterAnnotationTool.MEASUREMENT_AREA_RECT -> AnnotationToolWithVariant(AndroidAnnotationTool.MEASUREMENT_AREA_RECT)
107+
FlutterAnnotationTool.MEASUREMENT_AREA_POLYGON -> AnnotationToolWithVariant(AndroidAnnotationTool.MEASUREMENT_AREA_POLYGON)
108+
FlutterAnnotationTool.MEASUREMENT_AREA_ELLIPSE -> AnnotationToolWithVariant(AndroidAnnotationTool.MEASUREMENT_AREA_ELLIPSE)
109+
FlutterAnnotationTool.MEASUREMENT_PERIMETER -> AnnotationToolWithVariant(AndroidAnnotationTool.MEASUREMENT_PERIMETER)
110+
FlutterAnnotationTool.MEASUREMENT_DISTANCE -> AnnotationToolWithVariant(AndroidAnnotationTool.MEASUREMENT_DISTANCE)
111+
112+
// Some Flutter tools don't have direct Android equivalents
113+
FlutterAnnotationTool.CARET,
114+
FlutterAnnotationTool.RICH_MEDIA,
115+
FlutterAnnotationTool.SCREEN,
116+
FlutterAnnotationTool.FILE,
117+
FlutterAnnotationTool.WIDGET,
118+
FlutterAnnotationTool.STAMP_IMAGE,
119+
FlutterAnnotationTool.LINK,
120+
null -> null
121+
}
122+
}
123+
124+
/**
125+
* Maps an Android AnnotationTool to the corresponding Flutter AnnotationTool.
126+
*
127+
* @param androidTool The Android AnnotationTool.
128+
* @return The corresponding Flutter AnnotationTool, or null if no mapping exists.
129+
*/
130+
fun mapAndroidToolToFlutterTool(androidTool: AndroidAnnotationTool?): FlutterAnnotationTool? {
131+
return when (androidTool) {
132+
AndroidAnnotationTool.INK -> FlutterAnnotationTool.INK_PEN
133+
AndroidAnnotationTool.MAGIC_INK -> FlutterAnnotationTool.INK_MAGIC
134+
AndroidAnnotationTool.FREETEXT -> FlutterAnnotationTool.FREE_TEXT
135+
AndroidAnnotationTool.FREETEXT_CALLOUT -> FlutterAnnotationTool.FREE_TEXT_CALL_OUT
136+
AndroidAnnotationTool.STAMP -> FlutterAnnotationTool.STAMP
137+
AndroidAnnotationTool.IMAGE -> FlutterAnnotationTool.IMAGE
138+
AndroidAnnotationTool.HIGHLIGHT -> FlutterAnnotationTool.HIGHLIGHT
139+
AndroidAnnotationTool.UNDERLINE -> FlutterAnnotationTool.UNDERLINE
140+
AndroidAnnotationTool.SQUIGGLY -> FlutterAnnotationTool.SQUIGGLY
141+
AndroidAnnotationTool.STRIKEOUT -> FlutterAnnotationTool.STRIKE_OUT
142+
AndroidAnnotationTool.LINE -> FlutterAnnotationTool.LINE
143+
AndroidAnnotationTool.SQUARE -> FlutterAnnotationTool.SQUARE
144+
AndroidAnnotationTool.CIRCLE -> FlutterAnnotationTool.CIRCLE
145+
AndroidAnnotationTool.POLYGON -> FlutterAnnotationTool.POLYGON
146+
AndroidAnnotationTool.POLYLINE -> FlutterAnnotationTool.POLYLINE
147+
AndroidAnnotationTool.ERASER -> FlutterAnnotationTool.ERASER
148+
AndroidAnnotationTool.NOTE -> FlutterAnnotationTool.NOTE
149+
AndroidAnnotationTool.SOUND -> FlutterAnnotationTool.SOUND
150+
AndroidAnnotationTool.SIGNATURE -> FlutterAnnotationTool.SIGNATURE
151+
AndroidAnnotationTool.REDACTION -> FlutterAnnotationTool.REDACTION
152+
AndroidAnnotationTool.MEASUREMENT_AREA_RECT -> FlutterAnnotationTool.MEASUREMENT_AREA_RECT
153+
AndroidAnnotationTool.MEASUREMENT_AREA_POLYGON -> FlutterAnnotationTool.MEASUREMENT_AREA_POLYGON
154+
AndroidAnnotationTool.MEASUREMENT_AREA_ELLIPSE -> FlutterAnnotationTool.MEASUREMENT_AREA_ELLIPSE
155+
AndroidAnnotationTool.MEASUREMENT_PERIMETER -> FlutterAnnotationTool.MEASUREMENT_PERIMETER
156+
AndroidAnnotationTool.MEASUREMENT_DISTANCE -> FlutterAnnotationTool.MEASUREMENT_DISTANCE
157+
AnnotationTool.NONE,
158+
AnnotationTool.MEASUREMENT_SCALE_CALIBRATION,
159+
AnnotationTool.CAMERA,
160+
AnnotationTool.INSTANT_COMMENT_MARKER,
161+
AnnotationTool.INSTANT_HIGHLIGHT_COMMENT,
162+
AnnotationTool.ANNOTATION_MULTI_SELECTION,
163+
null -> null
164+
}
165+
}
166+
167+
/**
168+
* Maps an Android AnnotationToolWithVariant to the corresponding Flutter AnnotationTool.
169+
*
170+
* @param toolWithVariant The Android AnnotationToolWithVariant.
171+
* @return The corresponding Flutter AnnotationTool, or null if no mapping exists.
172+
*/
173+
fun mapAndroidToolWithVariantToFlutterTool(toolWithVariant: AnnotationToolWithVariant?): FlutterAnnotationTool? {
174+
if (toolWithVariant == null) return null
175+
176+
val tool = toolWithVariant.annotationTool
177+
val variant = toolWithVariant.variant
178+
179+
// Special cases for tools with variants
180+
if (tool == AndroidAnnotationTool.INK && variant != null) {
181+
return when (variant.name) {
182+
AnnotationToolVariant.Preset.PEN.name -> FlutterAnnotationTool.INK_PEN
183+
AnnotationToolVariant.Preset.HIGHLIGHTER.name -> FlutterAnnotationTool.INK_HIGHLIGHTER
184+
else -> FlutterAnnotationTool.INK_PEN // Default to pen if variant not recognized
185+
}
186+
}
187+
188+
if (tool == AndroidAnnotationTool.LINE && variant != null) {
189+
return when {
190+
variant.name == AnnotationToolVariant.Preset.ARROW.name -> FlutterAnnotationTool.ARROW
191+
else -> FlutterAnnotationTool.LINE
192+
}
193+
}
194+
195+
if (tool == AndroidAnnotationTool.SQUARE && variant != null) {
196+
return when {
197+
variant.name == AnnotationToolVariant.Preset.CLOUDY.name -> FlutterAnnotationTool.CLOUDY
198+
else -> FlutterAnnotationTool.SQUARE
199+
}
200+
}
201+
202+
// For all other cases, use the standard mapping
203+
return mapAndroidToolToFlutterTool(tool)
204+
}
205+
}

android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/PspdfkitApi.g.kt

+55
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,23 @@ interface PspdfkitWidgetControllerApi {
16181618
fun getZoomScale(pageIndex: Long, callback: (Result<Double>) -> Unit)
16191619
fun addEventListener(event: NutrientEvent)
16201620
fun removeEventListener(event: NutrientEvent)
1621+
/**
1622+
* Enters annotation creation mode.
1623+
*
1624+
* If [annotationTool] is provided, that specific tool will be activated.
1625+
* If no tool is provided, the default annotation tool will be used.
1626+
*
1627+
* Returns a [Future] that completes with a boolean indicating whether
1628+
* entering annotation creation mode was successful.
1629+
*/
1630+
fun enterAnnotationCreationMode(annotationTool: AnnotationTool?, callback: (Result<Boolean?>) -> Unit)
1631+
/**
1632+
* Exits annotation creation mode.
1633+
*
1634+
* Returns a [Future] that completes with a boolean indicating whether
1635+
* exiting annotation creation mode was successful.
1636+
*/
1637+
fun exitAnnotationCreationMode(callback: (Result<Boolean?>) -> Unit)
16211638

16221639
companion object {
16231640
/** The codec used by PspdfkitWidgetControllerApi. */
@@ -1985,6 +2002,44 @@ interface PspdfkitWidgetControllerApi {
19852002
channel.setMessageHandler(null)
19862003
}
19872004
}
2005+
run {
2006+
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.enterAnnotationCreationMode$separatedMessageChannelSuffix", codec)
2007+
if (api != null) {
2008+
channel.setMessageHandler { message, reply ->
2009+
val args = message as List<Any?>
2010+
val annotationToolArg = args[0] as AnnotationTool?
2011+
api.enterAnnotationCreationMode(annotationToolArg) { result: Result<Boolean?> ->
2012+
val error = result.exceptionOrNull()
2013+
if (error != null) {
2014+
reply.reply(wrapError(error))
2015+
} else {
2016+
val data = result.getOrNull()
2017+
reply.reply(wrapResult(data))
2018+
}
2019+
}
2020+
}
2021+
} else {
2022+
channel.setMessageHandler(null)
2023+
}
2024+
}
2025+
run {
2026+
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.pspdfkit_flutter.PspdfkitWidgetControllerApi.exitAnnotationCreationMode$separatedMessageChannelSuffix", codec)
2027+
if (api != null) {
2028+
channel.setMessageHandler { _, reply ->
2029+
api.exitAnnotationCreationMode{ result: Result<Boolean?> ->
2030+
val error = result.exceptionOrNull()
2031+
if (error != null) {
2032+
reply.reply(wrapError(error))
2033+
} else {
2034+
val data = result.getOrNull()
2035+
reply.reply(wrapResult(data))
2036+
}
2037+
}
2038+
}
2039+
} else {
2040+
channel.setMessageHandler(null)
2041+
}
2042+
}
19882043
}
19892044
}
19902045
}

0 commit comments

Comments
 (0)