Skip to content

Commit

Permalink
Fix image loading is not loding image on init in editor
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-divyesh-v committed Jan 1, 2025
1 parent d8f6c60 commit afb6e30
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 11 deletions.
10 changes: 6 additions & 4 deletions RichEditorDemo/RichEditorDemo/RichEditorDemo.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
7 changes: 6 additions & 1 deletion Sources/RichEditorSwiftUI/Actions/RichTextAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ public enum RichTextAction: Identifiable, Equatable {

/// Set link
case setLink(String? = nil)

/// Update Image Attachment as image takes time to download
case updateImageAttachments([ImageAttachment])

}

extension RichTextAction {
Expand Down Expand Up @@ -114,6 +118,7 @@ extension RichTextAction {
case .undoLatestChange: .richTextUndo
case .setHeaderStyle: .richTextIgnoreIt
case .setLink: .richTextLink
case .updateImageAttachments: .richTextIgnoreIt
}
}

Expand Down Expand Up @@ -164,7 +169,7 @@ extension RichTextAction {
case .toggleStyle(let style): style.titleKey
case .undoLatestChange: .actionUndoLatestChange
case .setLink: .link
case .setHeaderStyle: .ignoreIt
case .setHeaderStyle, .updateImageAttachments: .ignoreIt
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ import Foundation
} else {
removeLink()
}
case .updateImageAttachments(let attachments):
attachments.forEach({
textView.setImageAttachment(imageAttachment: $0)
})
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
super.init()
self.textView.delegate = self
subscribeToUserActions()
context.onTextViewDidEndWithSetUp()
}
#if canImport(UIKit)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ extension RichTextViewComponent {
let isSelectedRange = (index == selectedRange.location)
if isSelectedRange { deleteCharacters(in: selectedRange) }
if move { moveInputCursor(to: index) }
var insertedString: NSMutableAttributedString = .init()
let insertedString: NSMutableAttributedString = .init()
images.reversed().forEach {
insertedString.append(performPasteImage($0, at: index) ?? .init())
}
Expand All @@ -88,6 +88,12 @@ extension RichTextViewComponent {
#endif
}

public func setImageAttachment(imageAttachment: ImageAttachment) {
guard let range = imageAttachment.range else { return }
let image = imageAttachment.image
performSetImageAttachment(image, at: range)
}

/**
Paste text into the text view, at a certain index.

Expand Down Expand Up @@ -154,3 +160,15 @@ extension RichTextViewComponent {
}
}
#endif

#if iOS || macOS || os(tvOS) || os(visionOS)
extension RichTextViewComponent {
fileprivate func performSetImageAttachment(
_ image: ImageRepresentable,
at range: NSRange
) {
guard let attachmentString = getAttachmentString(for: image) else { return }
mutableAttributedString?.replaceCharacters(in: range, with: attachmentString)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// RichAttributes+ImageDownload.swift
// RichEditorSwiftUI
//
// Created by Divyesh Vekariya on 31/12/24.
//

import Foundation

extension RichAttributes {
func getImage() async -> ImageRepresentable? {
if let imageUrl = image {
let image = try? await ImageDownloadManager.shared.fetchImage(from: imageUrl)
return image
}
return nil
}
}
6 changes: 4 additions & 2 deletions Sources/RichEditorSwiftUI/Data/Models/RichAttributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,10 @@ extension RichAttributes {
? (byAdding ? att.align! : nil) : self.align),
///nil link indicates removal as well so removing link if `byAdding == false && att.link == nil`
link: (att.link != nil
? (byAdding ? att.link! : nil) : (att.link == nil && !byAdding) ? nil : self.link),
image: (att.image != nil ? (byAdding ? att.image! : nil) : self.image)
? (byAdding ? att.link! : nil)
: (att.link == nil && !byAdding) ? nil : self.link),
image: (att.image != nil
? (byAdding ? att.image! : nil) : self.image)
)
}
}
Expand Down
6 changes: 5 additions & 1 deletion Sources/RichEditorSwiftUI/Images/ImageAttachment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@

import Foundation

public class ImageAttachment {
public class ImageAttachment: Equatable {
public static func == (lhs: ImageAttachment, rhs: ImageAttachment) -> Bool {
return lhs.id == rhs.id && lhs.image == rhs.image
}

public let id: String
public let image: ImageRepresentable
internal var range: NSRange? = nil
Expand Down
3 changes: 1 addition & 2 deletions Sources/RichEditorSwiftUI/Images/ImageDownloadManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ public class ImageDownloadManager {
userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])
}

let (data, _) = try await URLSession.shared.data(from: url)

let (data, response) = try await URLSession.shared.data(from: url)
guard let image = ImageRepresentable(data: data) else {
throw NSError(
domain: "ImageDownloadManager", code: 500,
Expand Down
63 changes: 63 additions & 0 deletions Sources/RichEditorSwiftUI/UI/Context/RichEditorState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,69 @@ public class RichEditorState: ObservableObject {
}
}

//MARK: - Handle Image download
extension RichEditorState {
func onTextViewDidEndWithSetUp() {
setupWithImage()
}

func setupWithImage() {
let imageSpans = internalSpans.filter({ $0.attributes?.image != nil })
guard !imageSpans.isEmpty else { return }
imageSpans.forEach { item in
Task { @MainActor [weak self] in
guard let attributes = item.attributes else { return }
let image = await attributes.getImage()
if let image, let imageUrl = attributes.image {
let attachment = ImageAttachment(image: image, url: imageUrl)
attachment.updateRange(with: item.spanRange)
self?.actionPublisher.send(.updateImageAttachments([attachment]))
}
}
}
}

func setupWithImageAttachment(imageAttachment: [ImageAttachment]) {
let richText = internalRichText
var tempSpans: [RichTextSpanInternal] = []
var text = ""
richText.spans.forEach({
let span = RichTextSpanInternal(
from: text.utf16Length,
to: (text.utf16Length + $0.insert.utf16Length - 1),
attributes: $0.attributes)

tempSpans.append(span)
text += $0.insert
})

let str = NSMutableAttributedString(string: text)

tempSpans.forEach { span in
str.addAttributes(
span.attributes?.toAttributes(font: .standardRichTextFont)
?? [:], range: span.spanRange)
if span.attributes?.color == nil {
var color: ColorRepresentable = .clear
#if os(watchOS)
color = .black
#else
color = RichTextView.Theme.standard.fontColor
#endif
str.addAttributes(
[.foregroundColor: color], range: span.spanRange)
}
if let imageUrl = span.attributes?.image,
let image = imageAttachment.first(where: { $0.url == imageUrl })
{
str.addAttribute(.attachment, value: image.image, range: span.spanRange)
}
}

self.attributedString = str
}
}

extension RichEditorState {

/// Whether or not the context has a selected range.
Expand Down

0 comments on commit afb6e30

Please sign in to comment.