Skip to content
This repository has been archived by the owner on Jul 16, 2023. It is now read-only.

Add ability to filter randomly selected gradients #1

Merged
merged 5 commits into from
Oct 16, 2018
Merged
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
23 changes: 23 additions & 0 deletions Sources/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
disabled_rules:
- trailing_whitespace
- vertical_whitespace
- line_length
- opening_brace
- large_tuple
- generic_type_name
- multiple_closures_with_trailing_closure

opt_in_rules:
- closure_spacing
- conditional_returns_on_newline
#- empty_count
- explicit_init
#- force_unwrapping // THIS SHOULD BE USED
#- missing_docs
- overridden_super_call
- private_outlet
- redundant_nil_coalesing
#- switch_case_on_newline

excluded:
- gen
45 changes: 38 additions & 7 deletions Sources/Randient.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
464BE4E321455020009B2A0D /* Randient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 464BE4E221455020009B2A0D /* Randient.swift */; };
468EE01C2166A5A400C27982 /* RandientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 468EE01B2166A5A400C27982 /* RandientTests.swift */; };
468EE01E2166A5A400C27982 /* Randient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4639DD4C21451CFA0038E5A6 /* Randient.framework */; };
46DBB9CE21516B290094B965 /* UIGradient+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DBB9CD21516B290094B965 /* UIGradient+Metadata.swift */; };
46DBB9D8215173D40094B965 /* UIColor+Analysis.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DBB9D4215173D40094B965 /* UIColor+Analysis.swift */; };
46DBB9D9215173D40094B965 /* RandientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DBB9D6215173D40094B965 /* RandientView.swift */; };
46DBB9DA215173D40094B965 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DBB9D7215173D40094B965 /* GradientView.swift */; };
46DBB9DC215173E40094B965 /* UIColor+Interpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46DBB9DB215173E40094B965 /* UIColor+Interpolation.swift */; };
46E057A42175F2F1003FB809 /* UIGradientFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46E057A22175F2F1003FB809 /* UIGradientFilter.swift */; };
46E057A52175F2F1003FB809 /* UIGradient+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46E057A32175F2F1003FB809 /* UIGradient+Metadata.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -40,11 +41,12 @@
468EE0192166A5A400C27982 /* RandientTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RandientTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
468EE01B2166A5A400C27982 /* RandientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandientTests.swift; sourceTree = "<group>"; };
468EE01D2166A5A400C27982 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
46DBB9CD21516B290094B965 /* UIGradient+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGradient+Metadata.swift"; sourceTree = "<group>"; };
46DBB9D4215173D40094B965 /* UIColor+Analysis.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Analysis.swift"; sourceTree = "<group>"; };
46DBB9D6215173D40094B965 /* RandientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandientView.swift; sourceTree = "<group>"; };
46DBB9D7215173D40094B965 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = "<group>"; };
46DBB9DB215173E40094B965 /* UIColor+Interpolation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Interpolation.swift"; sourceTree = "<group>"; };
46E057A22175F2F1003FB809 /* UIGradientFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIGradientFilter.swift; sourceTree = "<group>"; };
46E057A32175F2F1003FB809 /* UIGradient+Metadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIGradient+Metadata.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -98,7 +100,7 @@
children = (
4639DD4F21451CFA0038E5A6 /* Randient.h */,
464BE4E221455020009B2A0D /* Randient.swift */,
46DBB9CD21516B290094B965 /* UIGradient+Metadata.swift */,
46E057A12175F2F1003FB809 /* Gradient */,
46DBB9D5215173D40094B965 /* Views */,
46DBB9D3215173D40094B965 /* Extensions */,
4639DD5021451CFA0038E5A6 /* Info.plist */,
Expand Down Expand Up @@ -134,6 +136,15 @@
path = Views;
sourceTree = "<group>";
};
46E057A12175F2F1003FB809 /* Gradient */ = {
isa = PBXGroup;
children = (
46E057A22175F2F1003FB809 /* UIGradientFilter.swift */,
46E057A32175F2F1003FB809 /* UIGradient+Metadata.swift */,
);
path = Gradient;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand All @@ -152,7 +163,8 @@
isa = PBXNativeTarget;
buildConfigurationList = 4639DD5421451CFA0038E5A6 /* Build configuration list for PBXNativeTarget "Randient" */;
buildPhases = (
46FB496A21453142005363F7 /* Load Latest Gradients */,
46E057A62175F5E3003FB809 /* SwiftLint */,
46FB496A21453142005363F7 /* Generate Gradients */,
4639DD4721451CFA0038E5A6 /* Sources */,
4639DD4821451CFA0038E5A6 /* Frameworks */,
4639DD4921451CFA0038E5A6 /* Headers */,
Expand Down Expand Up @@ -240,14 +252,32 @@
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
46FB496A21453142005363F7 /* Load Latest Gradients */ = {
46E057A62175F5E3003FB809 /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = SwiftLint;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nfi\n";
};
46FB496A21453142005363F7 /* Generate Gradients */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Load Latest Gradients";
name = "Generate Gradients";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -263,10 +293,11 @@
files = (
4622FF9D216755D400214563 /* UIGradient.swift in Sources */,
46DBB9DC215173E40094B965 /* UIColor+Interpolation.swift in Sources */,
46DBB9CE21516B290094B965 /* UIGradient+Metadata.swift in Sources */,
46DBB9D8215173D40094B965 /* UIColor+Analysis.swift in Sources */,
46DBB9DA215173D40094B965 /* GradientView.swift in Sources */,
46E057A52175F2F1003FB809 /* UIGradient+Metadata.swift in Sources */,
464BE4E321455020009B2A0D /* Randient.swift in Sources */,
46E057A42175F2F1003FB809 /* UIGradientFilter.swift in Sources */,
46DBB9D9215173D40094B965 /* RandientView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
1 change: 0 additions & 1 deletion Sources/Randient/Extensions/UIColor+Analysis.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,3 @@ internal extension UIColor {
return brightness >= 0.5
}
}

35 changes: 35 additions & 0 deletions Sources/Randient/Gradient/UIGradientFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// UIGradientFilter.swift
// Randient
//
// Created by Merrick Sapsford on 16/10/2018.
// Copyright © 2018 UI At Six. All rights reserved.
//

import UIKit

/// Filter that can be applied to a `UIGradient`.
public final class UIGradientFilter {

// MARK: Types

public typealias Execution = (UIGradient) -> Bool

// MARK: Properties

internal let identifier = NSUUID().uuidString
internal let execution: Execution

// MARK: Init

internal init(execution: @escaping Execution) {
self.execution = execution
}
}

extension UIGradientFilter: Equatable {

public static func == (lhs: UIGradientFilter, rhs: UIGradientFilter) -> Bool {
return lhs.identifier == rhs.identifier
}
}
60 changes: 58 additions & 2 deletions Sources/Randient/Randient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,91 @@ import Foundation

public class Randient {

// MARK: Properties

/// Filters that are applied to random selection.
public private(set) static var filters = [UIGradientFilter]()

/// The last randomized gradient.
private static var lastGradient: UIGradient?

// MARK: Randomization

/// Randomly select a new gradient from `UIGradients`.
///
/// - Returns: Randomly selected gradient.
public class func randomize() -> UIGradient {
let allGradients = UIGradient.allCases
let index = Int.random(in: 0 ..< allGradients.count)

if let newGradient = verifyNewGradient(allGradients[index]) {
if let newGradient = verifyGradient(allGradients[index]) {
return newGradient
} else {
return randomize()
}
}
}

// MARK: - Verification
extension Randient {

internal class func verifyGradient(_ gradient: UIGradient) -> UIGradient? {
guard let gradient = verifyIsNewGradient(gradient) else {
return nil
}
guard checkGradient(gradient, passes: Randient.filters) else {
return nil
}

return gradient
}

/// Verify that the new gradient can be used.
///
/// Checks that it is not equal to the previously returned gradient.
///
/// - Parameter gradient: New gradient.
/// - Returns: Gradient if it can be used.
internal class func verifyNewGradient(_ gradient: UIGradient) -> UIGradient? {
internal class func verifyIsNewGradient(_ gradient: UIGradient) -> UIGradient? {
guard gradient.data.colors != lastGradient?.data.colors else {
return nil
}
guard checkGradient(gradient, passes: Randient.filters) else {
return nil
}

self.lastGradient = gradient
return gradient
}
}

// MARK: - Filtering
public extension Randient {

/// Add a new filter that is applied to the randomly selected gradients.
///
/// - Parameter filters: Execution of the filter.
public class func addFilter(that filters: @escaping UIGradientFilter.Execution) {
Randient.filters.append(UIGradientFilter(execution: filters))
}

/// Remove a filter from being applied to random selection.
///
/// - Parameter filter: Filter to remove.
public class func removeFilter(_ filter: UIGradientFilter) {
guard let index = Randient.filters.index(of: filter) else {
return
}
Randient.filters.remove(at: index)
}

internal class func checkGradient(_ gradient: UIGradient,
passes filters: [UIGradientFilter]) -> Bool {
for filter in filters {
if filter.execution(gradient) == false {
return false
}
}
return true
}
}
8 changes: 3 additions & 5 deletions Sources/Randient/Views/GradientView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ open class GradientView: UIView {
// MARK: Properties

private var gradientLayer: CAGradientLayer? {
get {
if let gradientLayer = self.layer as? CAGradientLayer {
return gradientLayer
}
return nil
if let gradientLayer = self.layer as? CAGradientLayer {
return gradientLayer
}
return nil
}

/// The colors that are currently active in the gradient. Animatable.
Expand Down
2 changes: 1 addition & 1 deletion Sources/RandientTests/RandientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class RandientTests: XCTestCase {

func testNewGradientVerification() {
let gradient = Randient.randomize()
let verifiedGradient = Randient.verifyNewGradient(gradient)
let verifiedGradient = Randient.verifyIsNewGradient(gradient)
XCTAssertNil(verifiedGradient)
}
}