Skip to content

Commit

Permalink
Initial commit: Make elements easier to use
Browse files Browse the repository at this point in the history
  • Loading branch information
kyleve committed Jul 25, 2022
1 parent 05cbbfe commit 16ce47b
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
68 changes: 68 additions & 0 deletions BlueprintUILists/Sources/Element.swift
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
}
}
91 changes: 91 additions & 0 deletions ListableUI/Sources/IsEquivalent/IsEquivalentContent.swift
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
}
}

0 comments on commit 16ce47b

Please sign in to comment.