Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rich text not rendering when deserialised #159

Open
alelordelo opened this issue Mar 8, 2024 · 7 comments
Open

Rich text not rendering when deserialised #159

alelordelo opened this issue Mar 8, 2024 · 7 comments
Labels
bug Something isn't working

Comments

@alelordelo
Copy link

alelordelo commented Mar 8, 2024

This renders rich text deserialised from Realm:

 @Published var richTextContent = NSAttributedString(string: "")
Text(AttributedString(cellViewModel.richTextContent))

This render text and I can style it fine, but does NOT render rich text .rtf deserialised from Realm:

 @Published var richTextContent = NSAttributedString(string: "")
 RichTextEditor(text: $viewModel.richTextContent, context: viewModel2.context) { _ in
 }

I tried to manually refresh the view, but that didn't work. Really lost here on what could be wrong...

Any inputs are supper appreciated!

@danielsaidi
Copy link
Owner

Hi @alelordelo

Can you try this with the main branch? There was a font bug that causes styles to be ignored.

@danielsaidi danielsaidi added the bug Something isn't working label Mar 11, 2024
@alelordelo
Copy link
Author

alelordelo commented Mar 14, 2024

hi @danielsaidi, just tried now but didn't work also...

RichTextEditor render rich text fine when editing, but not when read from database.

Any idea why this read the rich text attributes, but RichTextEditor not?
Text(AttributedString(cellViewModel.richTextContent))

@danielsaidi
Copy link
Owner

I found a bug in the theming, and disabled applying the theme if the string's not empty...but perhaps something else needs to be fixed as well.

Just to clarify, how do you serialize? If you only serialize the raw string, the format will be thrown away. Have a look at the demo, and see how it persists to file.

@alelordelo
Copy link
Author

alelordelo commented Mar 15, 2024

hey @danielsaidi

So, this is basically my workflow:

Editing works fine

RichTextEditor(text: $viewModel.richTextContent, context: cellViewModel.context) { _ in }

Screenshot 2024-03-15 at 21 05 59

Serialize

        if let richTextData = try? richTextContent.data(from: NSRange(location: 0, length: richTextContent.length), documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf]) {
  newCell.content = richTextData
                            }

Deserialize

func deserializeRichText(from data: Data) -> NSAttributedString {
      do {
          let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
              .documentType: NSAttributedString.DocumentType.rtf
          ]
          let attributedString = try NSAttributedString(data: data, options: options, documentAttributes: nil)
          
          // Print success message with some details about the attributed string
          print("Successfully deserialized RTF data. Length: \(attributedString.length). Preview: \(attributedString.string.prefix(50))")
          
          return attributedString
      } catch {
          print("Error deserializing RTF data: \(error)")
          return NSAttributedString(string: "Failed to load content")
      }
  }

A- Read deserializeRichText into RichTextEditor, renders without complete rich text (underscript works)

 RichTextEditor(text: $viewModel.richTextContent, context: cellViewModel.context) { _ in }
         .onAppear {
                      // Debugging: Log the preview of richTextContent before loading it into the RichTextEditor
                      let previewText = viewModel.richTextContent.string.prefix(100) // Limiting to the first 100 characters for brevity
                      print("Loading rich text into RichTextEditor. Preview: \(previewText)")
                    print("Assigning rich text to cell \(cellViewModel.id). Preview: \(previewText)")
                      // Debugging: Log the attributes at the beginning of the content
                      if viewModel.richTextContent.length > 0 {
                          let range = NSRange(location: 0, length: min(10, cellViewModel.richTextContent.length)) // Inspect the first 10 characters
                          let attributes = cellViewModel.richTextContent.attributes(at: 0, effectiveRange: nil)
                          print("Attributes at start of rich text: \(attributes)")
                      }
                  }

Print this

Loading rich text into RichTextEditor. Preview: hello
Assigning rich text to cell 2DE583D2-2B09-4F2E-8AA6-7380C3E7A708. Preview: hello
Attributes at start of rich text: [:]

updateNSView called
Updated attributed string: hello
Attributes in range {0, 5}: [:]
makeNSView called
Initial attributed string: Academy typewriter, size 46, colour blue  
updateNSView called
Updated attributed string: Academy typewriter, size 46, colour blue  
Attributes in range {0, 42}: [__C.NSAttributedStringKey(_rawValue: NSStrikethroughColor): sRGB IEC61966-2.1 colorspace 0 0.47843 1 1, __C.NSAttributedStringKey(_rawValue: NSColor): Catalog color: System textColor, __C.NSAttributedStringKey(_rawValue: NSStrikethrough): 1, __C.NSAttributedStringKey(_rawValue: NSFont): "HelveticaNeue 16.00 pt. P [] (0x12e791e20) fobj=0x12e745790, spc=4.45", __C.NSAttributedStringKey(_rawValue: NSParagraphStyle): Alignment Right, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode WordWrapping, Tabs (
Screenshot 2024-03-15 at 20 59 20

B- Read deserializeRichText into Text(AttributedString( )) for debug purposes. Render correctly

Text(AttributedString(viewModel.richTextContent))

Screenshot 2024-03-15 at 21 02 15

Print this

Successfully deserialized RTF data. Length: 42. Preview: Academy typewriter, size 46, colour blue  
Successfully deserialized RTF data. Length: 42. Preview: Academy typewriter, size 46, colour blue  
DesignView rendered with namespace: ID(id: 626)
DesignView rendered with layout.id): 73A3271C-FC19-456F-AE02-935F72DD27B4
Loading rich text into RichTextEditor. Preview: hello
Assigning rich text to cell F7B9B307-177E-45B9-8DB5-E6F2F9B4E3CC. Preview: hello
Attributes at start of rich text: [:]
Loading rich text into RichTextEditor. Preview: Academy typewriter, size 46, colour blue  
Assigning rich text to cell 6621503E-929A-4758-B076-EA3A406661C2. Preview: Academy typewriter, size 46, colour blue  
Attributes at start of rich text: [__C.NSAttributedStringKey(_rawValue: NSStrikethrough): 1, __C.NSAttributedStringKey(_rawValue: NSStrikethroughColor): sRGB IEC61966-2.1 colorspace 0 0.47843 1 1, __C.NSAttributedStringKey(_rawValue: NSFont): "AcademyEngravedLetPlain 48.00 pt. P [] (0x142e57960) fobj=0x142f11f40, spc=15.89", __C.NSAttributedStringKey(_rawValue: NSColor): sRGB IEC61966-2.1 colorspace 0 0.47843 1 1, __C.NSAttributedStringKey(_rawValue: NSParagraphStyle): Alignment Right, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode WordWrapping, Tabs (

@danielsaidi
Copy link
Owner

@alelordelo Thank you for the detailed bug report! 🙏

In that case, I think it may be the font bug, since underline works.

@DominikBucher12 We should look into this.

@alelordelo
Copy link
Author

@danielsaidi and @DominikBucher12 ,

Updates on the debug...

I added some prints to RichTextEditor ViewRepresentable:



   public init(
       text: Binding<NSAttributedString>,
       context: RichTextContext,
       config: RichTextView.Configuration = .standard,
       format: RichTextDataFormat = .archivedData,
       viewConfiguration: @escaping ViewConfiguration = { _ in }
   ) {
       self.text = text
       self.config = config
       self._context = ObservedObject(wrappedValue: context)
       self.format = format
       self.viewConfiguration = viewConfiguration
   }

   public typealias ViewConfiguration = (RichTextViewComponent) -> Void

   @ObservedObject
   private var context: RichTextContext

   private var text: Binding<NSAttributedString>
   private let config: RichTextView.Configuration
   private var format: RichTextDataFormat
   private var viewConfiguration: ViewConfiguration

   #if iOS || os(tvOS) || os(visionOS)
   public let textView = RichTextView()
   #endif

   #if macOS
   public let scrollView = RichTextView.scrollableTextView()

   public var textView: RichTextView {
       scrollView.documentView as? RichTextView ?? RichTextView()
   }
   #endif

   public func makeCoordinator() -> RichTextCoordinator {
       RichTextCoordinator(
           text: text,
           textView: textView,
           richTextContext: context
       )
   }

   #if iOS || os(tvOS) || os(visionOS)
   public func makeUIView(context: Context) -> some UIView {
       textView.setup(with: text.wrappedValue, format: format)
       textView.configuration = config
       viewConfiguration(textView)
       return textView
   }

   public func updateUIView(_ view: UIViewType, context: Context) {}

   #else

   public func makeNSView(context: Context) -> some NSView {
       print("makeNSView called")
       print("Initial attributed string inside makeNSView : \(text.wrappedValue.string.prefix(100))") // Print the first 100 characters for brevity
       textView.setup(with: text.wrappedValue, format: format)
       textView.configuration = config
       viewConfiguration(textView)
       return scrollView
   }

   public func updateNSView(_ view: NSViewType, context: Context) {
       print("updateNSView called")
           let attributedString = text.wrappedValue
           print("Updated attributed string inside updateNSView: \(attributedString.string.prefix(100))") // Print the first 100 characters for brevity

           // Print attributes of the entire attributed string
           attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { attributes, range, _ in
               print("Attributes inside updateNSView in range \(range): \(attributes)")
           }
   }
   #endif
}

// MARK: RichTextPresenter

public extension RichTextEditor {

   /// Get the currently selected range.
   var selectedRange: NSRange {
       textView.selectedRange
   }
}

// MARK: RichTextReader

public extension RichTextEditor {

   /// Get the string that is managed by the editor.
   var attributedString: NSAttributedString {
       text.wrappedValue
   }
}

// MARK: RichTextWriter

public extension RichTextEditor {

   /// Get the mutable string that is managed by the editor.
   var mutableAttributedString: NSMutableAttributedString? {
       textView.mutableAttributedString
   }
}

#endif


And found that:

Initially the font is read correctly:
Attributes inside updateNSView in range {0, 14}: [__C.NSAttributedStringKey(_rawValue: NSStrikethrough): 1, __C.NSAttributedStringKey(_rawValue: NSFont): "AcademyEngravedLetPlain 72.00 pt.

But when updated, it defaults to AppleSystemUIFont:
Attributes inside updateNSView in range {0, 14}: [__C.NSAttributedStringKey(_rawValue: NSStrikethroughColor): sRGB IEC61966-2.1 colorspace 0 0.47843 1 1, __C.NSAttributedStringKey(_rawValue: NSFont): ".AppleSystemUIFont 16.00 pt.

Probably something is causing the view to be refreshed, and it defaults to apple font?

@danielsaidi
Copy link
Owner

I tested the demo app in the main branch, and opening a saved text document still works. It restores fonts, colors, styles, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants