Skip to content

Commit

Permalink
pull omni banner PR + modify for design requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
anlinguist committed Jul 20, 2023
1 parent 6a7a41e commit d9dc604
Show file tree
Hide file tree
Showing 15 changed files with 1,104 additions and 2 deletions.
Binary file added BannerViewDocuments/ClassName.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
183 changes: 183 additions & 0 deletions BannerViewDocuments/IterableBannerViewReadme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# UI Components provided by IterableSDK

## IterableBannerView for iOS

This repository contains a collection of IBDesignable components for iOS, specifically the IterableBannerView. The IterableBannerView is a versatile component that allows you to create visually appealing banners with customizable features. With this component, you can easily display titles, descriptions, buttons, and image within a banner, providing a seamless user experience.

#### Usage
- Open the storyboard or XIB file where you want to use the IterableBannerView.
- In the Object Library, search for "View" or browse the list of available components.
- Drag and drop the View onto your canvas.
- Click on Identity Inspector.
- Insert class name "IterableBannerView"

![ClassName](/BannerViewDocuments/ClassName.jpg)

### Design Samples
![Sample 1](/BannerViewDocuments/Sample1.jpg)
![Sample 2](/BannerViewDocuments/Sample2.jpg)
![Sample 3](/BannerViewDocuments/Sample3.jpg)

### Customized
Customize the various properties of the IterableBannerView in the Attributes Inspector, including:

![Property](/BannerViewDocuments/Property.jpg)

### View:
- Set the corner radius
- Shadow color
- Shadow offset
- Shadow radius
- Background color of the view

### Title:
- Specify the title text
- Font size
- Text color

### Description:
- Set the description text.
- Font size
- Text color

### Primary Button:
- Define the button text
- Text color
- Background color
- Border radius

### Secondary Button:
- Configure the button text
- Text color
- Background color
- Border radius
- Toggle its visibility.

### Image View:
- Choose the background color
- Border radius
- Border color
- Select an image
- Set the size (width and height)

Preview and adjust the appearance of the IterableBannerView directly in Interface Builder.
Build and run your project to see the IterableBannerView in action on your device or simulator.

## Video Preview
<!-- ![Preview](/BannerViewDocuments/full_design_video.mp4) -->

### Full Sample Code

```swift
import UIKit
import Foundation
import IterableSDK

struct IterableBannerData {
let title: String
let description: String
let primaryButtonTitle: String
let secondaryButtonTitle: String?
let image: UIImage?
}

class DesignSampleViewController: UIViewController, IterableBannerViewDelegate {

// Bind IBOutlet, using view from storyboard
@IBOutlet weak var bannerViewBottom: IterableBannerView!

var iterableBannerData: [IterableBannerData] = []

// Create Programatically
var bannerView = IterableBannerView(frame: CGRectMake(0, 50, 300, 159))
var bannerViewSecond = IterableBannerView()

//MARK:
override func viewDidLoad() {
super.viewDidLoad()
self.loadBannerData()
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
loadBannerView()
loadSecondBanner()
}

//MARK:
func loadBannerData() {
let firstBanner = IterableBannerData(title: "Try Gold Plan", description: "Enjoy 14 days of Premium", primaryButtonTitle: "Pay now", secondaryButtonTitle: nil, image: UIImage.init(named: "flag"))
let secondBanner = IterableBannerData(title: "Try Silver Plan", description: "Enjoy 7 days of Premium \n Second line description", primaryButtonTitle: "Pay for 7 days", secondaryButtonTitle: nil, image: UIImage.init(named: "selectedsubscription.png"))
iterableBannerData = [firstBanner,secondBanner]
}

func loadBannerView() {
bannerView.tag = 1
bannerView.iterableBannerViewDelegate = self
bannerView.frame = CGRectMake(16, 50, self.view.frame.width - 32, 159)
bannerView.labelTitle.text = iterableBannerData[0].title
bannerView.labelDescription.text = iterableBannerData[0].description
bannerView.btnPrimary.setTitle(iterableBannerData[0].primaryButtonTitle, for: .normal)

if ((iterableBannerData[0].secondaryButtonTitle) != nil) {
bannerView.btnSecondary.setTitle(iterableBannerData[0].secondaryButtonTitle, for: .normal)
bannerView.isShowSecondaryButton = true
}
else {
bannerView.isShowSecondaryButton = false
}

bannerView.imgView.image = iterableBannerData[0].image
bannerViewSecond.imgViewBorderWidth = 10
bannerViewSecond.imgViewBorderColor = UIColor.systemOrange
// Add a button action, an alternate option for a button event without using the delegate method.
// bannerView.btnPrimary.addTarget(self, action: #selector (btnPrimaryPressed), for: .touchUpInside)
self.view.addSubview(bannerView);
}

func loadSecondBanner() {
bannerViewSecond.tag = 2
bannerViewSecond.iterableBannerViewDelegate = self
bannerViewSecond.contentView.backgroundColor = UIColor.systemYellow
bannerViewSecond.iterableBannerViewDelegate = self

bannerViewSecond.labelTitle.text = iterableBannerData[1].title
bannerViewSecond.labelDescription.text = iterableBannerData[1].description + "new \n new"
bannerViewSecond.btnPrimary.setTitle(iterableBannerData[1].primaryButtonTitle, for: .normal)

if ((iterableBannerData[1].secondaryButtonTitle) != nil) {
bannerViewSecond.btnSecondary.setTitle(iterableBannerData[1].secondaryButtonTitle, for: .normal)
bannerViewSecond.isShowSecondaryButton = true
}
else {
bannerViewSecond.isShowSecondaryButton = false
}
bannerViewSecond.center = self.view.center
bannerViewSecond.frame = CGRectMake(16, 159 + 50 + 25, self.view.frame.width - 32, 200)
bannerViewSecond.imgView.image = iterableBannerData[1].image
bannerViewSecond.imgView.backgroundColor = UIColor.clear
bannerViewSecond.imgViewBorderWidth = 0
bannerViewSecond.imgViewBorderColor = UIColor.clear
self.view.addSubview(bannerViewSecond);
}

//MARK: Button Pressed add target method
@objc func btnPrimaryPressed () {
print("btnPrimaryPressed")
}

//MARK:IterableBannerViewDelegate Methods
func didPressPrimaryButton(button: UIButton, viewTag: Int) {
print("didPressPrimaryButton", viewTag)
}

func didPressSecondaryButton(button: UIButton, viewTag: Int) {
print("didPressSecondaryButton", viewTag)
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
}
```
Happy designing with IterableBannerView!
Binary file added BannerViewDocuments/Property.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BannerViewDocuments/Sample1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BannerViewDocuments/Sample2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BannerViewDocuments/Sample3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BannerViewDocuments/full_design_video.mp4
Binary file not shown.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ To learn more about various SDK features, read:
- [Customizing Mobile Inbox on iOS](https://support.iterable.com/hc/articles/360039091471)
- [iOS Universal Links](https://support.iterable.com/hc/articles/360035496511)
- [Deep Links in Push Notifications](https://support.iterable.com/hc/articles/360035453971)
- [UI Components](/BannerViewDocuments/IterableBannerViewReadme.md)

## Sample projects

Expand Down
1 change: 1 addition & 0 deletions script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cp -r "${SRCROOT}/swift-sdk/Resources" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app"
18 changes: 17 additions & 1 deletion swift-sdk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@
55E02D39253F8D86009DB8BC /* WebViewProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E02D38253F8D86009DB8BC /* WebViewProtocolTests.swift */; };
55E6F462238E066400808BCE /* DeepLinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E6F45E238E066400808BCE /* DeepLinkTests.swift */; };
55E9BE3429F9F5E6000C9FF2 /* DependencyContainerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E9BE3329F9F5E6000C9FF2 /* DependencyContainerProtocol.swift */; };
560ACF482A308C8A007F9503 /* IterableBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560ACF462A308C8A007F9503 /* IterableBannerView.swift */; };
564BCC302A30B60500A699B9 /* IterableBannerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 560ACF452A308C8A007F9503 /* IterableBannerView.xib */; };
5B49BB3E27CFB71500E6F00C /* PopupInboxSessionUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B49BB3D27CFB71500E6F00C /* PopupInboxSessionUITests.swift */; };
5B5AA711284F1A6D0093FED4 /* MockNetworkSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5AA710284F1A6D0093FED4 /* MockNetworkSession.swift */; };
5B5AA712284F1A6D0093FED4 /* MockNetworkSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5AA710284F1A6D0093FED4 /* MockNetworkSession.swift */; };
Expand Down Expand Up @@ -587,6 +589,8 @@
55E02D38253F8D86009DB8BC /* WebViewProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewProtocolTests.swift; sourceTree = "<group>"; };
55E6F45E238E066400808BCE /* DeepLinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeepLinkTests.swift; sourceTree = "<group>"; };
55E9BE3329F9F5E6000C9FF2 /* DependencyContainerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependencyContainerProtocol.swift; sourceTree = "<group>"; };
560ACF452A308C8A007F9503 /* IterableBannerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IterableBannerView.xib; sourceTree = "<group>"; };
560ACF462A308C8A007F9503 /* IterableBannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IterableBannerView.swift; sourceTree = "<group>"; };
5B49BB3D27CFB71500E6F00C /* PopupInboxSessionUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupInboxSessionUITests.swift; sourceTree = "<group>"; };
5B5AA710284F1A6D0093FED4 /* MockNetworkSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNetworkSession.swift; sourceTree = "<group>"; };
5B6C3C1027CE871F00B9A753 /* NavInboxSessionUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavInboxSessionUITests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -949,6 +953,14 @@
path = "embedded-messaging-tests";
sourceTree = "<group>";
};
560ACF442A308C8A007F9503 /* uicomponents */ = {
isa = PBXGroup;
children = (
560ACF462A308C8A007F9503 /* IterableBannerView.swift */,
);
path = uicomponents;
sourceTree = "<group>";
};
AC0248062279132400495FB9 /* Dwifft */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1008,9 +1020,10 @@
AC2263E120CF49B8009800EB /* swift-sdk */ = {
isa = PBXGroup;
children = (
AC44C0EB22615F8100E0641D /* Resources */,
560ACF442A308C8A007F9503 /* uicomponents */,
AC5C467E2756AEA4000762B6 /* swiftui */,
AC72A0BB20CF4C8C004D7997 /* Internal */,
AC44C0EB22615F8100E0641D /* Resources */,
AC2263F920CF4B63009800EB /* Supporting Files */,
AC72A0C120CF4CB8004D7997 /* CommerceItem.swift */,
AC72A0BE20CF4CB8004D7997 /* Constants.swift */,
Expand Down Expand Up @@ -1171,6 +1184,7 @@
AC44C0EB22615F8100E0641D /* Resources */ = {
isa = PBXGroup;
children = (
560ACF452A308C8A007F9503 /* IterableBannerView.xib */,
AC219C522260006600B98631 /* Assets.xcassets */,
AC50865224C60172001DC132 /* IterableDataModel.xcdatamodeld */,
AC219C4F225FEDBD00B98631 /* SampleInboxCell.xib */,
Expand Down Expand Up @@ -1902,6 +1916,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
564BCC302A30B60500A699B9 /* IterableBannerView.xib in Resources */,
AC219C532260006600B98631 /* Assets.xcassets in Resources */,
AC219C51225FEDBD00B98631 /* SampleInboxCell.xib in Resources */,
);
Expand Down Expand Up @@ -2033,6 +2048,7 @@
AC684A86222EF75C00F29749 /* InAppMessageParser.swift in Sources */,
AC72A0C920CF4CE2004D7997 /* IterableAction.swift in Sources */,
AC72A0CA20CF4CE2004D7997 /* ActionRunner.swift in Sources */,
560ACF482A308C8A007F9503 /* IterableBannerView.swift in Sources */,
ACC3FDB1253724DB0004A2E0 /* InAppCalculations.swift in Sources */,
ACD6116C2107D004003E7F6B /* NetworkHelper.swift in Sources */,
ACC362B624D16D91002C67BA /* IterableRequest.swift in Sources */,
Expand Down
88 changes: 88 additions & 0 deletions swift-sdk/Internal/EmbeddedMessagingManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@
import Foundation
import UIKit

public struct ResolvedMessage {
public let title: String?
public let description: String?
public var image: UIImage?
public let buttonText: String?
public let buttonTwoText: String?
public let message: IterableEmbeddedMessage

init(title: String?,
description: String?,
image: UIImage?,
buttonText: String?,
buttonTwoText: String?,
message: IterableEmbeddedMessage) {
self.title = title
self.description = description
self.image = image
self.buttonText = buttonText
self.buttonTwoText = buttonTwoText
self.message = message
}
}

class EmbeddedMessagingManager: NSObject, IterableEmbeddedMessagingManagerProtocol {
init(apiClient: ApiClientProtocol) {
ITBInfo()
Expand All @@ -23,6 +46,71 @@ class EmbeddedMessagingManager: NSObject, IterableEmbeddedMessagingManagerProtoc
return messages
}

public func resolveMessages(_ messages: [IterableEmbeddedMessage], completion: @escaping ([ResolvedMessage]) -> Void) {
var resolvedMessages: [ResolvedMessage] = []

let group = DispatchGroup()

for message in messages {
group.enter()

let title = message.elements?.title
let description = message.elements?.body
let imageUrl = message.elements?.mediaUrl
let buttonText = message.elements?.buttons?.first?.title
let buttonTwoText = message.elements?.buttons?.count ?? 0 > 1 ? message.elements?.buttons?[1].title : nil

DispatchQueue.global().async {
if let imageUrl = imageUrl, let url = URL(string: imageUrl) {
var request = URLRequest(url: url)
request.setValue("Mozilla/5.0 (iPhone; CPU iPhone OS 16_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1", forHTTPHeaderField: "User-Agent")

let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = request.allHTTPHeaderFields

let session = URLSession(configuration: config)

session.dataTask(with: request) { (data, _, _) in
defer { group.leave() }

guard let imageData = data else {
print("Unable to load image data")
return
}

let resolvedMessage = ResolvedMessage(title: title,
description: description,
image: UIImage(data: imageData),
buttonText: buttonText,
buttonTwoText: buttonTwoText,
message: message)

DispatchQueue.main.async {
resolvedMessages.append(resolvedMessage)
}

}.resume()
} else {
let resolvedMessage = ResolvedMessage(title: title,
description: description,
image: nil,
buttonText: buttonText,
buttonTwoText: buttonTwoText,
message: message)
DispatchQueue.main.async {
resolvedMessages.append(resolvedMessage)
group.leave()
}
}
}

}

group.notify(queue: .main) {
completion(resolvedMessages)
}
}

public func addUpdateListener(_ listener: IterableEmbeddedMessagingUpdateDelegate) {
listeners.add(listener)
}
Expand Down
4 changes: 4 additions & 0 deletions swift-sdk/Internal/EmptyEmbeddedMessagingManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import Foundation

class EmptyEmbeddedMessagingManager: IterableEmbeddedMessagingManagerProtocol {
func resolveMessages(_ messages: [IterableEmbeddedMessage], completion: @escaping ([ResolvedMessage]) -> Void) {

}


func addUpdateListener(_ listener: IterableEmbeddedMessagingUpdateDelegate) {

Expand Down
4 changes: 3 additions & 1 deletion swift-sdk/IterableEmbeddedMessagingManagerProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import Foundation

@objc public protocol IterableEmbeddedMessagingManagerProtocol {
public protocol IterableEmbeddedMessagingManagerProtocol {
func getMessages() -> [IterableEmbeddedMessage]
func resolveMessages(_ messages: [IterableEmbeddedMessage], completion: @escaping ([ResolvedMessage]) -> Void)


func addUpdateListener(_ listener: IterableEmbeddedMessagingUpdateDelegate)
func removeUpdateListener(_ listener: IterableEmbeddedMessagingUpdateDelegate)
Expand Down
Loading

0 comments on commit d9dc604

Please sign in to comment.