Skip to content

Commit

Permalink
Merge pull request #21 from deskpro/feat/objc-support
Browse files Browse the repository at this point in the history
Add Objective-C support
  • Loading branch information
qsd-faris authored May 15, 2024
2 parents e57d3b8 + ddaadee commit bb423f6
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Sources/Data/PushNotificationData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import Foundation
///Data class representing the payload of a push notification.
///
///The class encapsulates the information included in a push notification.
public class PushNotificationData {
@objc public class PushNotificationData: NSObject {

}
23 changes: 16 additions & 7 deletions Sources/Data/User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,30 @@
import Foundation

/// - Tag: User
public class User: Codable, Equatable {
@objc public class User: NSObject, Codable {

public var name: String? = nil
public var first_name: String? = nil
public var last_name: String? = nil
public var email: String? = nil
@objc public var name: String? = nil
@objc public var first_name: String? = nil
@objc public var last_name: String? = nil
@objc public var email: String? = nil

public init(name: String? = nil, firstName: String? = nil, lastName: String? = nil, email: String? = nil) {
@objc public init(name: String? = nil, firstName: String? = nil, lastName: String? = nil, email: String? = nil) {
self.name = name
self.first_name = firstName
self.last_name = lastName
self.email = email
}

/// Objective-C compatible equality check
@objc public func isEqualToUser(_ user: User) -> Bool {
return self.name == user.name && self.first_name == user.first_name && self.last_name == user.last_name && self.email == user.email
}
}

/// Extend the Swift functionality to still support the == operator in Swift contexts
extension User {

public static func == (lhs: User, rhs: User) -> Bool {
return lhs.name == rhs.name && lhs.first_name == rhs.first_name && lhs.last_name == rhs.last_name && lhs.email == rhs.email
return lhs.isEqualToUser(rhs)
}
}
33 changes: 17 additions & 16 deletions Sources/Deskpro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,38 @@ import UIKit
/// The `DeskPro` class provides methods for initializing the Messenger, managing user information,
/// handling push notifications, and presenting the DeskPro messaging interface.
///
public final class DeskPro: Messenger {
@objc public final class DeskPro: NSObject, Messenger {

private var messengerConfig: MessengerConfig

/// Coordinator to make sure that only one instance of webView is opened.
private var coordinator: PresentCoordinator

/// User defaults manager for storing user-related information.
var appUserDefaults: AppUserDefaults
var appUserDefaults: DeskproUserDefaults

/// Each Deskpro instance is having its own eventRouter to handle events in chat.
public var eventRouter: EventRouter
@objc public var eventRouter: EventRouter

/// Initializes the functionality of the application.
///
/// This method is a constructor for creating Deskpro objects with specific configurations and prepare for the execution of other features.
///
///- Parameter messengerConfig: The configuration object containing settings for the DeskPro Messenger.
///
public init(messengerConfig: MessengerConfig, containingViewController: UIViewController, enableAutologging: Bool = false) {
@objc public init(messengerConfig: MessengerConfig, containingViewController: UIViewController, enableAutologging: Bool = false) {
self.eventRouter = .init(enableAutologging: enableAutologging)
self.messengerConfig = messengerConfig
self.coordinator = PresentCoordinator(containingViewController: containingViewController, eventRouter: eventRouter)
self.appUserDefaults = AppUserDefaults(appId: messengerConfig.appId)
self.appUserDefaults = DeskproUserDefaults(appId: messengerConfig.appId)
}

/// Performs a test operation and returns a result as a String.
///
/// The method is intended to simulate a test scenario and provide a String result based on the outcome of the test.
///
/// - Returns: A String representing the result of the test operation.
public static func test() -> String {
@objc public static func test() -> String {
return "Hello world from Messenger!"
}

Expand All @@ -53,7 +53,7 @@ public final class DeskPro: Messenger {
///
/// - Parameter user: The [User](x-source-tag://User) object containing the user information.
///
public final func setUserInfo(user: User) {
@objc public final func setUserInfo(user: User) {
appUserDefaults.setUserInfo(user)
}

Expand All @@ -73,7 +73,7 @@ public final class DeskPro: Messenger {
///
/// - Returns: `true` if the token is successfully saved, `false` otherwise.
@discardableResult
public final func authorizeUser(userJwt: String) -> Bool {
@objc public final func authorizeUser(userJwt: String) -> Bool {
appUserDefaults.setJwtToken(userJwt)
return true
}
Expand All @@ -89,7 +89,7 @@ public final class DeskPro: Messenger {
///
/// - Returns: `true` if the logout operation is successful; `false` otherwise.
@discardableResult
public final func forgetUser() -> Bool {
@objc public final func forgetUser() -> Bool {
appUserDefaults.clear()
return true
}
Expand All @@ -102,7 +102,7 @@ public final class DeskPro: Messenger {
///
/// - Returns: `true` if the push registration token is successfully set; `false` otherwise.
@discardableResult
public final func setPushRegistrationToken(token: String) -> Bool {
@objc public final func setPushRegistrationToken(token: String) -> Bool {
appUserDefaults.setDeviceToken(token)
return true
}
Expand All @@ -121,7 +121,7 @@ public final class DeskPro: Messenger {
/// - Returns: `true` if the push notification is related to DeskPro; `false` otherwise.
///
/// - Tag: isDeskProPushNotification
public static func isDeskProPushNotification(data: [AnyHashable: Any]) -> Bool {
@objc public static func isDeskProPushNotification(data: [AnyHashable: Any]) -> Bool {
if let issuer = data["issuer"] as? String {
return issuer == "deskpro-messenger"
} else {
Expand All @@ -137,7 +137,7 @@ public final class DeskPro: Messenger {
///
/// - Parameter pushNotification: The push notification data to be handled.
///
public final func handlePushNotification(pushNotification: PushNotificationData) {
@objc public final func handlePushNotification(pushNotification: PushNotificationData) {
// TODO: Not yet implemented
}

Expand All @@ -147,7 +147,7 @@ public final class DeskPro: Messenger {
///
/// - Returns: A [PresentBuilder](x-source-tag://PresentBuilder) instance to start building presentation paths.
///
public final func present() -> PresentBuilder {
@objc public final func present() -> PresentBuilder {
let url = messengerConfig.appUrl//.appending(messengerConfig.appId)
//return PresentBuilder(url: url, containingViewController: containingViewController)
return PresentBuilder(url: url, appId: messengerConfig.appId, coordinator: coordinator)
Expand All @@ -157,7 +157,7 @@ public final class DeskPro: Messenger {
///
/// This method closes the currently displayed chat view, terminating the user's interaction with the DeskPro content.
///
public final func close() {
@objc public final func close() {
// TODO: Not yet implemented
}

Expand All @@ -167,7 +167,7 @@ public final class DeskPro: Messenger {
///
/// - Returns: The number of unread conversations in the inbox.
///
public final func getUnreadConversationCount() -> Int {
@objc public final func getUnreadConversationCount() -> Int {
// TODO: Not yet implemented
return 0
}
Expand All @@ -176,7 +176,8 @@ public final class DeskPro: Messenger {
///
/// This method turns on logging for the DeskPro SDK, allowing detailed information to be logged for debugging and troubleshooting purposes.
///
public final func enableLogging() {
@objc public final func enableLogging() {
// TODO: Not yet implemented
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation
/// UserDefaults utility class for managing user information and JWT tokens in the DeskPro Messenger module.
///
/// The class provides methods for retrieving, storing, and clearing user information, device tokens and JWT tokens using the UserDefaults API.
class AppUserDefaults {
final class DeskproUserDefaults {

/// UserDefaults instance.
let prefs = UserDefaults.standard
Expand Down
45 changes: 43 additions & 2 deletions Sources/Logs/EventRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
import Foundation

/// Notifies the outside subscriber if an event occured. Prints all of the events if the autologging is enabled
public final class EventRouter {
@objc public final class EventRouter: NSObject {

/// Invoked when an event occurs
public var handleEventCallback: ((DeskproEvent) -> Void)? = nil
@objc public var objcHandleEventCallback: ((ObjcDeskproEventData) -> Void)? = nil
private var enableAutologging: Bool

/// Initializes the EventRouter class
///
///- Parameter enableAutologging: If true, the EventRouter class will print all of the events that occur (during debug mode).
///
init(enableAutologging: Bool = false) {
@objc public init(enableAutologging: Bool = false) {
self.enableAutologging = enableAutologging
}

Expand All @@ -29,6 +30,36 @@ public final class EventRouter {

handleEventCallback?(event)
}

@objc func objcHandleOrLogEvent(event: ObjcDeskproEventData) {
if enableAutologging {
dprint("[DeskproLogger]: \(event.debugDescription)")
}

objcHandleEventCallback?(event)
}
}

@objc public final class ObjcDeskproEventData: NSObject {
@objc public var event: ObjcDeskproEvent
@objc public var data: String

@objc init(event: ObjcDeskproEvent, data: String) {
self.event = event
self.data = data
}

@objc public override var debugDescription: String {
"\(Date.nowString) [AppEvent] \(data)"
}
}

@objc public enum ObjcDeskproEvent: Int {
case newChat
case chatEnded
case newChatMessage
case chatUploadRequest
case custom
}

/// An event that occurs during a chat session. The observation of these events occurs through the EventRouter class
Expand Down Expand Up @@ -65,6 +96,16 @@ public enum DeskproEvent {
}
}

var toObjcEvent: ObjcDeskproEvent {
switch self {
case .newChat(_): return .newChat
case .chatEnded(_): return .chatEnded
case .newChatMessage(_): return .newChatMessage
case .chatUploadRequest(_): return .chatUploadRequest
case .custom(_): return .custom
}
}

/// Raw event JSON in string format
public var data: String {
switch self {
Expand Down
10 changes: 5 additions & 5 deletions Sources/MessengerConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ import Foundation
/// Configuration data class for initializing the Messenger feature in the application.
///
/// This data class holds configuration parameters required for setting up and initializing the Messenger feature within the application. The configuration includes the base URL of the Messenger service, the application ID, and the application key.
public final class MessengerConfig {
@objc public final class MessengerConfig: NSObject {

public var appUrl: String
public var appId: String
public var appKey: String?
@objc public var appUrl: String
@objc public var appId: String
@objc public var appKey: String?

///- Parameter appUrl: The base URL of the Messenger service.
///- Parameter appId: The unique identifier for the application using the Messenger feature.
///- Parameter appKey: The secret key for authenticating the application with the Messenger service.
public init(appUrl: String, appId: String, appKey: String? = nil) {
@objc public init(appUrl: String, appId: String, appKey: String? = nil) {
self.appUrl = appUrl
self.appId = appId
self.appKey = appKey
Expand Down
14 changes: 7 additions & 7 deletions Sources/PresentBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ import UIKit
/// The final constructed path can then be presented in a WebView using the [show](x-source-tag://show) method.
///
///- Tag: PresentBuilder
public final class PresentBuilder {
@objc public final class PresentBuilder: NSObject {

/// The coordinator for easier WebView presentation handling.
private weak var coordinator: PresentCoordinator?

/// The base URL for constructing the path.
public var url: String
@objc public var url: String

/// The application ID used for presentation.
private var appId: String
Expand All @@ -36,7 +36,7 @@ public final class PresentBuilder {
/// - Parameter url: The base URL for constructing the path.
/// - Parameter appId: The application ID used for presentation.
/// - Parameter coordinator: The coordinator for easier webView presentation handling
public init(url: String, appId: String, coordinator: PresentCoordinator) {
@objc public init(url: String, appId: String, coordinator: PresentCoordinator) {
self.url = url
self.appId = appId
self.path = path.appending(url)
Expand All @@ -48,7 +48,7 @@ public final class PresentBuilder {
/// - Parameter chatId: The identifier of the chat for which the history is requested.
///
/// - Returns: The [PresentBuilder](x-source-tag://PresentBuilder) instance for method chaining.
public final func chatHistory(_ chatId: Int) -> PresentBuilder {
@objc public final func chatHistory(_ chatId: Int) -> PresentBuilder {
path.append("/chat_history/\(chatId)")
return self
}
Expand All @@ -58,15 +58,15 @@ public final class PresentBuilder {
/// - Parameter articleId: The identifier of the article to be presented.
///
/// - Returns: The [PresentBuilder](x-source-tag://PresentBuilder) instance for method chaining.
public final func article(_ articleId: Int) -> PresentBuilder {
@objc public final func article(_ articleId: Int) -> PresentBuilder {
path.append("/article/\(articleId)")
return self
}

/// Appends the comments path to the constructed URL path.
///
/// - Returns: The [PresentBuilder](x-source-tag://PresentBuilder) instance for method chaining.
public final func comments() -> PresentBuilder {
@objc public final func comments() -> PresentBuilder {
path.append("/comments")
return self
}
Expand All @@ -76,7 +76,7 @@ public final class PresentBuilder {
/// If the application context is null, a message is logged, and the method returns early. Otherwise, the WebView is started with the constructed path and application ID.
///
///- Tag: show
public final func show() {
@objc public final func show() {
coordinator?.present(path: path, appId: appId)
}
}
5 changes: 3 additions & 2 deletions Sources/PresentCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import UIKit

/// The coordinator for easier WebView presentation handling. It will make sure that only one instance of WebView is presented at the time.
/// - Tag: PresentCoordinator
public final class PresentCoordinator: WebViewDelegate {
@objc public final class PresentCoordinator: NSObject, WebViewDelegate {

weak var containingViewController: UIViewController?

Expand All @@ -18,7 +18,7 @@ public final class PresentCoordinator: WebViewDelegate {

///- Parameter containingViewController: The ViewController from which the WebView will be presented.
///- Parameter eventRouter: The unique event router for this messenger instance. Enables event handling
public init(
@objc public init(
containingViewController: UIViewController,
eventRouter: EventRouter
) {
Expand Down Expand Up @@ -49,5 +49,6 @@ public final class PresentCoordinator: WebViewDelegate {
/// Delegate method: invoked when an event occurs
final func eventOccured(_ event: DeskproEvent) {
eventRouter.handleOrLogEvent(event: event)
eventRouter.objcHandleOrLogEvent(event: .init(event: event.toObjcEvent, data: event.data))
}
}
Loading

0 comments on commit bb423f6

Please sign in to comment.