Skip to content

Refactor post detail rendering with native RichView module #70

@graycreate

Description

@graycreate

Overview

Refactor V2er's content rendering by replacing two different implementations with a unified, high-performance RichView module.

Current State (Two Implementations)

1. Topic Content (NewsContentView.swift)

Implementation: HtmlView - WKWebView-based
Location: V2er/View/FeedDetail/NewsContentView.swift:23

HtmlView(html: contentInfo?.html, imgs: contentInfo?.imgs ?? [], rendered: $rendered)

Problems:

  • High memory usage (~20MB per WebView)
  • Slow initialization and rendering
  • Async height calculation causes UI jank
  • JavaScript bridge complexity
  • No caching mechanism

2. Reply Content (ReplyItemView.swift)

Implementation: RichText - NSAttributedString HTML parser
Location: V2er/View/FeedDetail/ReplyItemView.swift:48

RichText { info.content }

Problems:

  • No code syntax highlighting
  • No @mention detection/navigation
  • No image preview support
  • Inconsistent with topic rendering
  • No caching mechanism

Unified Issues

  • Maintaining two different implementations
  • Inconsistent user experience
  • Both lack modern features (@mention, code highlighting)
  • Both lack performance optimizations (caching)

Proposed Solution

Implement a unified RichView module that replaces both:

Architecture

V2EX HTML → HTMLToMarkdownConverter → Markdown
         → swift-markdown Parser → AST
         → V2EXMarkupVisitor → AttributedString
         → UITextView (via UIViewRepresentable)

Module Structure

V2er/View/RichView/
├── RichView.swift              # Public interface
├── Components/                 # RichTextView, AsyncImageAttachment
├── Rendering/                  # HTML→Markdown, MarkdownRenderer, V2EXMarkupVisitor
├── Support/                    # RenderCache, DegradationChecker, PerformanceBenchmark
├── Models/                     # RichViewEvent, RenderConfiguration, RenderMetadata
└── Extensions/                 # AttributedString+RichView, String+Markdown

Implementation Plan

Phase 1: Basic Infrastructure (2-3 days)

  • Create RichView module directory structure
  • Integrate SPM dependencies (swift-markdown, Highlightr)
  • Implement RichView.swift public interface
  • Implement Rendering/HTMLToMarkdownConverter.swift (basic tags)
  • Implement Rendering/MarkdownRenderer.swift
  • Implement Rendering/V2EXMarkupVisitor.swift (basic)
  • Implement Components/RichTextView.swift (UITextView wrapper)

Deliverable: Can render simple V2EX posts with text formatting and links


Phase 2: Complete Features (3-4 days)

  • Complete Rendering/HTMLToMarkdownConverter.swift
    • All HTML tags (img, blockquote, ul, ol, li, hr, h1-h6)
    • @mention detection and conversion
    • Image link wrapping handling
  • Complete Rendering/V2EXMarkupVisitor.swift
    • Image rendering with placeholders
    • List and quote rendering
    • Code syntax highlighting (Highlightr integration)
  • Implement Components/AsyncImageAttachment.swift
    • Kingfisher integration for async loading
    • Placeholder and error handling
  • Implement Models/RichViewEvent.swift (event types)
  • Implement Models/RenderConfiguration.swift (config options)
  • Complete event handling in RichTextView
    • Link taps, image taps, @mention taps
    • Text selection support

Deliverable: All V2EX content features working (images, code, @mentions)


Phase 3: Performance Optimization (2-3 days)

  • Implement Support/RenderCache.swift
    • NSCache with NSObject wrapper for AttributedString
    • MD5-based cache keys
    • LRU eviction policy
  • Implement Support/DegradationChecker.swift
    • HTML size detection (>100KB → WebView)
    • Unsupported tag detection
    • Error detection and logging
  • Implement Support/PerformanceBenchmark.swift
    • Render time measurement
    • Memory usage tracking
    • Cache hit rate statistics
  • Implement Models/RenderMetadata.swift
    • Performance metrics recording
  • Optimize async rendering
    • Use .task modifier (structured concurrency)
    • Priority control (.userInitiated)
  • Performance testing
    • Render speed < 50ms (single post)
    • Memory reduction > 70%
    • Scrolling at 60fps

Deliverable: Production-ready performance with caching


Phase 4: Integration (2-3 days)

4.1 Replace Topic Content (NewsContentView)

  • Replace HtmlView with RichView
    • Remove imgs parameter (auto-detect from HTML)
    • Use .default configuration
    • Implement event handlers (links, images, @mentions)
    • Maintain rendered state binding
  • Add feature flag useRichViewForTopic
    • Fallback to HtmlView on error
  • Test with various topic types
    • Text-only, images, code, @mentions, mixed

4.2 Replace Reply Content (ReplyItemView)

  • Replace RichText with RichView
    • Use .compact configuration (smaller fonts)
    • Implement event handlers
    • Adapt to reply list layout
  • Add feature flag useRichViewForReply
    • Fallback to RichText on error
  • Performance testing
    • Reply list scrolling (60fps)
    • Cache hit rate > 80%
    • Memory usage comparison
  • Test with various reply types
    • Short/long, code, @mentions, list performance (100+ replies)

4.3 UI & Interaction Testing

  • Font size adaptation (topic: 16pt, reply: 14pt)
  • Dark mode support (colors, code themes)
  • Line/paragraph spacing matching existing UI
  • Link clicking (external/internal navigation)
  • Image preview (viewer, gestures, close)
  • @mention navigation (user profile)
  • Text selection (long-press, copy)

4.4 Degradation Testing

  • Large content (>100KB) → WebView fallback
  • Unsupported tags → WebView fallback
  • Render errors → fallback with proper error handling
  • Verify fallback functionality

Deliverable: Both topic and reply content using RichView, ready for testing


Phase 5: Rollout (1-2 days)

  • Gradual rollout strategy
    • 10% users (monitor metrics)
    • 50% users (verify stability)
    • 100% users (full rollout)
  • Performance monitoring
    • Render time tracking
    • Memory usage monitoring
    • Cache hit rate analytics
    • Degradation rate tracking
  • User feedback collection
  • Bug fixes and refinements
  • Final cleanup
    • Remove HtmlView.swift if no longer needed
    • Remove old RichText.swift (Atributika version)
    • Remove Atributika dependency if unused elsewhere
    • Update documentation

Deliverable: Full production rollout with monitoring


Success Metrics

Performance Targets

  • Topic Content: 10x faster rendering (< 100ms vs ~1s)
  • Reply Content: 3-5x faster with caching
  • Memory: 70%+ reduction (eliminate WebView overhead)
  • Scrolling: Stable 60fps in reply lists with 100+ items
  • Cache Hit Rate: > 80% in reply lists

Feature Completeness

  • ✅ Code syntax highlighting (185+ languages)
  • ✅ @mention detection and navigation
  • ✅ Image preview with built-in viewer
  • ✅ Consistent rendering (topic & reply)
  • ✅ Text selection and copy

Quality Metrics

  • Degradation Rate: < 1% of content requiring WebView fallback
  • Crash Rate: No increase from baseline
  • User Complaints: No significant increase

Dependencies

  • swift-markdown (Apple official, iOS 15+) - CommonMark/GFM parser
  • Highlightr (v2.1.0+) - Syntax highlighting
  • SwiftSoup (already in project) - HTML parsing
  • Kingfisher (already in project) - Image loading

Migration Comparison

Feature HtmlView (Topic) RichText (Reply) RichView (New)
Render Engine WKWebView NSAttributedString HTML AttributedString + Markdown
Performance Slow (~1s) Medium (~200ms) Fast (<50ms)
Memory Usage High (~20MB) Low (~1MB) Low (~1MB)
Code Highlighting ✅ (185+ languages)
@Mention Navigation Manual ✅ Built-in
Image Preview Manual ✅ Built-in
Height Calculation Async (jank) Sync Sync
Caching ✅ Automatic (80%+ hit rate)
Maintainability Complex (JS bridge) Simple Simple (Swift native)

Risks & Mitigation

Risk Mitigation
Complex HTML edge cases WebView degradation fallback
Performance not meeting targets Staged KPIs (200ms→100ms→50ms)
Breaking existing functionality Feature flags + gradual rollout
Memory leaks in image loading Structured concurrency + lifecycle management
User complaints about changes Monitor feedback, quick rollback capability

Related

Timeline

Estimated: 10-12 days total
Priority: High (major performance improvement + feature unification)

Breakdown:

  • Phase 1: 2-3 days
  • Phase 2: 3-4 days
  • Phase 3: 2-3 days
  • Phase 4: 2-3 days
  • Phase 5: 1-2 days

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions