From 2d801ac32c37dbefebecbb67439909288a6725c2 Mon Sep 17 00:00:00 2001
From: Kyle Van Essen <k@squareup.com>
Date: Wed, 3 Jun 2020 17:24:36 -0700
Subject: [PATCH] Support providing additional information to Item callbacks

---
 .../PresentationState.ItemState.swift         | 23 ++++++--
 Listable/Sources/Item/Item.swift              | 59 ++++++++++++++-----
 2 files changed, 63 insertions(+), 19 deletions(-)

diff --git a/Listable/Sources/Internal/Presentation State/PresentationState.ItemState.swift b/Listable/Sources/Internal/Presentation State/PresentationState.ItemState.swift
index 0526add80..86c5b386b 100644
--- a/Listable/Sources/Internal/Presentation State/PresentationState.ItemState.swift	
+++ b/Listable/Sources/Internal/Presentation State/PresentationState.ItemState.swift	
@@ -153,6 +153,9 @@ extension PresentationState
         
         private(set) var isDisplayed : Bool = false
         
+        private var hasDisplayed : Bool = false
+        private var hasEndedDisplay : Bool = false
+        
         func setAndPerform(isDisplayed: Bool) {
             guard self.isDisplayed != isDisplayed else {
                 return
@@ -161,9 +164,21 @@ extension PresentationState
             self.isDisplayed = isDisplayed
             
             if self.isDisplayed {
-                self.model.onDisplay?(self.model.content)
+                self.model.onDisplay?(.init(
+                    item: self.model,
+                    isFirstDisplay: self.hasDisplayed == false
+                    )
+                )
+                
+                self.hasDisplayed = true
             } else {
-                self.model.onEndDisplay?(self.model.content)
+                self.model.onEndDisplay?(.init(
+                    item: self.model,
+                    isFirstEndDisplay: self.hasEndedDisplay == false
+                    )
+                )
+                
+                self.hasEndedDisplay = true
             }
         }
                 
@@ -288,13 +303,13 @@ extension PresentationState
                 if isSelected {
                     if let onSelect = self.model.onSelect {
                         SignpostLogger.log(log: .listInteraction, name: "Item onSelect", for: self.model) {
-                            onSelect(self.model.content)
+                            onSelect(.init(item: self.model))
                         }
                     }
                 } else {
                     if let onDeselect = self.model.onDeselect {
                         SignpostLogger.log(log: .listInteraction, name: "Item onDeselect", for: self.model) {
-                            onDeselect(self.model.content)
+                            onDeselect(.init(item: self.model))
                         }
                     }
                 }
diff --git a/Listable/Sources/Item/Item.swift b/Listable/Sources/Item/Item.swift
index 99675537a..997037c47 100644
--- a/Listable/Sources/Item/Item.swift
+++ b/Listable/Sources/Item/Item.swift
@@ -53,17 +53,10 @@ public struct Item<Content:ItemContent> : AnyItem
 
     public var reordering : Reordering?
         
-    public typealias OnSelect = (Content) -> ()
-    public var onSelect : OnSelect?
-    
-    public typealias OnDeselect = (Content) -> ()
-    public var onDeselect : OnDeselect?
-    
-    public typealias OnDisplay = (Content) -> ()
-    public var onDisplay : OnDisplay?
-    
-    public typealias OnEndDisplay = (Content) -> ()
-    public var onEndDisplay : OnEndDisplay?
+    public var onSelect : OnSelect.Callback?
+    public var onDeselect : OnDeselect.Callback?
+    public var onDisplay : OnDisplay.Callback?
+    public var onEndDisplay : OnEndDisplay.Callback?
     
     internal let reuseIdentifier : ReuseIdentifier<Content>
     
@@ -92,10 +85,10 @@ public struct Item<Content:ItemContent> : AnyItem
         selectionStyle : ItemSelectionStyle? = nil,
         swipeActions : SwipeActionsConfiguration? = nil,
         reordering : Reordering? = nil,
-        onDisplay : OnDisplay? = nil,
-        onEndDisplay : OnEndDisplay? = nil,
-        onSelect : OnSelect? = nil,
-        onDeselect : OnDeselect? = nil
+        onDisplay : OnDisplay.Callback? = nil,
+        onEndDisplay : OnEndDisplay.Callback? = nil,
+        onSelect : OnSelect.Callback? = nil,
+        onDeselect : OnDeselect.Callback? = nil
         )
     {
         self.content = content
@@ -172,6 +165,42 @@ public struct Item<Content:ItemContent> : AnyItem
 }
 
 
+public extension Item
+{
+    struct OnSelect
+    {
+        public typealias Callback = (OnSelect) -> ()
+        
+        public var item : Item
+    }
+    
+    struct OnDeselect
+    {
+        public typealias Callback = (OnDeselect) -> ()
+
+        public var item : Item
+    }
+    
+    struct OnDisplay
+    {
+        public typealias Callback = (OnDisplay) -> ()
+
+        public var item : Item
+        
+        public var isFirstDisplay : Bool
+    }
+    
+    struct OnEndDisplay
+    {
+        public typealias Callback = (OnEndDisplay) -> ()
+
+        public var item : Item
+        
+        public var isFirstEndDisplay : Bool
+    }
+}
+
+
 /// Allows specifying default properties to apply to an item when it is initialized,
 /// if those values are not provided to the initializer.
 /// Only non-nil values are used – if you do not want to provide a default value,