@mathers101/react-native-render-rich-text 0.1.9 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/README.md +140 -140
- package/ReactNativeRenderRichText.podspec +23 -23
- package/android/build.gradle +86 -86
- package/android/consumer-rules.pro +3 -3
- package/android/src/main/AndroidManifest.xml +2 -2
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextLayoutManager.kt +24 -24
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextPackage.kt +13 -13
- package/android/src/main/java/com/renderrichtext/MeasurementStore.kt +644 -644
- package/android/src/main/java/com/renderrichtext/accessibility/AccessibilityLabels.kt +17 -17
- package/android/src/main/java/com/renderrichtext/accessibility/AccessibleTiptapTextView.kt +112 -112
- package/android/src/main/java/com/renderrichtext/accessibility/TiptapAccessibilityHelper.kt +576 -576
- package/android/src/main/java/com/renderrichtext/events/CodeBlockPressEvent.kt +24 -24
- package/android/src/main/java/com/renderrichtext/events/ContextMenuItemPressEvent.kt +28 -28
- package/android/src/main/java/com/renderrichtext/events/CopyPressEvent.kt +24 -24
- package/android/src/main/java/com/renderrichtext/events/ImagePressEvent.kt +25 -25
- package/android/src/main/java/com/renderrichtext/events/LatexErrorEvent.kt +29 -29
- package/android/src/main/java/com/renderrichtext/events/LinkLongPressEvent.kt +23 -23
- package/android/src/main/java/com/renderrichtext/events/LinkPressEvent.kt +23 -23
- package/android/src/main/java/com/renderrichtext/events/MentionLongPressEvent.kt +25 -25
- package/android/src/main/java/com/renderrichtext/events/MentionPressEvent.kt +25 -25
- package/android/src/main/java/com/renderrichtext/events/TaskListItemPressEvent.kt +26 -26
- package/android/src/main/java/com/renderrichtext/math/LatexErrorReporter.kt +9 -9
- package/android/src/main/java/com/renderrichtext/parser/Parser.kt +59 -59
- package/android/src/main/java/com/renderrichtext/parser/TextLinkMatching.kt +35 -35
- package/android/src/main/java/com/renderrichtext/renderer/BaselineShiftRenderer.kt +45 -45
- package/android/src/main/java/com/renderrichtext/renderer/BlankLineRenderer.kt +39 -39
- package/android/src/main/java/com/renderrichtext/renderer/BlockquoteRenderer.kt +243 -243
- package/android/src/main/java/com/renderrichtext/renderer/BlockquoteTextRenderer.kt +56 -56
- package/android/src/main/java/com/renderrichtext/renderer/CodeBlockRenderer.kt +135 -135
- package/android/src/main/java/com/renderrichtext/renderer/CodeRenderer.kt +37 -37
- package/android/src/main/java/com/renderrichtext/renderer/EmphasisRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/renderer/HeadingRenderer.kt +81 -81
- package/android/src/main/java/com/renderrichtext/renderer/HighlightRenderer.kt +26 -26
- package/android/src/main/java/com/renderrichtext/renderer/LineBreakRenderer.kt +17 -17
- package/android/src/main/java/com/renderrichtext/renderer/LinkRenderer.kt +90 -90
- package/android/src/main/java/com/renderrichtext/renderer/ListContextManager.kt +109 -109
- package/android/src/main/java/com/renderrichtext/renderer/ListItemRenderer.kt +211 -211
- package/android/src/main/java/com/renderrichtext/renderer/ListRenderer.kt +133 -133
- package/android/src/main/java/com/renderrichtext/renderer/MentionRenderer.kt +85 -85
- package/android/src/main/java/com/renderrichtext/renderer/ParagraphRenderer.kt +91 -91
- package/android/src/main/java/com/renderrichtext/renderer/Renderer.kt +148 -148
- package/android/src/main/java/com/renderrichtext/renderer/SoftBreakRenderer.kt +17 -17
- package/android/src/main/java/com/renderrichtext/renderer/SpanStyleCache.kt +143 -143
- package/android/src/main/java/com/renderrichtext/renderer/StrikethroughRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/renderer/StrongRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/renderer/TextRenderer.kt +31 -31
- package/android/src/main/java/com/renderrichtext/renderer/ThematicBreakRenderer.kt +46 -46
- package/android/src/main/java/com/renderrichtext/renderer/UnderlineRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/spans/BaseListSpan.kt +164 -164
- package/android/src/main/java/com/renderrichtext/spans/BaselineShiftSpan.kt +27 -27
- package/android/src/main/java/com/renderrichtext/spans/BlockquoteSpan.kt +302 -302
- package/android/src/main/java/com/renderrichtext/spans/CodeBackgroundSpan.kt +205 -205
- package/android/src/main/java/com/renderrichtext/spans/CodeBlockSpan.kt +216 -216
- package/android/src/main/java/com/renderrichtext/spans/CodeSpan.kt +32 -32
- package/android/src/main/java/com/renderrichtext/spans/EmphasisSpan.kt +42 -42
- package/android/src/main/java/com/renderrichtext/spans/FadeInSpan.kt +29 -29
- package/android/src/main/java/com/renderrichtext/spans/HeadingSpan.kt +38 -38
- package/android/src/main/java/com/renderrichtext/spans/HighlightSpan.kt +80 -80
- package/android/src/main/java/com/renderrichtext/spans/ImageSpan.kt +481 -481
- package/android/src/main/java/com/renderrichtext/spans/InlineBackgroundGeometry.kt +42 -42
- package/android/src/main/java/com/renderrichtext/spans/LineHeightSpan.kt +39 -39
- package/android/src/main/java/com/renderrichtext/spans/LinkPillIconCache.kt +154 -154
- package/android/src/main/java/com/renderrichtext/spans/LinkPillSpan.kt +381 -381
- package/android/src/main/java/com/renderrichtext/spans/LinkSpan.kt +68 -68
- package/android/src/main/java/com/renderrichtext/spans/ListItemSpacingSpan.kt +33 -33
- package/android/src/main/java/com/renderrichtext/spans/ListMarkerAnchorSpan.kt +38 -38
- package/android/src/main/java/com/renderrichtext/spans/MarginBottomSpan.kt +76 -76
- package/android/src/main/java/com/renderrichtext/spans/MentionChipSpan.kt +132 -132
- package/android/src/main/java/com/renderrichtext/spans/MentionSpan.kt +46 -46
- package/android/src/main/java/com/renderrichtext/spans/OrderedListSpan.kt +127 -127
- package/android/src/main/java/com/renderrichtext/spans/SpoilerSpan.kt +33 -33
- package/android/src/main/java/com/renderrichtext/spans/StrikethroughSpan.kt +12 -12
- package/android/src/main/java/com/renderrichtext/spans/StrongSpan.kt +39 -39
- package/android/src/main/java/com/renderrichtext/spans/TaskListSpan.kt +143 -143
- package/android/src/main/java/com/renderrichtext/spans/TextSpan.kt +26 -26
- package/android/src/main/java/com/renderrichtext/spans/ThematicBreakSpan.kt +69 -69
- package/android/src/main/java/com/renderrichtext/spans/UnorderedListSpan.kt +96 -96
- package/android/src/main/java/com/renderrichtext/spoiler/SpoilerStubs.kt +46 -46
- package/android/src/main/java/com/renderrichtext/styles/BaseBlockStyle.kt +11 -11
- package/android/src/main/java/com/renderrichtext/styles/BlockquoteStyle.kt +83 -83
- package/android/src/main/java/com/renderrichtext/styles/CodeBlockStyle.kt +80 -80
- package/android/src/main/java/com/renderrichtext/styles/CodeStyle.kt +26 -26
- package/android/src/main/java/com/renderrichtext/styles/EmphasisStyle.kt +21 -21
- package/android/src/main/java/com/renderrichtext/styles/FactoidStyle.kt +21 -21
- package/android/src/main/java/com/renderrichtext/styles/HeadingStyle.kt +33 -33
- package/android/src/main/java/com/renderrichtext/styles/HighlightStyle.kt +19 -19
- package/android/src/main/java/com/renderrichtext/styles/ImageStyle.kt +29 -29
- package/android/src/main/java/com/renderrichtext/styles/InlineImageStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/InlineMathStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/LinkPillContent.kt +36 -36
- package/android/src/main/java/com/renderrichtext/styles/LinkPillStyle.kt +44 -44
- package/android/src/main/java/com/renderrichtext/styles/LinkStyle.kt +23 -23
- package/android/src/main/java/com/renderrichtext/styles/LinkVariantEntry.kt +34 -34
- package/android/src/main/java/com/renderrichtext/styles/ListStyle.kt +65 -65
- package/android/src/main/java/com/renderrichtext/styles/MathStyle.kt +29 -29
- package/android/src/main/java/com/renderrichtext/styles/MentionStyle.kt +19 -19
- package/android/src/main/java/com/renderrichtext/styles/ParagraphStyle.kt +33 -33
- package/android/src/main/java/com/renderrichtext/styles/SpoilerStyle.kt +27 -27
- package/android/src/main/java/com/renderrichtext/styles/StrikethroughStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/StrongStyle.kt +21 -21
- package/android/src/main/java/com/renderrichtext/styles/StyleConfig.kt +411 -411
- package/android/src/main/java/com/renderrichtext/styles/StyleParser.kt +92 -92
- package/android/src/main/java/com/renderrichtext/styles/SubscriptStyle.kt +16 -16
- package/android/src/main/java/com/renderrichtext/styles/SuperscriptStyle.kt +16 -16
- package/android/src/main/java/com/renderrichtext/styles/TableStyle.kt +75 -75
- package/android/src/main/java/com/renderrichtext/styles/TaskListStyle.kt +29 -29
- package/android/src/main/java/com/renderrichtext/styles/TextAlignment.kt +32 -32
- package/android/src/main/java/com/renderrichtext/styles/ThematicBreakStyle.kt +23 -23
- package/android/src/main/java/com/renderrichtext/styles/UnderlineStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/VideoStyle.kt +31 -31
- package/android/src/main/java/com/renderrichtext/utils/common/BorderStyleUtils.kt +86 -86
- package/android/src/main/java/com/renderrichtext/utils/common/BreakStrategyUtils.kt +32 -32
- package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockHighlighter.kt +36 -36
- package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockNode.kt +42 -42
- package/android/src/main/java/com/renderrichtext/utils/common/EllipsizeUtils.kt +27 -27
- package/android/src/main/java/com/renderrichtext/utils/common/EnrichedTiptapAncestorUtils.kt +10 -10
- package/android/src/main/java/com/renderrichtext/utils/common/FeatureFlags.kt +9 -9
- package/android/src/main/java/com/renderrichtext/utils/common/LinkRecognitionProps.kt +31 -31
- package/android/src/main/java/com/renderrichtext/utils/common/LinkRegexConfig.kt +56 -56
- package/android/src/main/java/com/renderrichtext/utils/common/MotionPreferences.kt +18 -18
- package/android/src/main/java/com/renderrichtext/utils/common/ReadableMapExtensions.kt +28 -28
- package/android/src/main/java/com/renderrichtext/utils/common/layout/RTLUtils.kt +6 -6
- package/android/src/main/java/com/renderrichtext/utils/common/serialization/TiptapASTSerializer.kt +368 -368
- package/android/src/main/java/com/renderrichtext/utils/text/ImageCache.kt +88 -88
- package/android/src/main/java/com/renderrichtext/utils/text/ImageDownloader.kt +203 -203
- package/android/src/main/java/com/renderrichtext/utils/text/LocalImageLoader.kt +167 -167
- package/android/src/main/java/com/renderrichtext/utils/text/TailFadeInAnimator.kt +84 -84
- package/android/src/main/java/com/renderrichtext/utils/text/conversion/HTMLGenerator.kt +1105 -1105
- package/android/src/main/java/com/renderrichtext/utils/text/conversion/TiptapExtractor.kt +423 -423
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/ParagraphUtils.kt +9 -9
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/SpannableExtensions.kt +9 -9
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/TextPaintExtensions.kt +76 -76
- package/android/src/main/java/com/renderrichtext/utils/text/interaction/CheckboxTouchHelper.kt +61 -61
- package/android/src/main/java/com/renderrichtext/utils/text/interaction/TaskListTapUtils.kt +286 -286
- package/android/src/main/java/com/renderrichtext/utils/text/span/ApplyLineHeight.kt +39 -39
- package/android/src/main/java/com/renderrichtext/utils/text/span/BlockSpacing.kt +142 -142
- package/android/src/main/java/com/renderrichtext/utils/text/span/SpanFlags.kt +43 -43
- package/android/src/main/java/com/renderrichtext/utils/text/span/WidthAwareSpans.kt +30 -30
- package/android/src/main/java/com/renderrichtext/utils/text/view/CodeBlockPressHost.kt +15 -15
- package/android/src/main/java/com/renderrichtext/utils/text/view/ImagePressHost.kt +19 -19
- package/android/src/main/java/com/renderrichtext/utils/text/view/SelectionActionMode.kt +235 -235
- package/android/src/main/java/com/renderrichtext/utils/text/view/TextSelectionColors.kt +48 -48
- package/android/src/main/java/com/renderrichtext/utils/text/view/TextViewSetup.kt +119 -119
- package/android/src/main/java/com/renderrichtext/views/ContextMenuPopup.kt +217 -217
- package/android/src/main/java/com/renderrichtext/views/CopyGlyph.kt +101 -101
- package/android/src/main/java/com/renderrichtext/views/WrapGlyph.kt +40 -40
- package/android/src/main/jni/CMakeLists.txt +52 -52
- package/android/src/main/jni/react/renderer/components/RichTextSpec/ComponentDescriptors.h +30 -30
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextComponentDescriptor.h +29 -29
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.cpp +45 -45
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.h +21 -21
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.cpp +38 -38
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.h +53 -53
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.cpp +9 -9
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.h +24 -24
- package/android/src/main/jni/react/renderer/components/RichTextSpec/conversions.h +40 -40
- package/cpp/parser/TiptapParser.hpp +13 -13
- package/cpp/vendor/nlohmann/json.hpp +24765 -24765
- package/ios/EnrichedTiptapText.h +27 -27
- package/ios/attachments/ENRMImageAttachment.h +51 -51
- package/ios/attachments/ENRMImageAttachment.m +398 -398
- package/ios/attachments/ENRMLinkPillAttachment.h +47 -47
- package/ios/attachments/ENRMLinkPillAttachment.m +324 -324
- package/ios/attachments/ENRMLinkPillIconCache.h +28 -28
- package/ios/attachments/ENRMLinkPillIconCache.m +181 -181
- package/ios/attachments/ENRMLinkPillText.h +27 -27
- package/ios/attachments/ENRMLinkPillText.m +118 -118
- package/ios/attachments/ENRMMathInlineAttachment.h +7 -7
- package/ios/attachments/ENRMMathInlineAttachment.m +4 -4
- package/ios/attachments/ThematicBreakAttachment.h +15 -15
- package/ios/attachments/ThematicBreakAttachment.m +33 -33
- package/ios/internals/ENRMViewFreeMeasurement.h +208 -208
- package/ios/internals/EnrichedTiptapTextComponentDescriptor.h +19 -19
- package/ios/internals/EnrichedTiptapTextShadowNode.h +43 -43
- package/ios/internals/EnrichedTiptapTextShadowNode.mm +69 -69
- package/ios/internals/EnrichedTiptapTextState.h +24 -24
- package/ios/internals/MeasurementCache.h +308 -308
- package/ios/internals/ShadowMeasurementUtils.h +145 -145
- package/ios/parser/ENRMTextLinkAttributes.h +7 -7
- package/ios/parser/ENRMTiptapParser.h +33 -33
- package/ios/parser/ENRMTiptapParser.mm +73 -73
- package/ios/parser/TiptapASTNode.m +52 -52
- package/ios/renderer/AttributedRenderer.h +23 -23
- package/ios/renderer/AttributedRenderer.m +229 -229
- package/ios/renderer/BaseRenderer.h +33 -33
- package/ios/renderer/BaseRenderer.m +46 -46
- package/ios/renderer/BaselineShiftTextAttributes.h +10 -10
- package/ios/renderer/BaselineShiftTextAttributes.m +26 -26
- package/ios/renderer/BlankLineRenderer.h +4 -4
- package/ios/renderer/BlankLineRenderer.m +51 -51
- package/ios/renderer/BlockquoteRenderer.h +6 -6
- package/ios/renderer/BlockquoteRenderer.m +258 -258
- package/ios/renderer/CodeBlockRenderer.h +9 -9
- package/ios/renderer/CodeBlockRenderer.m +99 -99
- package/ios/renderer/CodeRenderer.h +9 -9
- package/ios/renderer/CodeRenderer.m +69 -69
- package/ios/renderer/ENRMBlockquoteTextRenderer.h +25 -25
- package/ios/renderer/ENRMBlockquoteTextRenderer.m +48 -48
- package/ios/renderer/EmphasisRenderer.h +5 -5
- package/ios/renderer/EmphasisRenderer.m +99 -99
- package/ios/renderer/HeadingRenderer.h +6 -6
- package/ios/renderer/HeadingRenderer.m +102 -102
- package/ios/renderer/HighlightRenderer.h +7 -7
- package/ios/renderer/HighlightRenderer.m +33 -33
- package/ios/renderer/LinkRenderer.h +6 -6
- package/ios/renderer/LinkRenderer.m +157 -157
- package/ios/renderer/ListItemRenderer.h +24 -24
- package/ios/renderer/ListItemRenderer.m +283 -283
- package/ios/renderer/ListRenderer.h +13 -13
- package/ios/renderer/ListRenderer.m +126 -126
- package/ios/renderer/MentionRenderer.h +9 -9
- package/ios/renderer/MentionRenderer.m +96 -96
- package/ios/renderer/NodeRenderer.h +8 -8
- package/ios/renderer/ParagraphRenderer.h +6 -6
- package/ios/renderer/ParagraphRenderer.m +85 -85
- package/ios/renderer/RenderContext.h +145 -145
- package/ios/renderer/RenderContext.m +402 -402
- package/ios/renderer/RendererFactory.h +12 -12
- package/ios/renderer/StrikethroughRenderer.h +5 -5
- package/ios/renderer/StrikethroughRenderer.m +30 -30
- package/ios/renderer/StrongRenderer.h +5 -5
- package/ios/renderer/StrongRenderer.m +87 -87
- package/ios/renderer/TextRenderer.h +6 -6
- package/ios/renderer/TextRenderer.m +18 -18
- package/ios/renderer/ThematicBreakRenderer.h +4 -4
- package/ios/renderer/ThematicBreakRenderer.m +41 -41
- package/ios/renderer/UnderlineRenderer.h +4 -4
- package/ios/renderer/UnderlineRenderer.m +41 -41
- package/ios/styles/ENRMFontSlot.h +12 -12
- package/ios/styles/ENRMFontSlot.m +24 -24
- package/ios/styles/StyleConfig.h +488 -488
- package/ios/styles/StyleConfig.mm +2820 -2820
- package/ios/utils/AccessibilityInfo.h +35 -35
- package/ios/utils/AccessibilityInfo.m +24 -24
- package/ios/utils/BlockquoteBorder.h +26 -26
- package/ios/utils/BlockquoteBorder.m +294 -294
- package/ios/utils/CodeBackground.h +19 -19
- package/ios/utils/CodeBackground.m +196 -196
- package/ios/utils/CodeBlockBackground.h +17 -17
- package/ios/utils/CodeBlockBackground.m +102 -102
- package/ios/utils/ContextMenuUtils.h +76 -76
- package/ios/utils/ContextMenuUtils.mm +75 -75
- package/ios/utils/ENRMAccessibilityLabels.h +40 -40
- package/ios/utils/ENRMAccessibilityLabels.m +5 -5
- package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -24
- package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -37
- package/ios/utils/ENRMAtomicSize.h +65 -65
- package/ios/utils/ENRMCodeBlockContent.h +37 -37
- package/ios/utils/ENRMCodeBlockContent.mm +89 -89
- package/ios/utils/ENRMFeatureFlags.h +25 -25
- package/ios/utils/ENRMImageDownloader.h +30 -30
- package/ios/utils/ENRMImageDownloader.m +168 -168
- package/ios/utils/ENRMLatexErrorCoordinator.h +27 -27
- package/ios/utils/ENRMLatexErrorCoordinator.mm +75 -75
- package/ios/utils/ENRMLatexErrorReporting.h +13 -13
- package/ios/utils/ENRMLinkContextMenus.h +93 -93
- package/ios/utils/ENRMLinkContextMenus.m +178 -178
- package/ios/utils/ENRMLinkRegexConfig.h +30 -30
- package/ios/utils/ENRMLinkRegexConfig.mm +104 -104
- package/ios/utils/ENRMLinkRegexProps.h +23 -23
- package/ios/utils/ENRMLocalImageLoader.h +35 -35
- package/ios/utils/ENRMLocalImageLoader.m +111 -111
- package/ios/utils/ENRMMenuAction.h +27 -27
- package/ios/utils/ENRMMenuAction.m +33 -33
- package/ios/utils/ENRMSpoilerOverlayManager.h +15 -15
- package/ios/utils/ENRMSpoilerOverlayManager.m +19 -19
- package/ios/utils/ENRMSpoilerTapUtils.h +6 -6
- package/ios/utils/ENRMSpoilerTapUtils.m +11 -11
- package/ios/utils/ENRMTailFadeInAnimator.h +16 -16
- package/ios/utils/ENRMTailFadeInAnimator.m +161 -161
- package/ios/utils/ENRMTextHitTest.h +23 -23
- package/ios/utils/ENRMTextHitTest.m +20 -20
- package/ios/utils/ENRMTextInteractionUtils.h +20 -20
- package/ios/utils/ENRMTextInteractionUtils.m +15 -15
- package/ios/utils/ENRMTextRenderer.h +38 -38
- package/ios/utils/ENRMTextRenderer.m +54 -54
- package/ios/utils/ENRMTextViewSetup.h +132 -132
- package/ios/utils/ENRMUIKit.h +429 -429
- package/ios/utils/EditMenuUtils.h +105 -105
- package/ios/utils/EditMenuUtils.m +143 -143
- package/ios/utils/FontScaleObserver.h +10 -10
- package/ios/utils/FontScaleObserver.m +55 -55
- package/ios/utils/FontUtils.h +31 -31
- package/ios/utils/FontUtils.m +63 -63
- package/ios/utils/HTMLGenerator.h +25 -25
- package/ios/utils/HTMLGenerator.m +1041 -1041
- package/ios/utils/HeightUpdateUtils.h +25 -25
- package/ios/utils/ImageRequestHeaderUtils.h +35 -35
- package/ios/utils/LastElementUtils.h +97 -97
- package/ios/utils/LinkContextMenuUtils.h +55 -55
- package/ios/utils/LinkPillContentUtils.h +46 -46
- package/ios/utils/ListMarkerDrawer.h +15 -15
- package/ios/utils/ListMarkerDrawer.m +239 -239
- package/ios/utils/MentionBackground.h +26 -26
- package/ios/utils/MentionBackground.m +86 -86
- package/ios/utils/ParagraphStyleUtils.h +87 -87
- package/ios/utils/ParagraphStyleUtils.m +484 -484
- package/ios/utils/PasteboardUtils.h +48 -48
- package/ios/utils/PasteboardUtils.m +166 -166
- package/ios/utils/RTFExportUtils.h +24 -24
- package/ios/utils/RTFExportUtils.m +299 -299
- package/ios/utils/SelectionColorUtils.h +14 -14
- package/ios/utils/StylePropsUtils.h +1340 -1340
- package/ios/utils/TaskListTapUtils.h +6 -6
- package/ios/utils/TaskListTapUtils.m +14 -14
- package/ios/utils/TextViewLayoutManager.h +14 -14
- package/ios/utils/TiptapAccessibilityElementBuilder.h +43 -43
- package/ios/utils/TiptapAccessibilityElementBuilder.m +432 -432
- package/ios/utils/TiptapExtractor.h +17 -17
- package/ios/utils/TiptapExtractor.m +367 -367
- package/ios/views/ENRMTiptapTextView.h +25 -25
- package/ios/views/ENRMTiptapTextView.m +247 -247
- package/package.json +65 -70
- package/react-native.config.js +10 -10
- package/src/admonitionDefaults.ts +58 -58
- package/src/darkModeTextStyle.ts +99 -99
- package/src/headingDefaults.ts +21 -21
- package/src/index.tsx +4 -4
- package/src/linkVariantUtils.ts +120 -120
- package/src/normalizeTiptapStyle.ts +397 -397
- package/src/rn-globals.d.ts +1 -1
- package/src/styleUtils.ts +107 -107
- package/src/types/TiptapStyle.ts +532 -532
- package/src/types/TiptapStyleInternal.ts +299 -299
- package/src/types/linkPill.ts +9 -9
- package/src/utils/isDev.ts +4 -4
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
package com.renderrichtext.utils.text
|
|
2
|
-
|
|
3
|
-
import android.graphics.Bitmap
|
|
4
|
-
import android.util.LruCache
|
|
5
|
-
import java.security.MessageDigest
|
|
6
|
-
|
|
7
|
-
object ImageCache {
|
|
8
|
-
private const val ORIGINAL_CACHE_SIZE = 20 * 1024 * 1024
|
|
9
|
-
private const val PROCESSED_CACHE_SIZE = 30 * 1024 * 1024
|
|
10
|
-
|
|
11
|
-
private val originalCache = bitmapLruCache(ORIGINAL_CACHE_SIZE)
|
|
12
|
-
private val processedCache = bitmapLruCache(PROCESSED_CACHE_SIZE)
|
|
13
|
-
|
|
14
|
-
/** Header names lower-cased; sorted first so case aliases collapse deterministically. */
|
|
15
|
-
fun normalizedHeaders(headers: Map<String, String>): Map<String, String> =
|
|
16
|
-
headers.entries
|
|
17
|
-
.sortedBy { it.key }
|
|
18
|
-
.associate { it.key.lowercase() to it.value }
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Cache identity for a remote image request. Returns the URL itself when no
|
|
22
|
-
* headers are set; otherwise appends a SHA-256 digest of the sorted header
|
|
23
|
-
* pairs, so the same URL fetched with different headers is cached and
|
|
24
|
-
* deduplicated separately without embedding header values in the key.
|
|
25
|
-
* Header names are compared case-insensitively.
|
|
26
|
-
*/
|
|
27
|
-
fun requestKey(
|
|
28
|
-
url: String,
|
|
29
|
-
headers: Map<String, String>,
|
|
30
|
-
): String {
|
|
31
|
-
if (headers.isEmpty()) return url
|
|
32
|
-
val joined =
|
|
33
|
-
normalizedHeaders(headers)
|
|
34
|
-
.entries
|
|
35
|
-
.sortedBy { it.key }
|
|
36
|
-
.joinToString(separator = "\n") { "${it.key}:${it.value}" }
|
|
37
|
-
val digest = MessageDigest.getInstance("SHA-256").digest(joined.toByteArray())
|
|
38
|
-
return url + "|" + digest.joinToString(separator = "") { "%02x".format(it) }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
fun getOriginal(url: String): Bitmap? = originalCache.get(url)
|
|
42
|
-
|
|
43
|
-
fun putOriginal(
|
|
44
|
-
url: String,
|
|
45
|
-
bitmap: Bitmap,
|
|
46
|
-
) {
|
|
47
|
-
originalCache.put(url, bitmap)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
fun getProcessed(
|
|
51
|
-
url: String,
|
|
52
|
-
width: Int,
|
|
53
|
-
height: Int,
|
|
54
|
-
borderRadius: Int,
|
|
55
|
-
resizeMode: String,
|
|
56
|
-
): Bitmap? = processedCache.get(processedKey(url, width, height, borderRadius, resizeMode))
|
|
57
|
-
|
|
58
|
-
fun putProcessed(
|
|
59
|
-
url: String,
|
|
60
|
-
width: Int,
|
|
61
|
-
height: Int,
|
|
62
|
-
borderRadius: Int,
|
|
63
|
-
resizeMode: String,
|
|
64
|
-
bitmap: Bitmap,
|
|
65
|
-
) {
|
|
66
|
-
processedCache.put(processedKey(url, width, height, borderRadius, resizeMode), bitmap)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private fun processedKey(
|
|
70
|
-
url: String,
|
|
71
|
-
width: Int,
|
|
72
|
-
height: Int,
|
|
73
|
-
borderRadius: Int,
|
|
74
|
-
resizeMode: String,
|
|
75
|
-
): String = "${url}_w${width}_h${height}_r${borderRadius}_m$resizeMode"
|
|
76
|
-
|
|
77
|
-
// A minimum per-entry cost bounds entry count as well as decoded bytes.
|
|
78
|
-
internal fun bitmapLruCache(
|
|
79
|
-
maxSize: Int,
|
|
80
|
-
maxEntries: Int = Int.MAX_VALUE,
|
|
81
|
-
): LruCache<String, Bitmap> =
|
|
82
|
-
object : LruCache<String, Bitmap>(maxSize) {
|
|
83
|
-
override fun sizeOf(
|
|
84
|
-
key: String,
|
|
85
|
-
value: Bitmap,
|
|
86
|
-
): Int = value.allocationByteCount.coerceAtLeast(((maxSize.toLong() + maxEntries - 1) / maxEntries).toInt())
|
|
87
|
-
}
|
|
88
|
-
}
|
|
1
|
+
package com.renderrichtext.utils.text
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap
|
|
4
|
+
import android.util.LruCache
|
|
5
|
+
import java.security.MessageDigest
|
|
6
|
+
|
|
7
|
+
object ImageCache {
|
|
8
|
+
private const val ORIGINAL_CACHE_SIZE = 20 * 1024 * 1024
|
|
9
|
+
private const val PROCESSED_CACHE_SIZE = 30 * 1024 * 1024
|
|
10
|
+
|
|
11
|
+
private val originalCache = bitmapLruCache(ORIGINAL_CACHE_SIZE)
|
|
12
|
+
private val processedCache = bitmapLruCache(PROCESSED_CACHE_SIZE)
|
|
13
|
+
|
|
14
|
+
/** Header names lower-cased; sorted first so case aliases collapse deterministically. */
|
|
15
|
+
fun normalizedHeaders(headers: Map<String, String>): Map<String, String> =
|
|
16
|
+
headers.entries
|
|
17
|
+
.sortedBy { it.key }
|
|
18
|
+
.associate { it.key.lowercase() to it.value }
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Cache identity for a remote image request. Returns the URL itself when no
|
|
22
|
+
* headers are set; otherwise appends a SHA-256 digest of the sorted header
|
|
23
|
+
* pairs, so the same URL fetched with different headers is cached and
|
|
24
|
+
* deduplicated separately without embedding header values in the key.
|
|
25
|
+
* Header names are compared case-insensitively.
|
|
26
|
+
*/
|
|
27
|
+
fun requestKey(
|
|
28
|
+
url: String,
|
|
29
|
+
headers: Map<String, String>,
|
|
30
|
+
): String {
|
|
31
|
+
if (headers.isEmpty()) return url
|
|
32
|
+
val joined =
|
|
33
|
+
normalizedHeaders(headers)
|
|
34
|
+
.entries
|
|
35
|
+
.sortedBy { it.key }
|
|
36
|
+
.joinToString(separator = "\n") { "${it.key}:${it.value}" }
|
|
37
|
+
val digest = MessageDigest.getInstance("SHA-256").digest(joined.toByteArray())
|
|
38
|
+
return url + "|" + digest.joinToString(separator = "") { "%02x".format(it) }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fun getOriginal(url: String): Bitmap? = originalCache.get(url)
|
|
42
|
+
|
|
43
|
+
fun putOriginal(
|
|
44
|
+
url: String,
|
|
45
|
+
bitmap: Bitmap,
|
|
46
|
+
) {
|
|
47
|
+
originalCache.put(url, bitmap)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fun getProcessed(
|
|
51
|
+
url: String,
|
|
52
|
+
width: Int,
|
|
53
|
+
height: Int,
|
|
54
|
+
borderRadius: Int,
|
|
55
|
+
resizeMode: String,
|
|
56
|
+
): Bitmap? = processedCache.get(processedKey(url, width, height, borderRadius, resizeMode))
|
|
57
|
+
|
|
58
|
+
fun putProcessed(
|
|
59
|
+
url: String,
|
|
60
|
+
width: Int,
|
|
61
|
+
height: Int,
|
|
62
|
+
borderRadius: Int,
|
|
63
|
+
resizeMode: String,
|
|
64
|
+
bitmap: Bitmap,
|
|
65
|
+
) {
|
|
66
|
+
processedCache.put(processedKey(url, width, height, borderRadius, resizeMode), bitmap)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private fun processedKey(
|
|
70
|
+
url: String,
|
|
71
|
+
width: Int,
|
|
72
|
+
height: Int,
|
|
73
|
+
borderRadius: Int,
|
|
74
|
+
resizeMode: String,
|
|
75
|
+
): String = "${url}_w${width}_h${height}_r${borderRadius}_m$resizeMode"
|
|
76
|
+
|
|
77
|
+
// A minimum per-entry cost bounds entry count as well as decoded bytes.
|
|
78
|
+
internal fun bitmapLruCache(
|
|
79
|
+
maxSize: Int,
|
|
80
|
+
maxEntries: Int = Int.MAX_VALUE,
|
|
81
|
+
): LruCache<String, Bitmap> =
|
|
82
|
+
object : LruCache<String, Bitmap>(maxSize) {
|
|
83
|
+
override fun sizeOf(
|
|
84
|
+
key: String,
|
|
85
|
+
value: Bitmap,
|
|
86
|
+
): Int = value.allocationByteCount.coerceAtLeast(((maxSize.toLong() + maxEntries - 1) / maxEntries).toInt())
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -1,203 +1,203 @@
|
|
|
1
|
-
package com.renderrichtext.utils.text
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import android.graphics.Bitmap
|
|
5
|
-
import android.graphics.BitmapFactory
|
|
6
|
-
import android.os.Handler
|
|
7
|
-
import android.os.Looper
|
|
8
|
-
import android.util.Log
|
|
9
|
-
import okhttp3.Cache
|
|
10
|
-
import okhttp3.Call
|
|
11
|
-
import okhttp3.Callback
|
|
12
|
-
import okhttp3.OkHttpClient
|
|
13
|
-
import okhttp3.Request
|
|
14
|
-
import okhttp3.Response
|
|
15
|
-
import java.io.File
|
|
16
|
-
import java.io.IOException
|
|
17
|
-
import java.util.concurrent.TimeUnit
|
|
18
|
-
|
|
19
|
-
object ImageDownloader {
|
|
20
|
-
private const val TAG = "ImageDownloader"
|
|
21
|
-
private const val DISK_CACHE_SIZE = 100L * 1024 * 1024
|
|
22
|
-
private const val TIMEOUT = 15L
|
|
23
|
-
|
|
24
|
-
private val mainHandler = Handler(Looper.getMainLooper())
|
|
25
|
-
|
|
26
|
-
@Volatile
|
|
27
|
-
private var client: OkHttpClient? = null
|
|
28
|
-
|
|
29
|
-
// No disk cache: it keys by URL alone and would mix header sets.
|
|
30
|
-
@Volatile
|
|
31
|
-
private var headerClient: OkHttpClient? = null
|
|
32
|
-
private var maxTargetWidth: Int = 0
|
|
33
|
-
|
|
34
|
-
private val inFlight = HashMap<String, MutableList<(Bitmap?) -> Unit>>()
|
|
35
|
-
|
|
36
|
-
private fun getClient(context: Context): OkHttpClient =
|
|
37
|
-
client ?: synchronized(this) {
|
|
38
|
-
client ?: buildClient(context).also {
|
|
39
|
-
client = it
|
|
40
|
-
maxTargetWidth = context.applicationContext.resources.displayMetrics.widthPixels
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
private fun getHeaderClient(context: Context): OkHttpClient =
|
|
45
|
-
headerClient ?: synchronized(this) {
|
|
46
|
-
headerClient ?: getClient(context)
|
|
47
|
-
.newBuilder()
|
|
48
|
-
.cache(null)
|
|
49
|
-
.build()
|
|
50
|
-
.also { headerClient = it }
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private fun buildClient(context: Context): OkHttpClient {
|
|
54
|
-
val cacheDir = File(context.applicationContext.cacheDir, "enrm_image_cache")
|
|
55
|
-
return OkHttpClient
|
|
56
|
-
.Builder()
|
|
57
|
-
.cache(Cache(cacheDir, DISK_CACHE_SIZE))
|
|
58
|
-
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
|
|
59
|
-
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
|
|
60
|
-
.build()
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
fun download(
|
|
64
|
-
context: Context,
|
|
65
|
-
url: String,
|
|
66
|
-
headers: Map<String, String> = emptyMap(),
|
|
67
|
-
callback: (Bitmap?) -> Unit,
|
|
68
|
-
) {
|
|
69
|
-
val headers = ImageCache.normalizedHeaders(headers)
|
|
70
|
-
val requestKey = ImageCache.requestKey(url, headers)
|
|
71
|
-
|
|
72
|
-
ImageCache.getOriginal(requestKey)?.let {
|
|
73
|
-
callback(it)
|
|
74
|
-
return
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
synchronized(inFlight) {
|
|
78
|
-
val existing = inFlight[requestKey]
|
|
79
|
-
if (existing != null) {
|
|
80
|
-
existing.add(callback)
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
inFlight[requestKey] = mutableListOf(callback)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// OkHttp throws on a URL or header it cannot use; report that like any failed download.
|
|
87
|
-
val request =
|
|
88
|
-
try {
|
|
89
|
-
Request
|
|
90
|
-
.Builder()
|
|
91
|
-
.url(url)
|
|
92
|
-
.apply { headers.forEach { (name, value) -> addHeader(name, value) } }
|
|
93
|
-
.build()
|
|
94
|
-
} catch (e: IllegalArgumentException) {
|
|
95
|
-
Log.e(TAG, "Invalid image request: $url", e)
|
|
96
|
-
dispatchCallbacks(requestKey, null)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
val client = if (headers.isEmpty()) getClient(context) else getHeaderClient(context)
|
|
100
|
-
client.newCall(request).enqueue(
|
|
101
|
-
object : Callback {
|
|
102
|
-
override fun onResponse(
|
|
103
|
-
call: Call,
|
|
104
|
-
response: Response,
|
|
105
|
-
) {
|
|
106
|
-
val bitmap =
|
|
107
|
-
response.use {
|
|
108
|
-
try {
|
|
109
|
-
val bytes = it.body?.bytes() ?: return@use null
|
|
110
|
-
decodeDownsampled(bytes, maxTargetWidth)
|
|
111
|
-
} catch (_: OutOfMemoryError) {
|
|
112
|
-
Log.e(TAG, "OOM decoding image: $url")
|
|
113
|
-
null
|
|
114
|
-
} catch (e: Exception) {
|
|
115
|
-
Log.e(TAG, "Failed to decode image: $url", e)
|
|
116
|
-
null
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
bitmap?.let { ImageCache.putOriginal(requestKey, it) }
|
|
121
|
-
dispatchCallbacks(requestKey, bitmap)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
override fun onFailure(
|
|
125
|
-
call: Call,
|
|
126
|
-
e: IOException,
|
|
127
|
-
) {
|
|
128
|
-
Log.e(TAG, "Failed to download image: $url", e)
|
|
129
|
-
dispatchCallbacks(requestKey, null)
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private fun decodeDownsampled(
|
|
136
|
-
bytes: ByteArray,
|
|
137
|
-
targetWidth: Int,
|
|
138
|
-
maxDimension: Int? = null,
|
|
139
|
-
): Bitmap? {
|
|
140
|
-
val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
|
141
|
-
BitmapFactory.decodeByteArray(bytes, 0, bytes.size, opts)
|
|
142
|
-
return decodeWithSampleSize(opts, targetWidth, maxDimension) {
|
|
143
|
-
BitmapFactory.decodeByteArray(bytes, 0, bytes.size, it)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
fun decodeBytesDownsampled(
|
|
148
|
-
context: Context,
|
|
149
|
-
bytes: ByteArray,
|
|
150
|
-
maxDimension: Int? = null,
|
|
151
|
-
): Bitmap? = decodeDownsampled(bytes, context.resources.displayMetrics.widthPixels, maxDimension)
|
|
152
|
-
|
|
153
|
-
fun decodeFileDownsampled(
|
|
154
|
-
context: Context,
|
|
155
|
-
path: String,
|
|
156
|
-
maxDimension: Int? = null,
|
|
157
|
-
): Bitmap? {
|
|
158
|
-
val targetWidth = context.resources.displayMetrics.widthPixels
|
|
159
|
-
val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
|
160
|
-
BitmapFactory.decodeFile(path, opts)
|
|
161
|
-
return decodeWithSampleSize(opts, targetWidth, maxDimension) {
|
|
162
|
-
BitmapFactory.decodeFile(path, it)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private inline fun decodeWithSampleSize(
|
|
167
|
-
opts: BitmapFactory.Options,
|
|
168
|
-
targetWidth: Int,
|
|
169
|
-
maxDimension: Int?,
|
|
170
|
-
decode: (BitmapFactory.Options) -> Bitmap?,
|
|
171
|
-
): Bitmap? {
|
|
172
|
-
if (opts.outWidth <= 0 || opts.outHeight <= 0) return null
|
|
173
|
-
opts.inSampleSize =
|
|
174
|
-
if (maxDimension == null) {
|
|
175
|
-
calculateInSampleSize(opts.outWidth, targetWidth)
|
|
176
|
-
} else {
|
|
177
|
-
var sample = 1
|
|
178
|
-
val limit = maxDimension.coerceAtLeast(1).toLong()
|
|
179
|
-
while (maxOf(opts.outWidth, opts.outHeight).toLong() > limit * sample) sample *= 2
|
|
180
|
-
sample
|
|
181
|
-
}
|
|
182
|
-
opts.inJustDecodeBounds = false
|
|
183
|
-
return decode(opts)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
private fun calculateInSampleSize(
|
|
187
|
-
srcWidth: Int,
|
|
188
|
-
reqWidth: Int,
|
|
189
|
-
): Int {
|
|
190
|
-
if (srcWidth in 0..reqWidth) return 1
|
|
191
|
-
return Integer.highestOneBit(srcWidth / reqWidth)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
private fun dispatchCallbacks(
|
|
195
|
-
requestKey: String,
|
|
196
|
-
bitmap: Bitmap?,
|
|
197
|
-
) {
|
|
198
|
-
val callbacks = synchronized(inFlight) { inFlight.remove(requestKey) } ?: return
|
|
199
|
-
mainHandler.post {
|
|
200
|
-
callbacks.forEach { it(bitmap) }
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
1
|
+
package com.renderrichtext.utils.text
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Bitmap
|
|
5
|
+
import android.graphics.BitmapFactory
|
|
6
|
+
import android.os.Handler
|
|
7
|
+
import android.os.Looper
|
|
8
|
+
import android.util.Log
|
|
9
|
+
import okhttp3.Cache
|
|
10
|
+
import okhttp3.Call
|
|
11
|
+
import okhttp3.Callback
|
|
12
|
+
import okhttp3.OkHttpClient
|
|
13
|
+
import okhttp3.Request
|
|
14
|
+
import okhttp3.Response
|
|
15
|
+
import java.io.File
|
|
16
|
+
import java.io.IOException
|
|
17
|
+
import java.util.concurrent.TimeUnit
|
|
18
|
+
|
|
19
|
+
object ImageDownloader {
|
|
20
|
+
private const val TAG = "ImageDownloader"
|
|
21
|
+
private const val DISK_CACHE_SIZE = 100L * 1024 * 1024
|
|
22
|
+
private const val TIMEOUT = 15L
|
|
23
|
+
|
|
24
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
25
|
+
|
|
26
|
+
@Volatile
|
|
27
|
+
private var client: OkHttpClient? = null
|
|
28
|
+
|
|
29
|
+
// No disk cache: it keys by URL alone and would mix header sets.
|
|
30
|
+
@Volatile
|
|
31
|
+
private var headerClient: OkHttpClient? = null
|
|
32
|
+
private var maxTargetWidth: Int = 0
|
|
33
|
+
|
|
34
|
+
private val inFlight = HashMap<String, MutableList<(Bitmap?) -> Unit>>()
|
|
35
|
+
|
|
36
|
+
private fun getClient(context: Context): OkHttpClient =
|
|
37
|
+
client ?: synchronized(this) {
|
|
38
|
+
client ?: buildClient(context).also {
|
|
39
|
+
client = it
|
|
40
|
+
maxTargetWidth = context.applicationContext.resources.displayMetrics.widthPixels
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private fun getHeaderClient(context: Context): OkHttpClient =
|
|
45
|
+
headerClient ?: synchronized(this) {
|
|
46
|
+
headerClient ?: getClient(context)
|
|
47
|
+
.newBuilder()
|
|
48
|
+
.cache(null)
|
|
49
|
+
.build()
|
|
50
|
+
.also { headerClient = it }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private fun buildClient(context: Context): OkHttpClient {
|
|
54
|
+
val cacheDir = File(context.applicationContext.cacheDir, "enrm_image_cache")
|
|
55
|
+
return OkHttpClient
|
|
56
|
+
.Builder()
|
|
57
|
+
.cache(Cache(cacheDir, DISK_CACHE_SIZE))
|
|
58
|
+
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
|
|
59
|
+
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
|
|
60
|
+
.build()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fun download(
|
|
64
|
+
context: Context,
|
|
65
|
+
url: String,
|
|
66
|
+
headers: Map<String, String> = emptyMap(),
|
|
67
|
+
callback: (Bitmap?) -> Unit,
|
|
68
|
+
) {
|
|
69
|
+
val headers = ImageCache.normalizedHeaders(headers)
|
|
70
|
+
val requestKey = ImageCache.requestKey(url, headers)
|
|
71
|
+
|
|
72
|
+
ImageCache.getOriginal(requestKey)?.let {
|
|
73
|
+
callback(it)
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
synchronized(inFlight) {
|
|
78
|
+
val existing = inFlight[requestKey]
|
|
79
|
+
if (existing != null) {
|
|
80
|
+
existing.add(callback)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
inFlight[requestKey] = mutableListOf(callback)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// OkHttp throws on a URL or header it cannot use; report that like any failed download.
|
|
87
|
+
val request =
|
|
88
|
+
try {
|
|
89
|
+
Request
|
|
90
|
+
.Builder()
|
|
91
|
+
.url(url)
|
|
92
|
+
.apply { headers.forEach { (name, value) -> addHeader(name, value) } }
|
|
93
|
+
.build()
|
|
94
|
+
} catch (e: IllegalArgumentException) {
|
|
95
|
+
Log.e(TAG, "Invalid image request: $url", e)
|
|
96
|
+
dispatchCallbacks(requestKey, null)
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
val client = if (headers.isEmpty()) getClient(context) else getHeaderClient(context)
|
|
100
|
+
client.newCall(request).enqueue(
|
|
101
|
+
object : Callback {
|
|
102
|
+
override fun onResponse(
|
|
103
|
+
call: Call,
|
|
104
|
+
response: Response,
|
|
105
|
+
) {
|
|
106
|
+
val bitmap =
|
|
107
|
+
response.use {
|
|
108
|
+
try {
|
|
109
|
+
val bytes = it.body?.bytes() ?: return@use null
|
|
110
|
+
decodeDownsampled(bytes, maxTargetWidth)
|
|
111
|
+
} catch (_: OutOfMemoryError) {
|
|
112
|
+
Log.e(TAG, "OOM decoding image: $url")
|
|
113
|
+
null
|
|
114
|
+
} catch (e: Exception) {
|
|
115
|
+
Log.e(TAG, "Failed to decode image: $url", e)
|
|
116
|
+
null
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
bitmap?.let { ImageCache.putOriginal(requestKey, it) }
|
|
121
|
+
dispatchCallbacks(requestKey, bitmap)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override fun onFailure(
|
|
125
|
+
call: Call,
|
|
126
|
+
e: IOException,
|
|
127
|
+
) {
|
|
128
|
+
Log.e(TAG, "Failed to download image: $url", e)
|
|
129
|
+
dispatchCallbacks(requestKey, null)
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private fun decodeDownsampled(
|
|
136
|
+
bytes: ByteArray,
|
|
137
|
+
targetWidth: Int,
|
|
138
|
+
maxDimension: Int? = null,
|
|
139
|
+
): Bitmap? {
|
|
140
|
+
val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
|
141
|
+
BitmapFactory.decodeByteArray(bytes, 0, bytes.size, opts)
|
|
142
|
+
return decodeWithSampleSize(opts, targetWidth, maxDimension) {
|
|
143
|
+
BitmapFactory.decodeByteArray(bytes, 0, bytes.size, it)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
fun decodeBytesDownsampled(
|
|
148
|
+
context: Context,
|
|
149
|
+
bytes: ByteArray,
|
|
150
|
+
maxDimension: Int? = null,
|
|
151
|
+
): Bitmap? = decodeDownsampled(bytes, context.resources.displayMetrics.widthPixels, maxDimension)
|
|
152
|
+
|
|
153
|
+
fun decodeFileDownsampled(
|
|
154
|
+
context: Context,
|
|
155
|
+
path: String,
|
|
156
|
+
maxDimension: Int? = null,
|
|
157
|
+
): Bitmap? {
|
|
158
|
+
val targetWidth = context.resources.displayMetrics.widthPixels
|
|
159
|
+
val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
|
160
|
+
BitmapFactory.decodeFile(path, opts)
|
|
161
|
+
return decodeWithSampleSize(opts, targetWidth, maxDimension) {
|
|
162
|
+
BitmapFactory.decodeFile(path, it)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private inline fun decodeWithSampleSize(
|
|
167
|
+
opts: BitmapFactory.Options,
|
|
168
|
+
targetWidth: Int,
|
|
169
|
+
maxDimension: Int?,
|
|
170
|
+
decode: (BitmapFactory.Options) -> Bitmap?,
|
|
171
|
+
): Bitmap? {
|
|
172
|
+
if (opts.outWidth <= 0 || opts.outHeight <= 0) return null
|
|
173
|
+
opts.inSampleSize =
|
|
174
|
+
if (maxDimension == null) {
|
|
175
|
+
calculateInSampleSize(opts.outWidth, targetWidth)
|
|
176
|
+
} else {
|
|
177
|
+
var sample = 1
|
|
178
|
+
val limit = maxDimension.coerceAtLeast(1).toLong()
|
|
179
|
+
while (maxOf(opts.outWidth, opts.outHeight).toLong() > limit * sample) sample *= 2
|
|
180
|
+
sample
|
|
181
|
+
}
|
|
182
|
+
opts.inJustDecodeBounds = false
|
|
183
|
+
return decode(opts)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private fun calculateInSampleSize(
|
|
187
|
+
srcWidth: Int,
|
|
188
|
+
reqWidth: Int,
|
|
189
|
+
): Int {
|
|
190
|
+
if (srcWidth in 0..reqWidth) return 1
|
|
191
|
+
return Integer.highestOneBit(srcWidth / reqWidth)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private fun dispatchCallbacks(
|
|
195
|
+
requestKey: String,
|
|
196
|
+
bitmap: Bitmap?,
|
|
197
|
+
) {
|
|
198
|
+
val callbacks = synchronized(inFlight) { inFlight.remove(requestKey) } ?: return
|
|
199
|
+
mainHandler.post {
|
|
200
|
+
callbacks.forEach { it(bitmap) }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|