Skip to content

Commit 76d8858

Browse files
committed
Merge release/v1.8.0 into master
2 parents 9fba5a8 + 7cf2c86 commit 76d8858

File tree

10 files changed

+412
-5
lines changed

10 files changed

+412
-5
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
language: swift
22
xcode_project: ThunderBasics.xcodeproj # path to your xcodeproj folder
3-
osx_image: xcode11
3+
osx_image: xcode11.6
44
env:
55
global:
66
- LC_CTYPE=en_US.UTF-8
77
- LANG=en_US.UTF-8
88
matrix:
99
include:
1010
- xcode_scheme: ThunderBasics-iOS
11-
xcode_destination: platform=iOS Simulator,OS=13.0,name=iPhone 11 Pro Max
11+
xcode_destination: platform=iOS Simulator,OS=13.6,name=iPhone 11 Pro Max
1212
- xcode_scheme: ThunderBasics-macOS
1313
xcode_destination: platform=macOS

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Setting up your app to use ThunderBasics is a simple and quick process. You can
1010

1111
## Carthage
1212

13-
- Add `github "3sidedcube/ThunderBasics" == 1.7.0` to your Cartfile.
13+
- Add `github "3sidedcube/ThunderBasics" == 1.8.0` to your Cartfile.
1414
- Run `carthage update --platform ios` to fetch the framework.
1515
- Drag `ThunderBasics` into your project's _Linked Frameworks and Libraries_ section from the `Carthage/Build` folder.
1616
- Add the Build Phases script step as defined [here](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos).

ThunderBasics.xcodeproj/project.pbxproj

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
980AE1D6220896A700540E8E /* iso639_2.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 980AE1D5220896A700540E8E /* iso639_2.bundle */; };
1818
980AE269220AFD8C00540E8E /* Locale+ISO639_2Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 980AE268220AFD8C00540E8E /* Locale+ISO639_2Tests.swift */; };
1919
980AE26B220AFF7400540E8E /* ThunderBasics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C272EF8419C831AB004BD339 /* ThunderBasics.framework */; };
20+
B100A84924C9AF6800562777 /* MultipleShadowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B100A84824C9AF6800562777 /* MultipleShadowView.swift */; };
21+
B100A84B24C9AF6C00562777 /* ShadowComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = B100A84A24C9AF6C00562777 /* ShadowComponents.swift */; };
22+
B100A85124C9AF7400562777 /* CALayer+CornerCurve.swift in Sources */ = {isa = PBXBuildFile; fileRef = B100A84C24C9AF7300562777 /* CALayer+CornerCurve.swift */; };
23+
B100A85224C9AF7400562777 /* CALayer+Shadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B100A84D24C9AF7400562777 /* CALayer+Shadow.swift */; };
24+
B100A85324C9AF7400562777 /* UIView+CornerCurve.swift in Sources */ = {isa = PBXBuildFile; fileRef = B100A84E24C9AF7400562777 /* UIView+CornerCurve.swift */; };
25+
B100A85524C9AF7400562777 /* UIView+MultipleShadows.swift in Sources */ = {isa = PBXBuildFile; fileRef = B100A85024C9AF7400562777 /* UIView+MultipleShadows.swift */; };
2026
B10F06C324B4B3EA00B3F8BC /* nebraska.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B10F06C224B4B3EA00B3F8BC /* nebraska.jpg */; };
2127
B10F06C524B4C01300B3F8BC /* mit.png in Resources */ = {isa = PBXBuildFile; fileRef = B10F06C424B4C01300B3F8BC /* mit.png */; };
2228
B11063B41F41ABC6003E5814 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11063B31F41ABC6003E5814 /* Navigation.swift */; };
@@ -115,6 +121,12 @@
115121
980AE1D32208968800540E8E /* Locale+ISO639_2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Locale+ISO639_2.swift"; sourceTree = "<group>"; };
116122
980AE1D5220896A700540E8E /* iso639_2.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = iso639_2.bundle; sourceTree = "<group>"; };
117123
980AE268220AFD8C00540E8E /* Locale+ISO639_2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Locale+ISO639_2Tests.swift"; sourceTree = "<group>"; };
124+
B100A84824C9AF6800562777 /* MultipleShadowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipleShadowView.swift; sourceTree = "<group>"; };
125+
B100A84A24C9AF6C00562777 /* ShadowComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShadowComponents.swift; sourceTree = "<group>"; };
126+
B100A84C24C9AF7300562777 /* CALayer+CornerCurve.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CALayer+CornerCurve.swift"; sourceTree = "<group>"; };
127+
B100A84D24C9AF7400562777 /* CALayer+Shadow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CALayer+Shadow.swift"; sourceTree = "<group>"; };
128+
B100A84E24C9AF7400562777 /* UIView+CornerCurve.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+CornerCurve.swift"; sourceTree = "<group>"; };
129+
B100A85024C9AF7400562777 /* UIView+MultipleShadows.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+MultipleShadows.swift"; sourceTree = "<group>"; };
118130
B10F06C224B4B3EA00B3F8BC /* nebraska.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = nebraska.jpg; sourceTree = "<group>"; };
119131
B10F06C424B4C01300B3F8BC /* mit.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mit.png; sourceTree = "<group>"; };
120132
B11063B31F41ABC6003E5814 /* Navigation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Navigation.swift; sourceTree = "<group>"; };
@@ -296,6 +308,13 @@
296308
name = Frameworks;
297309
sourceTree = "<group>";
298310
};
311+
B100A84724C9AF3C00562777 /* Shadows */ = {
312+
isa = PBXGroup;
313+
children = (
314+
);
315+
name = Shadows;
316+
sourceTree = "<group>";
317+
};
299318
B120905B1BBABE9500AAB2E9 /* Core Spotlighting */ = {
300319
isa = PBXGroup;
301320
children = (
@@ -307,9 +326,11 @@
307326
B12BD5DE1C48043600D07A58 /* Views */ = {
308327
isa = PBXGroup;
309328
children = (
329+
B100A84724C9AF3C00562777 /* Shadows */,
310330
B1E6FC1F218B608C00971DC3 /* HUDActivityView.swift */,
311331
B12BD5DF1C48052000D07A58 /* LoadingButton.swift */,
312332
B1B6CFA71C4E5BC300CDC978 /* DesignableView.swift */,
333+
B100A84824C9AF6800562777 /* MultipleShadowView.swift */,
313334
);
314335
name = Views;
315336
sourceTree = "<group>";
@@ -353,13 +374,18 @@
353374
B1B6CF931C4E482000CDC978 /* Views and Layers */ = {
354375
isa = PBXGroup;
355376
children = (
377+
B100A84A24C9AF6C00562777 /* ShadowComponents.swift */,
378+
B100A85024C9AF7400562777 /* UIView+MultipleShadows.swift */,
356379
B13778DC20289820006FE6D5 /* UIView+AutoLayout.swift */,
357380
B146C3B921906B8A00A1DBCD /* UIView+Frame.swift */,
358381
B1FA1794230EE22C00AB9891 /* UIView+IntrinsicContentSize.swift */,
359382
B146C3BB219071F700A1DBCD /* UIView+Pop.swift */,
360383
B146C3BD21908A6700A1DBCD /* UILabel+SizeToFit.swift */,
361384
B146C3BF21908AFA00A1DBCD /* CAGradientLayer+AutoGradient.swift */,
385+
B100A84D24C9AF7400562777 /* CALayer+Shadow.swift */,
362386
B834866023D9E93B00F52BA6 /* UIView+Shadow.swift */,
387+
B100A84C24C9AF7300562777 /* CALayer+CornerCurve.swift */,
388+
B100A84E24C9AF7400562777 /* UIView+CornerCurve.swift */,
363389
);
364390
name = "Views and Layers";
365391
sourceTree = "<group>";
@@ -733,6 +759,7 @@
733759
files = (
734760
B1E6FC30218C5D3600971DC3 /* Toast.swift in Sources */,
735761
B13779322029F7EF006FE6D5 /* JSONSerialization+FromFile.swift in Sources */,
762+
B100A85524C9AF7400562777 /* UIView+MultipleShadows.swift in Sources */,
736763
B1E6FC4B218CAA8800971DC3 /* UIImage+Effects.swift in Sources */,
737764
B1E6FC2B218C4EF100971DC3 /* CoreSpotlightIndexable.swift in Sources */,
738765
B1E6FC34218C65B300971DC3 /* ToastViewController.swift in Sources */,
@@ -743,6 +770,7 @@
743770
B1B6CF8E1C4E47DB00CDC978 /* NSObject+AddedProperties.m in Sources */,
744771
B1E6FC20218B608C00971DC3 /* HUDActivityView.swift in Sources */,
745772
B1E6FC4D218CABF900971DC3 /* UIImage+Crop.swift in Sources */,
773+
B100A84B24C9AF6C00562777 /* ShadowComponents.swift in Sources */,
746774
B1D791FD1CBD58BA00EE5D45 /* UIApplication+NetworkActivityIndicator.m in Sources */,
747775
B1D15F6B2360A18D0086E23F /* CarouselAccessibilityElement.swift in Sources */,
748776
B146C3D12190A1AC00A1DBCD /* UIColor+Helpers.swift in Sources */,
@@ -763,19 +791,23 @@
763791
B13778DD20289820006FE6D5 /* UIView+AutoLayout.swift in Sources */,
764792
B1E6FC32218C5D9A00971DC3 /* ToastView.swift in Sources */,
765793
B146C3B62190570C00A1DBCD /* UIImage+Resize.swift in Sources */,
794+
B100A84924C9AF6800562777 /* MultipleShadowView.swift in Sources */,
766795
B12BD5E01C48052000D07A58 /* LoadingButton.swift in Sources */,
767796
B11063B41F41ABC6003E5814 /* Navigation.swift in Sources */,
768797
B146C3F32191E47600A1DBCD /* NSDateFormatter+Strftime.swift in Sources */,
769798
B146C3E42191D36A00A1DBCD /* UIViewController+DismissAnimated.swift in Sources */,
770799
B1E6FC49218C729500971DC3 /* UIColor+Comparison.swift in Sources */,
771800
B146C3BA21906B8A00A1DBCD /* UIView+Frame.swift in Sources */,
801+
B100A85124C9AF7400562777 /* CALayer+CornerCurve.swift in Sources */,
802+
B100A85224C9AF7400562777 /* CALayer+Shadow.swift in Sources */,
772803
B1898CD1230D7A9000A1F5D1 /* AccessibilityRefreshingViewController.swift in Sources */,
773804
B152AC501F20BF020079372B /* DateHelpers.swift in Sources */,
774805
49CF13291AB6D88A00AA5971 /* TSCContactsController.m in Sources */,
775806
B834865923D9E47A00F52BA6 /* UIEdgeInsets+Extensions.swift in Sources */,
776807
B146C3E22191CB2400A1DBCD /* UIWindow+VisibleViewController.swift in Sources */,
777808
B834865F23D9E89F00F52BA6 /* String+Extensions.swift in Sources */,
778809
B146C3C221908FB900A1DBCD /* UIColor+HexString.swift in Sources */,
810+
B100A85324C9AF7400562777 /* UIView+CornerCurve.swift in Sources */,
779811
B1E6FC36218C6BC000971DC3 /* ToastNotificationController.swift in Sources */,
780812
B834865D23D9E62E00F52BA6 /* DateFormatter+Extensions.swift in Sources */,
781813
);
@@ -1048,7 +1080,7 @@
10481080
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
10491081
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
10501082
MACH_O_TYPE = mh_dylib;
1051-
MARKETING_VERSION = 1.7.0;
1083+
MARKETING_VERSION = 1.8.0;
10521084
ONLY_ACTIVE_ARCH = NO;
10531085
PRODUCT_BUNDLE_IDENTIFIER = "com.threesidedcube.$(PRODUCT_NAME:rfc1034identifier)";
10541086
PRODUCT_NAME = ThunderBasics;
@@ -1077,7 +1109,7 @@
10771109
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
10781110
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
10791111
MACH_O_TYPE = mh_dylib;
1080-
MARKETING_VERSION = 1.7.0;
1112+
MARKETING_VERSION = 1.8.0;
10811113
PRODUCT_BUNDLE_IDENTIFIER = "com.threesidedcube.$(PRODUCT_NAME:rfc1034identifier)";
10821114
PRODUCT_NAME = ThunderBasics;
10831115
SKIP_INSTALL = YES;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// CALayer+CornerCurve.swift
3+
// ShadowView
4+
//
5+
// Created by Simon Mitchell on 23/07/2020.
6+
// Copyright © 2020 3 Sided Cube. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
public extension CALayer {
12+
13+
var viewCornerCurve: UIViewCornerCurve {
14+
set {
15+
if #available(iOS 13, *) {
16+
cornerCurve = newValue.layerCornerCurve
17+
}
18+
}
19+
get {
20+
if #available(iOS 13, *) {
21+
return UIViewCornerCurve(cornerCurve)
22+
}
23+
return .circular
24+
}
25+
}
26+
}

ThunderBasics/CALayer+Shadow.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// CALayer+Shadow.swift
3+
// ShadowView
4+
//
5+
// Created by Simon Mitchell on 23/07/2020.
6+
// Copyright © 2020 3 Sided Cube. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
extension CALayer {
12+
13+
/// A variable that allows you to set the shadow of a layer simply using `ShadowComponents`
14+
var shadow: ShadowComponents? {
15+
set {
16+
guard let newValue = newValue else {
17+
shadowColor = UIColor.black.cgColor
18+
shadowOpacity = 0
19+
shadowOffset = CGSize(width: 0, height: -3)
20+
shadowRadius = 3
21+
return
22+
}
23+
shadowRadius = newValue.radius
24+
shadowOpacity = newValue.opacity
25+
shadowColor = newValue.color.cgColor
26+
shadowOffset = newValue.offset
27+
}
28+
get {
29+
guard let shadowColor = shadowColor else {
30+
return nil
31+
}
32+
let color = UIColor(cgColor: shadowColor)
33+
return ShadowComponents(
34+
radius: shadowRadius,
35+
opacity: shadowOpacity,
36+
color: color,
37+
offset: shadowOffset
38+
)
39+
}
40+
}
41+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//
2+
// MultipleShadowView.swift
3+
// ShadowView
4+
//
5+
// Created by Simon Mitchell on 23/07/2020.
6+
// Copyright © 2020 3 Sided Cube. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
12+
protocol CornerObservableLayerDelegate: class {
13+
14+
func cornerObservableLayer(_ layer: CornerObservableLayer, didUpdateCornerRadius cornerRadius: CGFloat)
15+
16+
func cornerObservableLayer(_ layer: CornerObservableLayer, didUpdateCornerCurve cornerCurve: CALayerCornerCurve)
17+
}
18+
19+
internal class CornerObservableLayer: CALayer {
20+
21+
/// Delegate for corner property changes
22+
weak var cornerDelegate: CornerObservableLayerDelegate?
23+
24+
override var cornerRadius: CGFloat {
25+
didSet {
26+
cornerDelegate?.cornerObservableLayer(self, didUpdateCornerRadius: cornerRadius)
27+
}
28+
}
29+
30+
override var cornerCurve: CALayerCornerCurve {
31+
didSet {
32+
cornerDelegate?.cornerObservableLayer(self, didUpdateCornerCurve: cornerCurve)
33+
}
34+
}
35+
}
36+
37+
/// A subclass of `UIView` which ensures multiple shadows have their
38+
/// bounds, and corner radius properties updated when the parent view's properties
39+
/// change.
40+
public class MultipleShadowView: UIView {
41+
42+
public override class var layerClass: AnyClass {
43+
return CornerObservableLayer.self
44+
}
45+
46+
public override var backgroundColor: UIColor? {
47+
didSet {
48+
forEachShadowLayer { (shadowLayer) in
49+
shadowLayer.backgroundColor = layer.backgroundColor
50+
}
51+
}
52+
}
53+
54+
/// Whether the shadow layers should update their corner radius to match the view's
55+
/// layer's corner radius
56+
public var matchShadowCornerRadius: Bool = true {
57+
didSet {
58+
guard matchShadowCornerRadius else { return }
59+
forEachShadowLayer { (shadowLayer) in
60+
shadowLayer.cornerRadius = layer.cornerRadius
61+
}
62+
}
63+
}
64+
65+
/// Whether the shadow layers should update their corner curve to match the view's
66+
/// layer's corner curve
67+
public var matchShadowCornerCurve: Bool = true {
68+
didSet {
69+
guard matchShadowCornerCurve else { return }
70+
if #available(iOS 13.0, *) {
71+
forEachShadowLayer { (shadowLayer) in
72+
shadowLayer.cornerCurve = layer.cornerCurve
73+
}
74+
}
75+
}
76+
}
77+
78+
public override init(frame: CGRect) {
79+
super.init(frame: frame)
80+
(layer as? CornerObservableLayer)?.cornerDelegate = self
81+
}
82+
83+
public required init?(coder: NSCoder) {
84+
super.init(coder: coder)
85+
(layer as? CornerObservableLayer)?.cornerDelegate = self
86+
}
87+
88+
override public func layoutSubviews() {
89+
super.layoutSubviews()
90+
forEachShadowLayer { (shadowLayer) in
91+
shadowLayer.frame = bounds
92+
}
93+
}
94+
}
95+
96+
extension MultipleShadowView: CornerObservableLayerDelegate {
97+
98+
func cornerObservableLayer(_ layer: CornerObservableLayer, didUpdateCornerRadius cornerRadius: CGFloat) {
99+
guard matchShadowCornerRadius else { return }
100+
forEachShadowLayer { (shadowLayer) in
101+
shadowLayer.cornerRadius = cornerRadius
102+
}
103+
}
104+
105+
func cornerObservableLayer(_ layer: CornerObservableLayer, didUpdateCornerCurve cornerCurve: CALayerCornerCurve) {
106+
guard matchShadowCornerCurve else { return }
107+
if #available(iOS 13.0, *) {
108+
forEachShadowLayer { (shadowLayer) in
109+
shadowLayer.cornerCurve = layer.cornerCurve
110+
}
111+
}
112+
}
113+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// ShadowComponents.swift
3+
// ShadowView
4+
//
5+
// Created by Simon Mitchell on 23/07/2020.
6+
// Copyright © 2020 3 Sided Cube. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
/// Component representation of all properties required to render a shadow in UIKit
12+
public struct ShadowComponents {
13+
14+
/// The system default shadow
15+
public static let systemDefault: ShadowComponents = .init(
16+
radius: 3,
17+
opacity: 0,
18+
color: .black,
19+
offset: .init(width: 0, height: -3)
20+
)
21+
22+
/// The blur radius of the shadow
23+
public let radius: CGFloat
24+
25+
/// The opacity of the shadow
26+
public let opacity: Float
27+
28+
/// The color of the shadow
29+
public let color: UIColor
30+
31+
/// The offset of the shadow
32+
public let offset: CGSize
33+
34+
/// Default memberwise initialiser for the components
35+
/// - Parameters:
36+
/// - radius: The blur radius of the shadow
37+
/// - opacity: The opacity of the shadow
38+
/// - color: The color of the shadow
39+
/// - offset: The offset of the shadow
40+
public init(radius: CGFloat, opacity: Float, color: UIColor, offset: CGSize) {
41+
self.radius = radius
42+
self.opacity = opacity
43+
self.color = color
44+
self.offset = offset
45+
}
46+
}

0 commit comments

Comments
 (0)