Skip to content

Commit

Permalink
Merge pull request #16 from colinc86/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
colinc86 authored Jun 14, 2023
2 parents 3489517 + f2b3cc4 commit 3d1888a
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 139 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/swift.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This workflow will build a Swift project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift

name: Swift
name: Unit Tests

on:
push:
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A SwiftUI view that renders LaTeX equations.

[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcolinc86%2FLaTeXSwiftUI%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/colinc86/LaTeXSwiftUI) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcolinc86%2FLaTeXSwiftUI%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/colinc86/LaTeXSwiftUI)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcolinc86%2FLaTeXSwiftUI%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/colinc86/LaTeXSwiftUI) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcolinc86%2FLaTeXSwiftUI%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/colinc86/LaTeXSwiftUI) [![Unit Tests](https://github.com/colinc86/LaTeXSwiftUI/actions/workflows/swift.yml/badge.svg)](https://github.com/colinc86/LaTeXSwiftUI/actions/workflows/swift.yml)

<center><img src="./assets/images/device.png" width="362"></center>

Expand All @@ -23,7 +23,7 @@ A SwiftUI view that renders LaTeX equations.
- [Format Equation Number](#format-equation-number)
- [Unencode HTML](#🔗-unencode-html)
- [Rendering Style](#🕶️-rendering-style)
- [Animated](#🪩-animated)
- [Rendering Animation](#🪩-animated)
- [Caching](#🗄️-caching)
- [Preloading](#🏃‍♀️-preloading)

Expand All @@ -47,7 +47,7 @@ It won't
Add the dependency to your package manifest file.

```swift
.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.2.1")
.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.2.2")
```

## ⌨️ Usage
Expand Down Expand Up @@ -237,14 +237,14 @@ The view has four rendering styles. The `wait` style is the default style, and l
| `wait` | No | *(default)* The view blocks the main queue until its finished rendering. |


#### 🪩 Animated
#### 🪩 Rendering Animation

The `animated` modifier applies to the view when using the asynchronous rendering styles `empty`, `original`, or `progress`.
When using the asynchronous rendering styles `empty`, `original`, or `progress`, use this modifier to determine the animation applied to the transition between views. The default value is `none`.

```swift
LaTeX(input)
.renderingStyle(.original)
.animated()
.renderingAnimation(.easeIn)
```

> In the above example, the input text will be displayed until the SVGs have been rendered at which point the rendered views will animate in to view.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ private struct RenderingStyleKey: EnvironmentKey {
static let defaultValue: LaTeX.RenderingStyle = .wait
}

private struct AnimatedKey: EnvironmentKey {
static let defaultValue: Bool = false
private struct RenderingAnimationKey: EnvironmentKey {
static let defaultValue: Animation? = .none
}

extension EnvironmentValues {
Expand Down Expand Up @@ -143,9 +143,9 @@ extension EnvironmentValues {
}

/// Whether or not rendering should be animated.
var animated: Bool {
get { self[AnimatedKey.self] }
set { self[AnimatedKey.self] = newValue }
var renderingAnimation: Animation? {
get { self[RenderingAnimationKey.self] }
set { self[RenderingAnimationKey.self] = newValue }
}

}
10 changes: 5 additions & 5 deletions Sources/LaTeXSwiftUI/Extensions/View+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,12 @@ public extension View {
environment(\.renderingStyle, style)
}

/// Sets whether or not the view will animate its render state changes.
/// Sets the animation the view should apply to its rendered images.
///
/// - Parameter animate: Whether animations are enabled.
/// - Returns: A view that animates its rendering.
func animated(_ animate: Bool = true) -> some View {
environment(\.animated, animate)
/// - Parameter animation: The animation.
/// - Returns: A view that animates its rendered state.
func renderingAnimation(_ animation: Animation?) -> some View {
environment(\.renderingAnimation, animation)
}

}
109 changes: 90 additions & 19 deletions Sources/LaTeXSwiftUI/LaTeX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ public struct LaTeX: View {
/// The view's rendering style.
@Environment(\.renderingStyle) private var renderingStyle

/// Whether or not rendering should be animated.
@Environment(\.animated) private var animated
/// The animation the view should apply to its rendered images.
@Environment(\.renderingAnimation) private var renderingAnimation

/// The view's current display scale.
@Environment(\.displayScale) private var displayScale
Expand Down Expand Up @@ -188,24 +188,27 @@ public struct LaTeX: View {
// MARK: View body

public var body: some View {
if renderState.rendered {
bodyWithBlocks(renderState.blocks)
}
else {
switch renderingStyle {
case .empty:
Text("")
.task(render)
case .original:
Text(latex)
.task(render)
case .progress:
ProgressView()
.task(render)
case .wait:
bodyWithBlocks(syncBlocks)
VStack(spacing: 0) {
if renderState.rendered {
bodyWithBlocks(renderState.blocks)
}
else {
switch renderingStyle {
case .empty:
Text("")
.task(render)
case .original:
Text(latex)
.task(render)
case .progress:
ProgressView()
.task(render)
case .wait:
bodyWithBlocks(syncBlocks)
}
}
}
.animation(renderingAnimation, value: renderState.rendered)
}

}
Expand All @@ -229,7 +232,6 @@ extension LaTeX {
/// Renders the view's components.
@Sendable private func render() async {
await renderState.render(
animated: animated,
unencodeHTML: unencodeHTML,
parsingMode: parsingMode,
font: font,
Expand Down Expand Up @@ -296,6 +298,58 @@ struct LaTeX_Previews: PreviewProvider {
.previewLayout(.sizeThatFits)
.previewDisplayName("Hello, LaTeX!")

VStack {
LaTeX("Hello, $\\color{blue}\\LaTeX$")
.imageRenderingMode(.original)

LaTeX("Hello, $\\LaTeX$")
.imageRenderingMode(.template)
}
.previewDisplayName("Image Rendering Mode")

VStack {
LaTeX("$\\asdf$")
.errorMode(.error)

LaTeX("$\\asdf$")
.errorMode(.original)

LaTeX("$\\asdf$")
.errorMode(.rendered)
}
.previewDisplayName("Error Mode")

VStack {
LaTeX("$x&lt;0$")
.errorMode(.error)

LaTeX("$x&lt;0$")
.unencoded()
.errorMode(.error)
}
.previewDisplayName("Unencoded")

VStack {
LaTeX("$a^2 + b^2 = c^2$")
.parsingMode(.onlyEquations)

LaTeX("a^2 + b^2 = c^2")
.parsingMode(.all)
}
.previewDisplayName("Parsing Mode")

VStack {
LaTeX("Equation 1: $$x = 3$$")
.blockMode(.blockViews)

LaTeX("Equation 1: $$x = 3$$")
.blockMode(.blockText)

LaTeX("Equation 1: $$x = 3$$")
.blockMode(.alwaysInline)
}
.previewDisplayName("Block Mode")

VStack {
LaTeX("$$E = mc^2$$")
.equationNumberMode(.right)
Expand All @@ -313,6 +367,23 @@ struct LaTeX_Previews: PreviewProvider {
.formatEquationNumber { n in
return "~[\(n)]~"
}

VStack {
LaTeX("Hello, $\\LaTeX$!")
.renderingStyle(.wait)

LaTeX("Hello, $\\LaTeX$!")
.renderingStyle(.empty)

LaTeX("Hello, $\\LaTeX$!")
.renderingStyle(.original)
.renderingAnimation(.default)

LaTeX("Hello, $\\LaTeX$!")
.renderingStyle(.progress)
.renderingAnimation(.easeIn)
}
.previewDisplayName("Rendering Style and Animated")
}

}
20 changes: 20 additions & 0 deletions Sources/LaTeXSwiftUI/Models/Component.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,26 @@ internal struct ComponentBlock: Hashable, Identifiable {
components.count == 1 && !components[0].type.inline
}

/// Creates the image view and its size for the given block.
///
/// If the block isn't an equation block, then this method returns `nil`.
///
/// - Parameter block: The block.
/// - Returns: The image, its size, and any associated error text.
@MainActor func image(
font: Font,
displayScale: CGFloat,
renderingMode: Image.TemplateRenderingMode
) -> (Image, CGSize, String?)? {
guard isEquationBlock, let component = components.first else {
return nil
}
return component.convertToImage(
font: font,
displayScale: displayScale,
renderingMode: renderingMode)
}

}

/// A LaTeX component.
Expand Down
27 changes: 5 additions & 22 deletions Sources/LaTeXSwiftUI/Models/LaTeXRenderState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,27 +59,19 @@ extension LaTeXRenderState {
/// Renders the views components.
///
/// - Parameters:
/// - animated: The `animated` environment variable.
/// - unencodeHTML: The `unencodeHTML` environment variable.
/// - parsingMode: The `parsingMode` environment variable.
/// - font: The `font environment` variable.
/// - displayScale: The `displayScale` environment variable.
/// - texOptions: The `texOptions` environment variable.
func render(animated: Bool, unencodeHTML: Bool, parsingMode: LaTeX.ParsingMode, font: Font?, displayScale: CGFloat, texOptions: TeXInputProcessorOptions) async {
func render(unencodeHTML: Bool, parsingMode: LaTeX.ParsingMode, font: Font?, displayScale: CGFloat, texOptions: TeXInputProcessorOptions) async {
let isRen = await isRendering
let ren = await rendered
guard !isRen && !ren else {
return
}
await MainActor.run {
if animated {
withAnimation {
isRendering = true
}
}
else {
isRendering = true
}
isRendering = true
}

let renderedBlocks = await Renderer.shared.render(
Expand All @@ -89,18 +81,9 @@ extension LaTeXRenderState {
texOptions: texOptions)

await MainActor.run {
if animated {
withAnimation {
blocks = renderedBlocks
isRendering = false
rendered = true
}
}
else {
blocks = renderedBlocks
isRendering = false
rendered = true
}
blocks = renderedBlocks
isRendering = false
rendered = true
}
}

Expand Down
73 changes: 73 additions & 0 deletions Sources/LaTeXSwiftUI/Views/ComponentBlockText.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// ComponentBlockText.swift
// LaTeXSwiftUI
//
// Copyright (c) 2023 Colin Campbell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//

import SwiftUI

/// Displays a component block as a text view.
internal struct ComponentBlockText: View {

/// The component blocks to display in the view.
let block: ComponentBlock

// MARK: Private properties

/// The rendering mode to use with the rendered MathJax images.
@Environment(\.imageRenderingMode) private var imageRenderingMode

/// What to do in the case of an error.
@Environment(\.errorMode) private var errorMode

/// The view's font.
@Environment(\.font) private var font

/// The view's current display scale.
@Environment(\.displayScale) private var displayScale

/// The view's block rendering mode.
@Environment(\.blockMode) private var blockMode

// MARK: View body

var body: Text {
block.components.enumerated().map { i, component in
return component.convertToText(
font: font ?? .body,
displayScale: displayScale,
renderingMode: imageRenderingMode,
errorMode: errorMode,
blockRenderingMode: blockMode,
isInEquationBlock: block.isEquationBlock)
}.reduce(Text(""), +)
}

}

struct ComponentBlockTextPreviews: PreviewProvider {
static var previews: some View {
ComponentBlockText(block: ComponentBlock(components: [
Component(text: "Hello, World!", type: .text)
]))
}
}
Loading

0 comments on commit 3d1888a

Please sign in to comment.