Skip to content

Commit

Permalink
Feature request: Callback when presented and dismissed #50.
Browse files Browse the repository at this point in the history
Build bump.
  • Loading branch information
huri000 committed Jun 16, 2018
1 parent e5919f5 commit 5f8cb29
Show file tree
Hide file tree
Showing 18 changed files with 329 additions and 230 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# Change Log
Any notable changes to this project will be documented in this file.

## 0.4.2

### Features

[Feature request: Callback when presented and dismissed #50](https://github.com/huri000/SwiftEntryKit/issues/50)

- Added a `LifecycleActions` construct to `EKAttributes`. It contains the following optional callbacks: willAppear, didAppear, willDisappear, didDisappear for the currently displayed entry.
- Added an optional completion handler for `SwiftEntryKit` `dismiss` method.

## 0.4.1

### Issues Handled
Expand Down
4 changes: 2 additions & 2 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ PODS:
- Nimble (7.0.2)
- Quick (1.2.0)
- QuickLayout (2.0.2)
- SwiftEntryKit (0.4.1):
- SwiftEntryKit (0.4.2):
- QuickLayout (= 2.0.2)

DEPENDENCIES:
Expand All @@ -24,7 +24,7 @@ SPEC CHECKSUMS:
Nimble: bfe1f814edabba69ff145cb1283e04ed636a67f2
Quick: 58d203b1c5e27fff7229c4c1ae445ad7069a7a08
QuickLayout: a730730b646b231fd4ef7cffaeb1e81fe0e1ca92
SwiftEntryKit: ea33b0916c8071f6d61b5d6c0aa34a09e1ee315a
SwiftEntryKit: b330a8ce7a9433f1706877a585f8dd60b7f29f52

PODFILE CHECKSUM: edd6c2af5cc390dbf823427759474ab6c303ec9e

Expand Down
4 changes: 2 additions & 2 deletions Example/Pods/Local Podspecs/SwiftEntryKit.podspec.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Example/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

388 changes: 196 additions & 192 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Example/Pods/Target Support Files/SwiftEntryKit/Info.plist

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Example/SwiftEntryKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
143F3AAC2090B312009F3719 /* UserInteractionSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 143F3AAB2090B312009F3719 /* UserInteractionSelectionTableViewCell.swift */; };
143F3AAE2090B4E2009F3719 /* HapticFeedbackSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 143F3AAD2090B4E2009F3719 /* HapticFeedbackSelectionTableViewCell.swift */; };
143F3AB22090B7F0009F3719 /* ScrollSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 143F3AB12090B7F0009F3719 /* ScrollSelectionTableViewCell.swift */; };
144E51BD20D56E150051FDCA /* EKAttributes+Completion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144E51BC20D56E150051FDCA /* EKAttributes+Completion.swift */; };
144E51BD20D56E150051FDCA /* EKAttributes+LifecycleActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144E51BC20D56E150051FDCA /* EKAttributes+LifecycleActions.swift */; };
145F56B820B84ACA0027EB67 /* EKAttributes+StatusBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 145F56B720B84ACA0027EB67 /* EKAttributes+StatusBar.swift */; };
145F56BB20B863220027EB67 /* UIApplication+EKAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 145F56BA20B863220027EB67 /* UIApplication+EKAppearance.swift */; };
14665621209204A5008FB96D /* AnimationSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14665620209204A5008FB96D /* AnimationSelectionTableViewCell.swift */; };
Expand Down Expand Up @@ -208,7 +208,7 @@
143F3AAB2090B312009F3719 /* UserInteractionSelectionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInteractionSelectionTableViewCell.swift; sourceTree = "<group>"; };
143F3AAD2090B4E2009F3719 /* HapticFeedbackSelectionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedbackSelectionTableViewCell.swift; sourceTree = "<group>"; };
143F3AB12090B7F0009F3719 /* ScrollSelectionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollSelectionTableViewCell.swift; sourceTree = "<group>"; };
144E51BC20D56E150051FDCA /* EKAttributes+Completion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EKAttributes+Completion.swift"; sourceTree = "<group>"; };
144E51BC20D56E150051FDCA /* EKAttributes+LifecycleActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EKAttributes+LifecycleActions.swift"; sourceTree = "<group>"; };
14580CCA20B7F4FB001AF703 /* DemoAppInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = DemoAppInfo.plist; sourceTree = "<group>"; };
145F56B720B84ACA0027EB67 /* EKAttributes+StatusBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EKAttributes+StatusBar.swift"; sourceTree = "<group>"; };
145F56BA20B863220027EB67 /* UIApplication+EKAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+EKAppearance.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -466,7 +466,7 @@
isa = PBXGroup;
children = (
14B48B3120B81C9700CE3EF4 /* EKAttributes.swift */,
144E51BC20D56E150051FDCA /* EKAttributes+Completion.swift */,
144E51BC20D56E150051FDCA /* EKAttributes+LifecycleActions.swift */,
14B48B3620B81C9700CE3EF4 /* EKAttributes+Animation.swift */,
14B48B3C20B81C9700CE3EF4 /* EKAttributes+BackgroundStyle.swift */,
14B48B2F20B81C9700CE3EF4 /* EKAttributes+Count.swift */,
Expand Down Expand Up @@ -992,7 +992,7 @@
14B48B7120B81C9700CE3EF4 /* EKAttributes+Animation.swift in Sources */,
14B3A51A20C16E44002306C4 /* EKRatingSymbolsContainerView.swift in Sources */,
14B48B8820B81C9700CE3EF4 /* EKMessageContentView.swift in Sources */,
144E51BD20D56E150051FDCA /* EKAttributes+Completion.swift in Sources */,
144E51BD20D56E150051FDCA /* EKAttributes+LifecycleActions.swift in Sources */,
14B48B6F20B81C9700CE3EF4 /* EKAttributes+Validations.swift in Sources */,
14B48B6620B81C9700CE3EF4 /* UIView+Shadow.swift in Sources */,
14B48B7A20B81C9700CE3EF4 /* EKPopUpMessage.swift in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions Example/SwiftEntryKit/Presets/PresetsData/PresetsDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,23 @@ struct PresetsDataSource {
attributes.entryBackground = .color(color: .satCyan)
attributes.shadow = .active(with: .init(color: .darkChatMessage, opacity: 0.5, radius: 2))
attributes.statusBar = .light

attributes.lifecycleEvents.willAppear = {
print("will appear action goes here")
}

attributes.lifecycleEvents.didAppear = {
print("did appear action goes here")
}

attributes.lifecycleEvents.willDisappear = {
print("will disappear action goes here")
}

attributes.lifecycleEvents.didDisappear = {
print("did disappear action goes here")
}

descriptionString = "Absorbs (swallows) touches and the status bar becomes light"
descriptionThumb = ThumbDesc.topNote.rawValue
description = .init(with: attributes, title: "Top Standard Note", description: descriptionString, thumb: descriptionThumb)
Expand Down
4 changes: 3 additions & 1 deletion Example/SwiftEntryKit/Presets/PresetsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ class PresetsViewController: UIViewController {
let closeButtonLabelStyle = EKProperty.LabelStyle(font: mediumFont, color: grayColor)
let closeButtonLabel = EKProperty.LabelContent(text: "Dismiss", style: closeButtonLabelStyle)
let closeButton = EKProperty.ButtonContent(label: closeButtonLabel, backgroundColor: .clear, highlightedBackgroundColor: grayColor.withAlphaComponent(0.05)) {
SwiftEntryKit.dismiss()
SwiftEntryKit.dismiss {
// Here you may perform a completion handler
}
}

// Ok Button - Make transition to a new entry when the button is tapped
Expand Down
43 changes: 38 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* [User Interaction](#user-interaction)
* [Scroll Behavior](#scroll-behavior)
* [Haptic Feedback](#haptic-feedback)
* [Lifecycle Events](#lifecycle-events)
* [Background Style](#background-style)
* [Shadow](#shadow)
* [Round Corners](#round-corners)
Expand Down Expand Up @@ -55,15 +56,16 @@ Banners or Pop-Ups are called *Entries*.
- The entries are displayed in a separated UIWindow (of type EKWindow), so the user is able to navigate the app freely while entries are being displayed in a non intrusive manner.
- The kit offers some beautiful [presets](#presets) that can be themed with your app colors and fonts.
- **Customization**: Entries are highly customizable
- [x] Can be displayed at the top or the bottom of the screen.
- [x] Can be displayed either at the top, center, or the bottom of the screen.
- [x] Can be displayed within or outside the screen's safe area.
- [x] Can be stylized: have a border, drop-shadow and round corners.
- [x] Their content's and the screen's background can be blurred, dimmed, colored or have a gradient style.
- [x] Transition animations are customizable - Entrance, Exit and Pop (by another entry).
- [x] The user interactions with the entry or the screen can be intercepted.
- [x] Entries have an optional rubber banding effect in panning.
- [x] Entries can be optionally dismissed by a simple swipe gesture.
- [x] Entries can be optionally dismissed using a simple swipe gesture.
- [x] Entries have display priority attribute. That means that an entry can be dismissed only be other entry with equal or higher priority.
- [x] Entries can be optionally injected with lifecycle events: *will* and *did* appear/disappear.
- [x] The status bar style is settable for the display duration of the entry.
- [x] SwiftEntryKit supports [custom views](#custom-view-usage-example) as well.

Expand Down Expand Up @@ -128,7 +130,7 @@ source 'https://github.com/cocoapods/specs.git'
platform :ios, '9.0'
use_frameworks!

pod 'SwiftEntryKit', '0.4.1'
pod 'SwiftEntryKit', '0.4.2'
```

Then, run the following command:
Expand All @@ -151,7 +153,7 @@ $ brew install carthage
To integrate SwiftEntryKit into your Xcode project using Carthage, specify the following in your `Cartfile`:

```ogdl
github "huri000/SwiftEntryKit" == 0.4.1
github "huri000/SwiftEntryKit" == 0.4.2
```

## Usage
Expand Down Expand Up @@ -343,6 +345,27 @@ attributes.scroll = .edgeCrossingDisabled(swipeable: true)
#### [Haptic Feedback](https://developer.apple.com/ios/human-interface-guidelines/user-interaction/feedback/)
The device can produce a haptic feedback, thus adding an additional sensory depth to each entry.

#### Lifecycle Events
Events can be injected to the entry so that they are to be called during its lifecycle.

```Swift
attributes.lifecycleEvents.willAppear = {
// Executed before the entry animates inside
}

attributes.lifecycleEvents.didAppear = {
// Executed after the entry animates inside
}

attributes.lifecycleEvents.willDisappear = {
// Executed before the entry animates outside
}

attributes.lifecycleEvents.didDisappear = {
// Executed after the entry animates outside
}
```

#### Background Style
The entry and the screen can have various background styles, such as blur, color, gradient and even an image.

Expand Down Expand Up @@ -485,6 +508,7 @@ public struct EKAttributes
public var entryInteraction: UserInteraction
public var scroll: Scroll
public var hapticFeedbackType: NotificationHapticFeedback
public var lifecycleEvents: LifecycleEvents

// Theme & Style
public var entryBackground: BackgroundStyle
Expand Down Expand Up @@ -566,8 +590,17 @@ You can dismiss an entry by simply invoke *dismiss* in the SwiftEntryKit class,
```Swift
SwiftEntryKit.dismiss()
```
This will dismiss the entry animatedly using it's *exitAnimation* attribute and on comletion it'll remove the window as well.
This dismisses the entry animatedly using its *exitAnimation* attribute and on comletion, the window would be removed as well.

#### Using a completion handler

Use a trailing closure as completion handler to the dismiss mechanism.

```Swift
SwiftEntryKit.dismiss {
// Executed right after the entry has been dismissed
}
```

### Is Currently Displaying
Inquire whether an entry is currently displayed:
Expand Down
32 changes: 30 additions & 2 deletions Source/Infra/EKContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ class EKContentView: UIView {

private var keyboardState = KeyboardState.hidden

// Dismissal handler
var dismissHandler: SwiftEntryKit.DismissCompletionHandler?

// Data source
private var attributes: EKAttributes {
return contentView.attributes
Expand All @@ -80,6 +83,9 @@ class EKContentView: UIView {

self.contentView = contentView

// Execute willAppear lifecycle action if needed
contentView.attributes.lifecycleEvents.willAppear?()

// Setup attributes
setupAttributes()

Expand Down Expand Up @@ -314,6 +320,10 @@ class EKContentView: UIView {

// Animate out
func animateOut(pushOut: Bool) {

// Execute willDisappear action if needed
contentView.attributes.lifecycleEvents.willDisappear?()

if attributes.positionConstraints.keyboardRelation.isBound {
endEditing(true)
}
Expand Down Expand Up @@ -387,9 +397,18 @@ class EKContentView: UIView {
self.transform = CGAffineTransform(scaleX: scale.end, y: scale.end)
}
}

entryDelegate?.changeToActive(withAttributes: attributes)


// Execute didAppear action if needed
if animation.containsAnimation {
DispatchQueue.main.asyncAfter(deadline: .now() + animation.maxDuration) {
self.contentView.attributes.lifecycleEvents.didAppear?()
}
} else {
contentView.attributes.lifecycleEvents.didAppear?()
}

scheduleAnimateOut()
}

Expand Down Expand Up @@ -448,8 +467,17 @@ class EKContentView: UIView {
guard superview != nil else {
return
}

// Execute didDisappear action if needed
contentView.content.attributes.lifecycleEvents.didDisappear?()

// Execute dismiss handler if needed
dismissHandler?()

// Remove the view from its superview and in a case of a view controller, from its parent controller.
super.removeFromSuperview()
contentView.content.viewController?.removeFromParentViewController()

if EKAttributes.count > 0 {
EKAttributes.count -= 1
}
Expand Down
3 changes: 2 additions & 1 deletion Source/Infra/EKRootViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ class EKRootViewController: UIViewController {
}

// Make last entry exit using exitAnimation - animatedly
func animateOutLastEntry() {
func animateOutLastEntry(completionHandler: SwiftEntryKit.DismissCompletionHandler? = nil) {
lastEntry?.dismissHandler = completionHandler
lastEntry?.animateOut(pushOut: false)
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Infra/EKWindowProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ final class EKWindowProvider {
}

/** Dismiss the current entry */
func dismiss() {
func dismiss(with completion: SwiftEntryKit.DismissCompletionHandler? = nil) {
guard let rootVC = rootVC else {
return
}
rootVC.animateOutLastEntry()
rootVC.animateOutLastEntry(completionHandler: completion)
}

/** Layout the window view-hierarchy if needed */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
//
// EKAttributes+Completion.swift
// EKAttributes+LifecycleActions.swift
// SwiftEntryKit
//
// Created by Daniel Huri on 6/16/18.
// Copyright © 2018 CocoaPods. All rights reserved.
// Copyright (c) 2018 [email protected]. All rights reserved.
//

import Foundation

extension EKAttributes {

public struct LifecycleActions {
/** Contains optionally injected events that take place during the entry lifecycle */
public struct LifecycleEvents {

public typealias Action = () -> Void
public typealias Event = () -> Void

/** Executed before the entry appears - before the animation starts.
Might not get called in case another entry with a higher display priority is displayed.
*/
public var willAppear: Action?
public var willAppear: Event?

/** Executed after the animation ends.
Might not get called in case another entry with a higher display priority is displayed.
*/
public var didAppear: Action?
public var didAppear: Event?

/** Executed before the entry disappears (Before the animation starts) */
public var willDisappear: Action?
public var willDisappear: Event?

/** Executed after the entry disappears (After the animation ends) */
public var didDisappear: Action?
public var didDisappear: Event?

public init(willAppear: Action? = nil, didAppear: Action? = nil, willDisappear: Action? = nil, didDisappear: Action? = nil) {
public init(willAppear: Event? = nil, didAppear: Event? = nil, willDisappear: Event? = nil, didDisappear: Event? = nil) {
self.willAppear = willAppear
self.didAppear = didAppear
self.willDisappear = willDisappear
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ extension EKAttributes {

/** Describes the entry behavior when a new entry shows (with equal or higher display-priority) */
public enum PopBehavior {

/** The entry disappears promptly (Does not animates out) when a new one shows */
case overridden

Expand Down
Loading

0 comments on commit 5f8cb29

Please sign in to comment.