-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit: Make elements easier to use
- Loading branch information
Showing
2 changed files
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// | ||
// Element.swift | ||
// BlueprintUILists | ||
// | ||
// Created by Kyle Van Essen on 7/24/22. | ||
// | ||
|
||
import BlueprintUI | ||
import ListableUI | ||
|
||
|
||
// MARK: Item / ItemContent Extensions | ||
|
||
extension Element { | ||
|
||
func asItem( | ||
configure : (inout Item<WrappedElementContent<Self, ObjectIdentifier>>) -> () = { _ in } | ||
) -> Item<WrappedElementContent<Self, ObjectIdentifier>> { | ||
Item( | ||
WrappedElementContent( | ||
represented: self, | ||
identifierValue: ObjectIdentifier(Self.Type.self) | ||
), | ||
configure: configure | ||
) | ||
} | ||
|
||
func asItem<ID:Hashable>( | ||
id : ID, | ||
configure : (inout Item<WrappedElementContent<Self, ID>>) -> () = { _ in } | ||
) -> Item<WrappedElementContent<Self, ID>> { | ||
Item( | ||
WrappedElementContent( | ||
represented: self, | ||
identifierValue: id | ||
), | ||
configure: configure | ||
) | ||
} | ||
} | ||
|
||
|
||
public struct WrappedElementContent<ElementType:Element, IdentifierValue:Hashable> : BlueprintItemContent | ||
{ | ||
public let represented : ElementType | ||
|
||
public let identifierValue: IdentifierValue | ||
|
||
public func isEquivalent(to other: Self) -> Bool { | ||
false | ||
} | ||
|
||
public func element(with info: ApplyItemContentInfo) -> Element { | ||
represented | ||
} | ||
} | ||
|
||
|
||
extension WrappedElementContent where ElementType : Equatable { | ||
|
||
public func isEquivalent(to other: Self) -> Bool { | ||
represented == other.represented | ||
} | ||
|
||
public var reappliesToVisibleView: ReappliesToVisibleView { | ||
.ifNotEquivalent | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// | ||
// IsEquivalentContent.swift | ||
// ListableUI | ||
// | ||
// Created by Kyle Van Essen on 11/28/21. | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
/// Used by the list to determine when the content of content has changed; in order to | ||
/// remeasure the content and re-layout the list. | ||
/// | ||
/// Please see ``IsEquivalentContent/isEquivalent(to:)-15tcq`` for a full discussion of | ||
/// correct (and incorrect) implementation and usages. | ||
public protocol IsEquivalentContent { | ||
|
||
/// | ||
/// Used by the list to determine when the content of content has changed; in order to | ||
/// remeasure the content and re-layout the list. | ||
/// | ||
/// You should return `false` from this method when any values within your content that | ||
/// affects visual appearance or layout (and in particular, sizing) changes. When the list | ||
/// receives `false` back from this method, it will invalidate any cached sizing it has stored | ||
/// for the content, and re-measure + re-layout the content. | ||
/// | ||
/// ## ⚠️ Important | ||
/// `isEquivalent(to:)` is **not** an identifier check. That is what the `identifierValue` | ||
/// on your `ItemContent` is for. It is to determine when content has meaningfully changed. | ||
/// | ||
/// ## 🤔 Examples & How To | ||
/// | ||
/// ```swift | ||
/// struct MyItemContent : ItemContent, Equatable { | ||
/// | ||
/// var identifierValue : UUID | ||
/// var title : String | ||
/// var detail : String | ||
/// var theme : MyTheme | ||
/// var onTapDetail : () -> () | ||
/// | ||
/// func isEquivalent(to other : MyItemContent) -> Bool { | ||
/// // 🚫 Missing checks for title and detail. | ||
/// // If they change, they likely affect sizing, | ||
/// // which would result in incorrect item sizing. | ||
/// | ||
/// self.theme == other.theme | ||
/// } | ||
/// | ||
/// func isEquivalent(to other : MyItemContent) -> Bool { | ||
/// // 🚫 Missing check for theme. | ||
/// // If the theme changed; its likely that the device's | ||
/// // accessibility settings changed; dark mode was enabled, | ||
/// // etc. All of these can affect the appearance or sizing | ||
/// // of the item. | ||
/// | ||
/// self.title == other.title && | ||
/// self.detail == other.detail | ||
/// } | ||
/// | ||
/// func isEquivalent(to other : MyItemContent) -> Bool { | ||
/// // ✅ Checking all parameters which can affect appearance + layout. | ||
/// // 💡 Not checking identifierValue or onTapDetail, since they do not affect appearance + layout. | ||
/// | ||
/// self.theme == other.theme && | ||
/// self.title == other.title && | ||
/// self.detail == other.detail | ||
/// } | ||
/// } | ||
/// | ||
/// struct MyItemContent : ItemContent, Equatable { | ||
/// // ✅ Nothing else needed! | ||
/// // `Equatable` conformance provides `isEquivalent(to:) for free!` | ||
/// } | ||
/// ``` | ||
/// | ||
/// ## Note | ||
/// If your ``ItemContent`` conforms to ``Equatable``, there is a default | ||
/// implementation of this method which simply returns `self == other`. | ||
/// | ||
func isEquivalent(to other : Self) -> Bool | ||
} | ||
|
||
|
||
public extension IsEquivalentContent where Self:Equatable | ||
{ | ||
/// If your content is `Equatable`, `isEquivalent` is based on the `Equatable` implementation. | ||
func isEquivalent(to other : Self) -> Bool { | ||
self == other | ||
} | ||
} |