Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Notification #5

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions MageNotification/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.service</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
</dict>
</dict>
</plist>
70 changes: 70 additions & 0 deletions MageNotification/NotificationService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// NotificationService.swift
// MageNotification
//
// Created by Kushkumar Katira on 28/03/24.
//

import UserNotifications

class NotificationService: UNNotificationServiceExtension {

var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

if let bestAttemptContent = bestAttemptContent,
// ✅ payload
let fcmOptionsUserInfo = bestAttemptContent.userInfo["attachment"] as? [String: Any] {
guard let imageURLString = fcmOptionsUserInfo["image"] as? String else {
contentHandler(bestAttemptContent)
return
}
let imageURL = URL(string: imageURLString)!

// 🔥 download image.
guard let imageData = try? Data(contentsOf: imageURL) else {
contentHandler(bestAttemptContent)
return
}

// 🔥 set UNNotificationAttachment.
guard let attachment = UNNotificationAttachment.saveImageToDisk(identifier: "notification.jpg", data: imageData, options: nil) else {
contentHandler(bestAttemptContent)
return
}
bestAttemptContent.attachments = [attachment]
contentHandler(bestAttemptContent)
}
}

override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}

extension UNNotificationAttachment {
static func saveImageToDisk(identifier: String, data: Data, options: [AnyHashable : Any]? = nil) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let folderName = ProcessInfo.processInfo.globallyUniqueString
let folderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(folderName, isDirectory: true)!

do {
try fileManager.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
let fileURL = folderURL.appendingPathExtension(identifier)
try data.write(to: fileURL)
let attachment = try UNNotificationAttachment(identifier: identifier, url: fileURL, options: options)
return attachment
} catch {
print("saveImageToDisk error - \(error)")
}
return nil
}
}
15 changes: 11 additions & 4 deletions Shared/Clients/HttpClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,27 +74,34 @@ class HttpClient {
let configuration = URLSessionConfiguration.default

configuration.httpAdditionalHeaders = ["Content-Type": "application/json",
"x-api-key": "89ft2axc7yttqj4cba22qit7ztpebi"] // gbg5qzp3s17zhddy3tv6o9rkovqm2q
"x-api-key": "kzv2i5n40w02hodb1rhne9wduj26z8"] // gbg5qzp3s17zhddy3tv6o9rkovqm2q

let session = URLSession(configuration: configuration)

let (data, response) = try await session.data(for: request)

let string = String(data: data, encoding: .utf8)!
print("API Request", request)
print("API RESPONSE: ", string)

guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 || httpResponse.statusCode == 201
else {
if let httpResponse = response as? HTTPURLResponse {
print("API Response With Error Code:\n", request, httpResponse.statusCode)
}
throw NetworkError.invalidResponse
}

guard let result = try? JSONDecoder().decode(T.self, from: data) else {
do {
let result = try JSONDecoder().decode(T.self, from: data)
return result
} catch {
print("Decode Error", error)
print("Decode Model", T.self)
throw NetworkError.decodingError
}

return result

}

}
65 changes: 65 additions & 0 deletions Shared/Extensions/NotificationManager/NotificationManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@


import FirebaseCore
import FirebaseMessaging
import UserNotifications

protocol NotificationManagerDelegate {
func didReceiveNotificationToken(token: String)
}

class NotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate {

var delegate: NotificationManagerDelegate?
private lazy var pushNotificationOption: UNNotificationPresentationOptions = {
if #available(iOS 14.0, *) {
return [.alert, .banner, .sound]
} else {
return [.alert, .sound]
}
}()

func registerForPushNotifications() {
Messaging.messaging().delegate = self
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
}
UIApplication.shared.registerForRemoteNotifications()
updateFirestorePushTokenIfNeeded()
}

func updateFirestorePushTokenIfNeeded() {
if let token = Messaging.messaging().fcmToken {
delegate?.didReceiveNotificationToken(token: token)
}
}

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
updateFirestorePushTokenIfNeeded()
}

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let data = notification.request.content.userInfo
print("Notification Data: \(data)")
completionHandler(pushNotificationOption)
}

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let data = response.notification.request.content.userInfo
print("Notification Data: \(data)")
completionHandler()
}

func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
print("Notification Data New", data)
}

}
8 changes: 8 additions & 0 deletions Shared/Extensions/Userdefaults+Extention.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ extension UserDefaults {
}
}

static var fcm_token: String {
get {
self.standard.string(forKey: "fcm_token") ?? ""
} set {
self.standard.set(newValue, forKey: "fcm_token")
}
}

static var userId: String {
get {
self.standard.string(forKey: "user_id") ?? ""
Expand Down
30 changes: 30 additions & 0 deletions Shared/GoogleService-Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>API_KEY</key>
<string>AIzaSyANEyeZ1aHmAEmUJenx2EP05xp_bYMbGrU</string>
<key>GCM_SENDER_ID</key>
<string>1012053466850</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>io.codecrow.mage</string>
<key>PROJECT_ID</key>
<string>mage-dev-922da</string>
<key>STORAGE_BUCKET</key>
<string>mage-dev-922da.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:1012053466850:ios:091f4ef2227966551cc8bb</string>
</dict>
</plist>
22 changes: 21 additions & 1 deletion Shared/MageApp/MageApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,36 @@

import SwiftUI
import FirebaseCore
import FirebaseMessaging

class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()

let notificationManager = NotificationManager()
notificationManager.delegate = self
notificationManager.registerForPushNotifications()

return true
}


func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
// Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
}

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {

return true
}
}

extension AppDelegate: NotificationManagerDelegate {

func didReceiveNotificationToken(token: String) {
print("FCM Token: ", token)
UserDefaults.fcm_token = token
}
}
4 changes: 2 additions & 2 deletions Shared/Models/AuthModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ struct AuthData: Codable, Hashable {
}

struct AuthUserData: Codable, Hashable {
let _id: String?
let _id: Int?
let avatar: String?
let createdAt: Int?
let createdAt: String?
let displayName: String?
let isOnline: Bool?
let planDetails: PlanDetails?
Expand Down
10 changes: 7 additions & 3 deletions Shared/Models/Channel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@

import Foundation

struct favorite: Codable, Hashable {

}

struct Channel: Codable, Hashable {
var _id: String
var _id: Int
let title: String
let description: String
let userDetails: User
let userDetails: User?
}

extension Channel {
static var preview: Channel {
Channel(_id: "01234", title: "Test channel", description: "Test channel description", userDetails: User(_id: "1234", username: "testgagansuie", displayName: "Test Gagan Suie", avatar: "img"))
Channel(_id: 01234, title: "Test channel", description: "Test channel description", userDetails: User(_id: "1234", username: "testgagansuie", displayName: "Test Gagan Suie", avatar: "img"))
}
}
14 changes: 9 additions & 5 deletions Shared/Models/ChannelModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class ChannelModel: ObservableObject {

let client = HttpClient()
@Published var channels: [Channel] = []
@Published var favorite: [favorite] = []

func fetchChannels() async throws {
channels = try await client.load(Resource(url: URL.allChannels))
Expand All @@ -25,13 +26,16 @@ class ChannelModel: ObservableObject {
header["userId"] = UserDefaults.userId
header["User-Agent"] = "Mage-Mobile"

let param: [String: String] = [:]
header["deviceToken"] = UserDefaults.token
var param: [String: String] = [:]
param["deviceToken"] = UserDefaults.fcm_token
print(param)

let paramData = try PropertyListSerialization.data(fromPropertyList: param, format: PropertyListSerialization.PropertyListFormat.binary, options: 0)
let paramData = try JSONSerialization.data(withJSONObject: param)

// let paramData = try PropertyListSerialization.data(fromPropertyList: param, format: PropertyListSerialization.PropertyListFormat.binary, options: 0)

print(paramData)
channels = try await client.load(Resource(url: URL.favorites, headers: header, method: .patch(paramData)))
print(channels)
favorite = try await client.load(Resource(url: URL.favorites, headers: header, method: .patch(paramData)))
print(favorite)
}
}
6 changes: 2 additions & 4 deletions Shared/Screens/BrowseScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ struct BrowseScreen: View {

struct BrowseScreen_Previews: PreviewProvider {
static var previews: some View {
NavigationStack {
BrowseScreen()
.environmentObject(ChannelModel())
}
BrowseScreen()
.environmentObject(ChannelModel())
}
}
6 changes: 2 additions & 4 deletions Shared/Screens/ChannelScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ struct ChannelScreen: View {

struct ChannelScreen_Previews: PreviewProvider {
static var previews: some View {
NavigationStack {
ChannelScreen(channel: Channel(_id: "01234", title: "Test Channel", description: "Test channel description", userDetails: User(_id: "1234", username: "testgagansuie", displayName: "Test Gagan Suie", avatar: "img" )))
.environmentObject(ChannelModel())
}
ChannelScreen(channel: Channel(_id: 01234, title: "Test Channel", description: "Test channel description", userDetails: User(_id: "1234", username: "testgagansuie", displayName: "Test Gagan Suie", avatar: "img" )))
.environmentObject(ChannelModel())
}
}
2 changes: 1 addition & 1 deletion Shared/Views/ChannelCellView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct ChannelCellView: View {
HStack(alignment: .firstTextBaseline, spacing: AppConfig.smallRadius) {
Text(channel.title)
.font(AppFonts.font(size: 16, style: .bold))
Text(channel.userDetails.username)
Text(channel.userDetails?.username ?? "")
.font(AppFonts.font(size: 16, style: .medium))
Spacer()
}
Expand Down
3 changes: 2 additions & 1 deletion Shared/mage_iosApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import SwiftUI
struct mage_iosApp: App {

@State var isFromLogin = false

@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

var body: some Scene {
WindowGroup {
LogInScreen(isLogin: _isFromLogin)
Expand Down
8 changes: 8 additions & 0 deletions mage-ios (iOS).entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>
Loading
Loading