Skip to content

Commit

Permalink
1.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
nathantannar4 committed Feb 28, 2024
1 parent ede3eba commit 21771ea
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 29 deletions.
70 changes: 70 additions & 0 deletions Sources/Turbocharger/Sources/View/ForEach.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// Copyright (c) Nathan Tannar
//

import SwiftUI

extension ForEach {
@_disfavoredOverload
@inlinable
public init<_Data: RandomAccessCollection>(
_ data: _Data,
@ViewBuilder content: @escaping (_Data.Index, _Data.Element) -> Content
) where Data == Array<(_Data.Index, _Data.Element)>, ID == _Data.Index, Content: View {
let elements = Array(zip(data.indices, data))
self.init(elements, id: \.0) { index, element in
content(index, element)
}
}

@inlinable
public init<
_Data: RandomAccessCollection
>(
_ data: _Data,
id: KeyPath<_Data.Element, ID>,
@ViewBuilder content: @escaping (_Data.Index, _Data.Element) -> Content
) where Data == Array<(_Data.Index, _Data.Element)>, Content: View {
let elements = Array(zip(data.indices, data))
let elementPath: KeyPath<(_Data.Index, _Data.Element), _Data.Element> = \.1
self.init(elements, id: elementPath.appending(path: id)) { index, element in
content(index, element)
}
}

@inlinable
public init<
_Data: RandomAccessCollection
>(
_ data: _Data,
@ViewBuilder content: @escaping (_Data.Index, _Data.Element) -> Content
) where Data == Array<(_Data.Index, _Data.Element)>, _Data.Element: Identifiable, ID == _Data.Element.ID, Content: View {
let elements = Array(zip(data.indices, data))
self.init(elements, id: \.1.id) { index, element in
content(index, element)
}
}
}

// MARK: - ForEach Previews

struct ForEach_Previews: PreviewProvider {
struct Model: Identifiable {
var id = UUID().uuidString
}
static var previews: some View {
VStack {
ForEach([10, 20, 30]) { index, number in
Text("\(index): \(number)")
}

ForEach([10, 20, 30], id: \.self) { index, number in
Text("\(index): \(number)")
}

ForEach([Model()]) { index, model in
Text("\(index): \(model.id)")
}
}
}
}
71 changes: 68 additions & 3 deletions Sources/Turbocharger/Sources/View/MarqueeHStack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public struct MarqueeHStack<Selection: Hashable, Content: View>: View {

public var spacing: CGFloat
public var speed: Double
public var minimumInterval: Double?
public var isScrollEnabled: Bool
public var content: Content

Expand All @@ -20,13 +21,15 @@ public struct MarqueeHStack<Selection: Hashable, Content: View>: View {
public init(
spacing: CGFloat? = nil,
speed: Double = 1,
minimumInterval: Double? = nil,
delay: TimeInterval = 2,
isScrollEnabled: Bool = true,
@ViewBuilder content: () -> Content
) where Selection == Never {
self.selection = nil
self.spacing = spacing ?? 4
self.speed = speed
self.minimumInterval = minimumInterval
self.isScrollEnabled = isScrollEnabled
self.content = content()
self._startAt = State(wrappedValue: Date.now.addingTimeInterval(delay))
Expand All @@ -37,13 +40,15 @@ public struct MarqueeHStack<Selection: Hashable, Content: View>: View {
selection: Binding<Selection>,
spacing: CGFloat? = nil,
speed: Double = 1,
minimumInterval: Double? = nil,
delay: TimeInterval = 2,
isScrollEnabled: Bool = true,
@ViewBuilder content: () -> Content
) {
self.selection = selection
self.spacing = spacing ?? 4
self.speed = speed
self.minimumInterval = minimumInterval
self.isScrollEnabled = isScrollEnabled
self.content = content()
self._startAt = State(wrappedValue: Date.now.addingTimeInterval(delay))
Expand All @@ -60,7 +65,7 @@ public struct MarqueeHStack<Selection: Hashable, Content: View>: View {
content
} content: { source in
TimelineView(
.animation(minimumInterval: nil, paused: !isScrollEnabled)
.animation(minimumInterval: minimumInterval, paused: !isScrollEnabled)
) { ctx in
MarqueeHStackBody(
selection: selection,
Expand Down Expand Up @@ -180,10 +185,10 @@ private struct MarqueeHStackBody<Selection: Hashable>: View {

let requiredWidth = resolvedSymbols.map(\.symbol.size.width).reduce(0, +) + spacing * CGFloat(views.count - 1)
let timestamp = keyframe / 20 * speed
let dx = (requiredWidth * timestamp).truncatingRemainder(dividingBy: requiredWidth).rounded()
let dx = (requiredWidth * timestamp).truncatingRemainder(dividingBy: requiredWidth)
var origin = CGPoint(
x: 0,
y: (size.height / 2).rounded()
y: (size.height / 2)
)

if requiredWidth > size.width {
Expand Down Expand Up @@ -217,3 +222,63 @@ private struct MarqueeHStackBody<Selection: Hashable>: View {
box?.nodes = proxies
}
}

// MARK: - Previews

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
struct MarqueeHStack_Previews: PreviewProvider {
static var previews: some View {
VStack {
MarqueeHStack(speed: 2) {
ForEach(0..<10, id: \.self) { index in
Label {
Text("Index: \(index)")
} icon: {
Image(systemName: "info")
}
.foregroundColor(.white)
.padding(.vertical, 6)
.padding(.horizontal, 8)
.background {
Capsule()
.fill(.black)
}
}
}

MarqueeHStack(speed: -1) {
ForEach(10..<20, id: \.self) { index in
Label {
Text("Index: \(index)")
} icon: {
Image(systemName: "info")
}
.foregroundColor(.white)
.padding(.vertical, 6)
.padding(.horizontal, 8)
.background {
Capsule()
.fill(.black)
}
}
}

MarqueeHStack {
ForEach(20..<30, id: \.self) { index in
Label {
Text("Index: \(index)")
} icon: {
Image(systemName: "info")
}
.foregroundColor(.white)
.padding(.vertical, 6)
.padding(.horizontal, 8)
.background {
Capsule()
.fill(.black)
}
}
}
}
}
}
26 changes: 0 additions & 26 deletions Sources/Turbocharger/Sources/View/ProposedSizeObserver.swift

This file was deleted.

1 comment on commit 21771ea

@danqing
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathantannar4 is the ProposedSizeObserver file removed by mistake? It's still used here so now build is broken:

.modifier(ProposedSizeObserver(size: $size))

Please sign in to comment.