Skip to content

Add padding to multiline modifier #29

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

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct CharacterView: View {
Text(character?.name)
.skeleton(with: loading)
.shape(type: .capsule)
.multiline(lines: 3, scales: [1: 0.5, 2: 0.25])
.multiline(lines: 3, scales: [1: 0.5, 2: 0.25], padding: EdgeInsets(top: 16, leading: 0, bottom: 16, trailing: 0))
.appearance(type: .gradient())
.animation(type: .linear())
}
Expand All @@ -35,7 +35,7 @@ struct CharacterView: View {
#if DEBUG
struct CharacterView_Previews: PreviewProvider {
static var previews: some View {
CharacterView(character: nil, loading: false)
CharacterView(character: nil, loading: true).previewLayout(.sizeThatFits).frame(width: 300, height: 100, alignment: .center)
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -54,46 +54,33 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/SkeletonUI-watchOS WatchKit App">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "87A5D90D230803F50096BD32"
BuildableName = "SkeletonUI-watchOS WatchKit App.app"
BlueprintName = "SkeletonUI-watchOS WatchKit App"
ReferencedContainer = "container:SkeletonUI-watchOS.xcodeproj">
</BuildableReference>
</RemoteRunnable>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/SkeletonUI-watchOS WatchKit App">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "87A5D90D230803F50096BD32"
BuildableName = "SkeletonUI-watchOS WatchKit App.app"
BlueprintName = "SkeletonUI-watchOS WatchKit App"
ReferencedContainer = "container:SkeletonUI-watchOS.xcodeproj">
</BuildableReference>
</RemoteRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "87A5D90D230803F50096BD32"
BuildableName = "SkeletonUI-watchOS WatchKit App.app"
BlueprintName = "SkeletonUI-watchOS WatchKit App"
ReferencedContainer = "container:SkeletonUI-watchOS.xcodeproj">
</BuildableReference>
</MacroExpansion>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing",
"state": {
"branch": null,
"revision": "12c6a7ce9d67f39a23c6bab757bdb073bd997885",
"version": "1.7.1"
"revision": "f8a9c997c3c1dab4e216a8ec9014e23144cbab37",
"version": "1.9.0"
}
}
]
Expand Down
2 changes: 1 addition & 1 deletion SkeletonUI.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'SkeletonUI'
s.version = '1.0.5'
s.version = '1.0.6'
s.summary = 'Elegant skeleton loading animation in SwiftUI and Combine'
s.description = <<-DESC
SkeletonUI aims to bring an elegant, declarative syntax to skeleton loading animations. Get rid of loading screens or spinners and start using skeletons to represent final content shapes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ public extension ModifiedContent where Content: View, Modifier == SkeletonModifi
return self
}

func multiline(lines: Int, scales: [Int: CGFloat]? = nil, spacing: CGFloat? = nil) -> ModifiedContent<Content, SkeletonModifier> {
func multiline(lines: Int, scales: [Int: CGFloat]? = nil, spacing: CGFloat? = nil, padding: EdgeInsets? = nil) -> ModifiedContent<Content, SkeletonModifier> {
modifier.skeleton.multiline.lines.send(lines)
modifier.skeleton.multiline.scales.send(scales)
modifier.skeleton.multiline.spacing.send(spacing)
modifier.skeleton.multiline.padding.send(padding)
return self
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/SkeletonUI/Extensions/View+SkeletonModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import SwiftUI

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public extension View {
func skeleton(with loading: Bool, transition: AnyTransition? = nil, animated: Animation? = nil) -> ModifiedContent<Self, SkeletonModifier> {
modifier(SkeletonModifier(skeleton: SkeletonInteractor(loading, transition: transition, animated: animated)))
func skeleton(with loading: Bool, transition: AnyTransition? = nil, animated: Animation? = nil, width: CGFloat? = nil, height: CGFloat? = nil) -> ModifiedContent<Self, SkeletonModifier> {
modifier(SkeletonModifier(skeleton: SkeletonInteractor(loading, transition: transition, animated: animated, width: width, height: height)))
}
}
2 changes: 2 additions & 0 deletions Sources/SkeletonUI/Modifiers/SkeletonModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public struct SkeletonModifier: ViewModifier {
}
}
}
.padding(skeleton.multiline.presenter.padding ?? EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
.frame(width: skeleton.presenter.width, height: skeleton.presenter.height)
.transition(skeleton.presenter.transition)
} else {
content
Expand Down
5 changes: 5 additions & 0 deletions Sources/SkeletonUI/Multiline/MultilineInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ protocol MultilineInteractable: AnyObject {
var scale: CurrentValueSubject<CGFloat, Never> { get }
var spacing: CurrentValueSubject<CGFloat?, Never> { get }
var scales: CurrentValueSubject<[Int: CGFloat]?, Never> { get }
var padding: CurrentValueSubject<EdgeInsets?, Never> { get }
}

final class MultilineInteractor: MultilineInteractable {
Expand All @@ -18,6 +19,7 @@ final class MultilineInteractor: MultilineInteractable {
let scale: CurrentValueSubject<CGFloat, Never>
let spacing: CurrentValueSubject<CGFloat?, Never>
let scales: CurrentValueSubject<[Int: CGFloat]?, Never>
let padding: CurrentValueSubject<EdgeInsets?, Never>

private var cancellables = Set<AnyCancellable>()

Expand All @@ -27,6 +29,8 @@ final class MultilineInteractor: MultilineInteractable {
scale = CurrentValueSubject<CGFloat, Never>(presenter.scale)
spacing = CurrentValueSubject<CGFloat?, Never>(presenter.spacing)
scales = CurrentValueSubject<[Int: CGFloat]?, Never>(presenter.scales)
padding = CurrentValueSubject<EdgeInsets?, Never>(presenter.padding)

line.map { [weak self] line in
guard let self = self else { fatalError() }
if let scale = self.scales.value?[line] {
Expand All @@ -37,5 +41,6 @@ final class MultilineInteractor: MultilineInteractable {
lines.assign(to: \.lines, on: presenter).store(in: &cancellables)
scales.assign(to: \.scales, on: presenter).store(in: &cancellables)
spacing.assign(to: \.spacing, on: presenter).store(in: &cancellables)
padding.assign(to: \.padding, on: presenter).store(in: &cancellables)
}
}
1 change: 1 addition & 0 deletions Sources/SkeletonUI/Multiline/MultilinePresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ final class MultilinePresenter: ObservableObject {
@Published var spacing: CGFloat?
@Published var scale: CGFloat = 1
@Published var scales: [Int: CGFloat]?
@Published var padding: EdgeInsets?
}
4 changes: 2 additions & 2 deletions Sources/SkeletonUI/Skeleton/SkeletonInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ final class SkeletonInteractor: SkeletonInteractable {
let appearance: AppearanceInteractable
let animation: AnimationInteractable

init(_ loading: Bool, transition: AnyTransition?, animated: Animation?, shape: ShapeInteractable = ShapeInteractor(), multiline: MultilineInteractable = MultilineInteractor(), appearance: AppearanceInteractable = AppearanceInteractor(), animation: AnimationInteractable = AnimationInteractor()) {
presenter = SkeletonPresenter(loading, transition: transition, animated: animated)
init(_ loading: Bool, transition: AnyTransition?, animated: Animation?, width: CGFloat?, height: CGFloat?, shape: ShapeInteractable = ShapeInteractor(), multiline: MultilineInteractable = MultilineInteractor(), appearance: AppearanceInteractable = AppearanceInteractor(), animation: AnimationInteractable = AnimationInteractor()) {
presenter = SkeletonPresenter(loading, transition: transition, animated: animated, width: width, height: height)
self.shape = shape
self.multiline = multiline
self.appearance = appearance
Expand Down
6 changes: 5 additions & 1 deletion Sources/SkeletonUI/Skeleton/SkeletonPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ final class SkeletonPresenter: ObservableObject {
@Published var loading: Bool
@Published var transition: AnyTransition
@Published var animated: Animation
@Published var width: CGFloat?
@Published var height: CGFloat?

init(_ loading: Bool, transition: AnyTransition?, animated: Animation?) {
init(_ loading: Bool, transition: AnyTransition?, animated: Animation?, width: CGFloat?, height: CGFloat?) {
self.loading = loading
self.transition = transition ?? .opacity
self.animated = animated ?? .default
self.width = width
self.height = height
}
}
6 changes: 6 additions & 0 deletions Tests/SkeletonUISnapshotTests/AutoMockable.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ class AppearanceInteractableMock: AppearanceInteractable {

}
class MultilineInteractableMock: MultilineInteractable {
var underlyingPadding: CurrentValueSubject<EdgeInsets?, Never>!
var padding: CurrentValueSubject<EdgeInsets?, Never> {
get { return underlyingPadding }
set(value) { underlyingPadding = value }
}

var presenter: MultilinePresenter {
get { return underlyingPresenter }
set(value) { underlyingPresenter = value }
Expand Down
5 changes: 5 additions & 0 deletions Tests/SkeletonUISnapshotTests/SnapshotTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ final class SnapshotTests: XCTestCase {
let view = Text(nil).skeleton(with: true).appearance(type: .solid()).shape(type: .rectangle).multiline(lines: 2, scales: [1: 0.5]).animation(type: .pulse())
assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 50)))
}

func testCustomTextWithPadding() {
let view = Text(nil).skeleton(with: true).appearance(type: .solid()).shape(type: .rectangle).multiline(lines: 2, scales: [1: 0.5], padding: EdgeInsets(top: 5, leading: 0, bottom: 5, trailing: 0)).animation(type: .pulse())
assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 60)))
}

func testDefaultImage() {
#if os(macOS)
Expand Down