From f7c490163bd2233ad15c8929760d2f66cd9c6d28 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Tue, 3 Apr 2018 16:49:43 +0530 Subject: [PATCH 01/33] minor refactoring --- Rocket.Chat.xcodeproj/project.pbxproj | 39 +++- .../xcschemes/Rocket.Chat.xcscheme | 8 +- .../SubscriptionManager+Messages.swift | 52 +++++ .../SubscriptionManager+Rooms.swift | 50 +++++ .../SubscriptionManager+Search.swift | 76 +++++++ .../SubscriptionManager+Typing.swift | 47 +++++ .../SubscriptionManager.swift | 199 ++---------------- 7 files changed, 280 insertions(+), 191 deletions(-) create mode 100644 Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Messages.swift create mode 100644 Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Rooms.swift create mode 100644 Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Search.swift create mode 100644 Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Typing.swift rename Rocket.Chat/Managers/Model/{ => SubscriptionManager}/SubscriptionManager.swift (53%) diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 2f04a7b9a2..7da4a220c0 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -86,6 +86,11 @@ 14FBFF771FB267BF000D400B /* MentionsTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14FBFF761FB267BF000D400B /* MentionsTextFieldTableViewCell.swift */; }; 14FBFF791FB267C9000D400B /* MentionsTextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14FBFF781FB267C9000D400B /* MentionsTextFieldTableViewCell.xib */; }; 15A2FD223558011BFDE03883 /* Pods_Rocket_ChatTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68D870A8D54F5431A14607AE /* Pods_Rocket_ChatTests.framework */; }; + 3330329820738D4600A9514D /* SubscriptionManager+Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329720738D4600A9514D /* SubscriptionManager+Messages.swift */; }; + 3330329A20738E1500A9514D /* SubscriptionManager+Rooms.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329920738E1500A9514D /* SubscriptionManager+Rooms.swift */; }; + 3330329C20738E6000A9514D /* SubscriptionManager+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */; }; + 3330329E20738EBB00A9514D /* SubscriptionManager+Typing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */; }; + 333032A02073940800A9514D /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; 334CFFEE20668DDF003CDB99 /* EmojiCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */; }; 339B692B2050449700F97392 /* KeyboardFrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339B6929205042D300F97392 /* KeyboardFrameView.swift */; }; 33A5C9BE206A561400FE1C8F /* emojiNames.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9BD206A561400FE1C8F /* emojiNames.json */; }; @@ -400,7 +405,6 @@ 80AE2544203E61CF00DC2867 /* ChatMessageUnreadSeparator.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80AE2543203E61CF00DC2867 /* ChatMessageUnreadSeparator.xib */; }; 80B3DC0B202DCE1D004249AD /* SAMLViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3DC0A202DCE1D004249AD /* SAMLViewController.swift */; }; 80C110891FB62F7B00205BB1 /* OAuthViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80C110881FB62F7B00205BB1 /* OAuthViewControllerSpec.swift */; }; - 80C7DD5E1FF46B8000E6647C /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; 80CFB5721F8D697100FC9715 /* ReplyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80CFB5711F8D697100FC9715 /* ReplyView.xib */; }; 80CFB5741F8DA55C00FC9715 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80CFB5731F8DA55C00FC9715 /* ReplyView.swift */; }; 80D955C2202154A300E3F281 /* CASViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D955C1202154A300E3F281 /* CASViewController.swift */; }; @@ -560,6 +564,10 @@ 14F8A291202E65C700175FDC /* Blue-76@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Blue-76@2x.png"; sourceTree = ""; }; 14FBFF761FB267BF000D400B /* MentionsTextFieldTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionsTextFieldTableViewCell.swift; sourceTree = ""; }; 14FBFF781FB267C9000D400B /* MentionsTextFieldTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MentionsTextFieldTableViewCell.xib; sourceTree = ""; }; + 3330329720738D4600A9514D /* SubscriptionManager+Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Messages.swift"; sourceTree = ""; }; + 3330329920738E1500A9514D /* SubscriptionManager+Rooms.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Rooms.swift"; sourceTree = ""; }; + 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Search.swift"; sourceTree = ""; }; + 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Typing.swift"; sourceTree = ""; }; 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionViewCell.swift; sourceTree = ""; }; 339B6929205042D300F97392 /* KeyboardFrameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardFrameView.swift; sourceTree = ""; }; 33A5C9BD206A561400FE1C8F /* emojiNames.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emojiNames.json; sourceTree = ""; }; @@ -1193,6 +1201,18 @@ path = Blue; sourceTree = ""; }; + 3330329F2073905900A9514D /* SubscriptionManager */ = { + isa = PBXGroup; + children = ( + 41DAE93B1D318E280098E068 /* SubscriptionManager.swift */, + 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */, + 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */, + 3330329920738E1500A9514D /* SubscriptionManager+Rooms.swift */, + 3330329720738D4600A9514D /* SubscriptionManager+Messages.swift */, + ); + path = SubscriptionManager; + sourceTree = ""; + }; 33A5C9C0206A565800FE1C8F /* Emojis */ = { isa = PBXGroup; children = ( @@ -1268,7 +1288,7 @@ children = ( 41552F651D30308C0081438D /* AuthManager.swift */, 411D76E41F39F05A00B0A8DF /* AuthSettingsManager.swift */, - 41DAE93B1D318E280098E068 /* SubscriptionManager.swift */, + 3330329F2073905900A9514D /* SubscriptionManager */, 41DC7A1C1D38471700896FC0 /* MessageManager.swift */, 4162E1521D651A8800AAAE49 /* UserManager.swift */, 8073719D1F9688B200D53ADF /* LoginServiceManager.swift */, @@ -2396,7 +2416,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = Rocket.Chat; TargetAttributes = { 41DF76DE1D2C50710028DBF8 = { @@ -2535,9 +2555,8 @@ 41DCB8261DDC828200E1197F /* SubscriptionSearchMoreView.xib in Resources */, 4102E3AA1E532323004BAA82 /* Preferences.storyboard in Resources */, 14F8A288202E659000175FDC /* White-60@3x.png in Resources */, - 80C7DD5E1FF46B8000E6647C /* RCEmojiKit.strings in Resources */, + 333032A02073940800A9514D /* RCEmojiKit.strings in Resources */, 14F8A25E202E64B200175FDC /* BnW-76@2x.png in Resources */, - 80C7DD5E1FF46B8000E6647C /* RCEmojiKit.strings in Resources */, 419D84FE1DF599CA0021F034 /* ChatHeaderViewStatus.xib in Resources */, 4133EDD11DA2835F005AA783 /* ChatMessageImageView.xib in Resources */, 14F8A280202E659000175FDC /* White-76@2x.png in Resources */, @@ -2984,6 +3003,7 @@ 418C74431FA3813F00499577 /* CompoundPickerViewDelegate.swift in Sources */, 80235D1B1F74070100A56CA5 /* SubscriptionMembersRequest.swift in Sources */, 41A1748C1DD9F2F900188E3B /* UIViewControllerExtension.swift in Sources */, + 3330329A20738E1500A9514D /* SubscriptionManager+Rooms.swift in Sources */, 8020CCF51FEAD8C9003424F4 /* EmojiPickerController.swift in Sources */, 41D701D61E67111E00FED2EE /* MessageTextFontAttributes.swift in Sources */, D1D535EE1F708628006625D2 /* APIRequest.swift in Sources */, @@ -3090,6 +3110,8 @@ 99D888F82045DFC500E51306 /* EditProfileTableViewController.swift in Sources */, 0B3A9764202C692D0019CA92 /* ChangeAppIconViewController.swift in Sources */, 41EE157E1E05BED600754D45 /* ChatControllerAutocomplete.swift in Sources */, + 3330329E20738EBB00A9514D /* SubscriptionManager+Typing.swift in Sources */, + 3330329C20738E6000A9514D /* SubscriptionManager+Search.swift in Sources */, 80A63C531F71BD2900FE5AC4 /* UserInfoRequest.swift in Sources */, 80F09A1D1FFFC24800977D0D /* NSAttributedString+CustomEmojis.swift in Sources */, 995FEB2F206286D9004EE38F /* WebBrowserManager.swift in Sources */, @@ -3103,6 +3125,7 @@ 99923773204B3BD800C2D15F /* UploadAvatarRequest.swift in Sources */, 41AC3CD91DCCA0C9002DC39A /* AutocompleteCell.swift in Sources */, 809B530B1FE2B1AB00833DD2 /* UploadClient.swift in Sources */, + 3330329820738D4600A9514D /* SubscriptionManager+Messages.swift in Sources */, D1C536CE1F688B7100EBA8D9 /* UIFontExtensions.swift in Sources */, 8013F8761FD6B5E000EE1A4E /* VersionMiddleware.swift in Sources */, 80235D241F7466FF00A56CA5 /* LoaderTableViewCell.swift in Sources */, @@ -3356,12 +3379,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -3412,12 +3437,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -3577,12 +3604,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/Rocket.Chat.xcodeproj/xcshareddata/xcschemes/Rocket.Chat.xcscheme b/Rocket.Chat.xcodeproj/xcshareddata/xcschemes/Rocket.Chat.xcscheme index 48edf104a9..0962caf636 100644 --- a/Rocket.Chat.xcodeproj/xcshareddata/xcschemes/Rocket.Chat.xcscheme +++ b/Rocket.Chat.xcodeproj/xcshareddata/xcschemes/Rocket.Chat.xcscheme @@ -1,6 +1,6 @@ + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -67,7 +66,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Messages.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Messages.swift new file mode 100644 index 0000000000..11eddb2a4b --- /dev/null +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Messages.swift @@ -0,0 +1,52 @@ +// +// SubscriptionManager+Messages.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/3/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import Foundation + +extension SubscriptionManager { + static func markAsRead(_ subscription: Subscription, completion: @escaping MessageCompletion) { + let request = [ + "msg": "method", + "method": "readMessages", + "params": [subscription.rid] + ] as [String: Any] + + SocketManager.send(request) { response in + guard !response.isError() else { return Log.debug(response.result.string) } + completion(response) + } + } + + static func sendTextMessage(_ message: Message, completion: @escaping MessageCompletion) { + + let request = [ + "msg": "method", + "method": "sendMessage", + "params": [[ + "_id": message.identifier ?? "", + "rid": message.subscription.rid, + "msg": message.text + ]] + ] as [String: Any] + + SocketManager.send(request) { (response) in + guard !response.isError() else { return Log.debug(response.result.string) } + completion(response) + } + } + + static func toggleFavorite(_ subscription: Subscription, completion: @escaping MessageCompletion) { + let request = [ + "msg": "method", + "method": "toggleFavorite", + "params": [subscription.rid, !subscription.favorite] + ] as [String: Any] + + SocketManager.send(request, completion: completion) + } +} diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Rooms.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Rooms.swift new file mode 100644 index 0000000000..460282c052 --- /dev/null +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Rooms.swift @@ -0,0 +1,50 @@ +// +// SubscriptionManager+Rooms.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/3/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import Foundation + +extension SubscriptionManager { + static func createDirectMessage(_ username: String, completion: @escaping MessageCompletion) { + let request = [ + "msg": "method", + "method": "createDirectMessage", + "params": [username] + ] as [String: Any] + + SocketManager.send(request) { response in + guard !response.isError() else { return Log.debug(response.result.string) } + completion(response) + } + } + + static func getRoom(byName name: String, completion: @escaping MessageCompletion) { + let request = [ + "msg": "method", + "method": "getRoomByTypeAndName", + "params": ["c", name] + ] as [String: Any] + + SocketManager.send(request) { response in + guard !response.isError() else { return Log.debug(response.result.string) } + completion(response) + } + } + + static func join(room rid: String, completion: @escaping MessageCompletion) { + let request = [ + "msg": "method", + "method": "joinRoom", + "params": [rid] + ] as [String: Any] + + SocketManager.send(request) { (response) in + guard !response.isError() else { return Log.debug(response.result.string) } + completion(response) + } + } +} diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Search.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Search.swift new file mode 100644 index 0000000000..70051caafd --- /dev/null +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Search.swift @@ -0,0 +1,76 @@ +// +// SubscriptionManager+Search.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/3/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import Foundation +import RealmSwift + +extension SubscriptionManager { + static func spotlight(_ text: String, completion: @escaping MessageCompletionObjectsList) { + let request = [ + "msg": "method", + "method": "spotlight", + "params": [text, NSNull(), ["rooms": true, "users": true]] + ] as [String: Any] + + let currentRealm = Realm.current + SocketManager.send(request) { response in + guard !response.isError() else { + completion([]) + return Log.debug(response.result.string) + } + + var subscriptions = [Subscription]() + var identifiers = [String]() + let rooms = response.result["result"]["rooms"].array + let users = response.result["result"]["users"].array + + currentRealm?.execute({ (realm) in + rooms?.forEach { object in + let subscription = Subscription.getOrCreate(realm: realm, values: object, updates: { (object) in + object?.rid = object?.identifier ?? "" + }) + + if let identifier = subscription.identifier { + identifiers.append(identifier) + } + + subscriptions.append(subscription) + } + + users?.forEach { object in + let user = User.getOrCreate(realm: realm, values: object, updates: nil) + let subscription = Subscription() + subscription.identifier = user.identifier ?? "" + subscription.otherUserId = user.identifier + subscription.type = .directMessage + subscription.name = user.username ?? "" + subscription.fname = user.name ?? "" + subscriptions.append(subscription) + + if let identifier = subscription.identifier { + identifiers.append(identifier) + } + } + + realm.add(subscriptions, update: true) + }, completion: { + var detachedSubscriptions = [Subscription]() + + Realm.executeOnMainThread(realm: currentRealm, { (realm) in + for identifier in identifiers { + if let subscription = realm.object(ofType: Subscription.self, forPrimaryKey: identifier) { + detachedSubscriptions.append(subscription) + } + } + }) + + completion(detachedSubscriptions) + }) + } + } +} diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Typing.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Typing.swift new file mode 100644 index 0000000000..6c11b03dd8 --- /dev/null +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Typing.swift @@ -0,0 +1,47 @@ +// +// SubscriptionManager+Typing.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/3/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import Foundation + +extension SubscriptionManager { + static func subscribeTypingEvent(_ subscription: Subscription, completion: @escaping (String?, Bool) -> Void) { + let eventName = "\(subscription.rid)/typing" + let request = [ + "msg": "sub", + "name": "stream-notify-room", + "id": eventName, + "params": [eventName, false] + ] as [String: Any] + + SocketManager.subscribe(request, eventName: eventName) { response in + guard !response.isError() else { return Log.debug(response.result.string) } + + let msg = response.result["fields"]["args"] + let userNameTyping = msg[0].string + let flag = (msg[1].int ?? 0) > 0 + + completion(userNameTyping, flag) + } + } + + static func sendTypingStatus(_ subscription: Subscription, isTyping: Bool, completion: MessageCompletion? = nil) { + guard let username = AuthManager.currentUser()?.username else { return } + + let request = [ + "msg": "method", + "method": "stream-notify-room", + "params": ["\(subscription.rid)/typing", username, isTyping] + ] as [String: Any] + + SocketManager.send(request) { response in + guard !response.isError() else { return Log.debug(response.result.string) } + + completion?(response) + } + } +} diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift similarity index 53% rename from Rocket.Chat/Managers/Model/SubscriptionManager.swift rename to Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift index 6878d25df7..2013d431ff 100644 --- a/Rocket.Chat/Managers/Model/SubscriptionManager.swift +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift @@ -196,196 +196,33 @@ struct SubscriptionManager { }) } } -} -// MARK: Typing -extension SubscriptionManager { - static func subscribeTypingEvent(_ subscription: Subscription, completion: @escaping (String?, Bool) -> Void) { - let eventName = "\(subscription.rid)/typing" + static func subscribeInAppNotifications() { + guard let user = AuthManager.currentUser() else { return } + + let eventName = "\(user.identifier ?? "")/notifications" let request = [ "msg": "sub", - "name": "stream-notify-room", - "id": eventName, + "name": "stream-notify-user", "params": [eventName, false] - ] as [String: Any] - - SocketManager.subscribe(request, eventName: eventName) { response in - guard !response.isError() else { return Log.debug(response.result.string) } - - let msg = response.result["fields"]["args"] - let userNameTyping = msg[0].string - let flag = (msg[1].int ?? 0) > 0 - - completion(userNameTyping, flag) - } - } - - static func sendTypingStatus(_ subscription: Subscription, isTyping: Bool, completion: MessageCompletion? = nil) { - guard let username = AuthManager.currentUser()?.username else { return } - - let request = [ - "msg": "method", - "method": "stream-notify-room", - "params": ["\(subscription.rid)/typing", username, isTyping] - ] as [String: Any] - - SocketManager.send(request) { response in - guard !response.isError() else { return Log.debug(response.result.string) } - - completion?(response) - } - } -} - -// MARK: Search -extension SubscriptionManager { - static func spotlight(_ text: String, completion: @escaping MessageCompletionObjectsList) { - let request = [ - "msg": "method", - "method": "spotlight", - "params": [text, NSNull(), ["rooms": true, "users": true]] - ] as [String: Any] + ] as [String: Any] let currentRealm = Realm.current - SocketManager.send(request) { response in - guard !response.isError() else { - completion([]) - return Log.debug(response.result.string) - } - - var subscriptions = [Subscription]() - var identifiers = [String]() - let rooms = response.result["result"]["rooms"].array - let users = response.result["result"]["users"].array - - currentRealm?.execute({ (realm) in - rooms?.forEach { object in - let subscription = Subscription.getOrCreate(realm: realm, values: object, updates: { (object) in - object?.rid = object?.identifier ?? "" - }) - - if let identifier = subscription.identifier { - identifiers.append(identifier) - } - - subscriptions.append(subscription) - } - - users?.forEach { object in - let user = User.getOrCreate(realm: realm, values: object, updates: nil) - let subscription = Subscription() - subscription.identifier = user.identifier ?? "" - subscription.otherUserId = user.identifier - subscription.type = .directMessage - subscription.name = user.username ?? "" - subscription.fname = user.name ?? "" - subscriptions.append(subscription) - - if let identifier = subscription.identifier { - identifiers.append(identifier) - } - } - - realm.add(subscriptions, update: true) - }, completion: { - var detachedSubscriptions = [Subscription]() - - Realm.executeOnMainThread(realm: currentRealm, { (realm) in - for identifier in identifiers { - if let subscription = realm.object(ofType: Subscription.self, forPrimaryKey: identifier) { - detachedSubscriptions.append(subscription) - } - } - }) - - completion(detachedSubscriptions) - }) - } - } -} - -// MARK: Rooms, Groups & DMs -extension SubscriptionManager { - static func createDirectMessage(_ username: String, completion: @escaping MessageCompletion) { - let request = [ - "msg": "method", - "method": "createDirectMessage", - "params": [username] - ] as [String: Any] - - SocketManager.send(request) { response in - guard !response.isError() else { return Log.debug(response.result.string) } - completion(response) - } - } - - static func getRoom(byName name: String, completion: @escaping MessageCompletion) { - let request = [ - "msg": "method", - "method": "getRoomByTypeAndName", - "params": ["c", name] - ] as [String: Any] - - SocketManager.send(request) { response in - guard !response.isError() else { return Log.debug(response.result.string) } - completion(response) - } - } - - static func join(room rid: String, completion: @escaping MessageCompletion) { - let request = [ - "msg": "method", - "method": "joinRoom", - "params": [rid] - ] as [String: Any] - - SocketManager.send(request) { (response) in - guard !response.isError() else { return Log.debug(response.result.string) } - completion(response) - } - } -} - -// MARK: Messages -extension SubscriptionManager { - static func markAsRead(_ subscription: Subscription, completion: @escaping MessageCompletion) { - let request = [ - "msg": "method", - "method": "readMessages", - "params": [subscription.rid] - ] as [String: Any] - - SocketManager.send(request) { response in + SocketManager.subscribe(request, eventName: eventName) { response in guard !response.isError() else { return Log.debug(response.result.string) } - completion(response) - } - } - - static func sendTextMessage(_ message: Message, completion: @escaping MessageCompletion) { - let request = [ - "msg": "method", - "method": "sendMessage", - "params": [[ - "_id": message.identifier ?? "", - "rid": message.subscription.rid, - "msg": message.text - ]] - ] as [String: Any] + let object = response.result["fields"]["args"][1] + print(object) - SocketManager.send(request) { (response) in - guard !response.isError() else { return Log.debug(response.result.string) } - completion(response) +// currentRealm?.execute({ (realm) in +// if let rid = object["_id"].string { +// if let subscription = Subscription.find(rid: rid, realm: realm) { +// subscription.mapRoom(object) +// +// realm.add(subscription, update: true) +// } +// } +// }) } } - - static func toggleFavorite(_ subscription: Subscription, completion: @escaping MessageCompletion) { - let request = [ - "msg": "method", - "method": "toggleFavorite", - "params": [subscription.rid, !subscription.favorite] - ] as [String: Any] - - SocketManager.send(request, completion: completion) - } } From 6085621752bac58b0358b0fab5dbcda5c7f848c3 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Tue, 3 Apr 2018 17:59:12 +0530 Subject: [PATCH 02/33] added subscription for notifications --- .../Model/SubscriptionManager/SubscriptionManager.swift | 5 ++--- Rocket.Chat/Managers/Socket/SocketManager.swift | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift index 2013d431ff..6c35d0c907 100644 --- a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift @@ -200,18 +200,17 @@ struct SubscriptionManager { static func subscribeInAppNotifications() { guard let user = AuthManager.currentUser() else { return } - let eventName = "\(user.identifier ?? "")/notifications" + let eventName = "\(user.identifier ?? "")/notification" let request = [ "msg": "sub", "name": "stream-notify-user", "params": [eventName, false] ] as [String: Any] - let currentRealm = Realm.current SocketManager.subscribe(request, eventName: eventName) { response in guard !response.isError() else { return Log.debug(response.result.string) } - let object = response.result["fields"]["args"][1] + let object = response.result["fields"]["args"][0] print(object) // currentRealm?.execute({ (realm) in diff --git a/Rocket.Chat/Managers/Socket/SocketManager.swift b/Rocket.Chat/Managers/Socket/SocketManager.swift index fdacab281c..e1ba0d4928 100644 --- a/Rocket.Chat/Managers/Socket/SocketManager.swift +++ b/Rocket.Chat/Managers/Socket/SocketManager.swift @@ -147,6 +147,7 @@ extension SocketManager { UserManager.changes() SubscriptionManager.changes(auth) SubscriptionManager.subscribeRoomChanges() + SubscriptionManager.subscribeInAppNotifications() PermissionManager.changes() PermissionManager.updatePermissions() CustomEmojiManager.sync() From b66f2dfd259bef51ef278f168fdaa721ad5cbf44 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Wed, 4 Apr 2018 18:30:51 +0530 Subject: [PATCH 03/33] Added Animation --- Rocket.Chat.xcodeproj/project.pbxproj | 33 ++++++- Rocket.Chat/Animation.swift | 47 ++++++++++ Rocket.Chat/AppDelegate.swift | 16 ++++ Rocket.Chat/Managers/LogManager.swift | 2 +- .../SubscriptionManager.swift | 1 + Rocket.Chat/NotificationViewController.swift | 93 +++++++++++++++++++ .../Views/Notification/NotificationView.swift | 21 +++++ .../Views/Notification/NotificationView.xib | 77 +++++++++++++++ 8 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 Rocket.Chat/Animation.swift create mode 100644 Rocket.Chat/NotificationViewController.swift create mode 100644 Rocket.Chat/Views/Notification/NotificationView.swift create mode 100644 Rocket.Chat/Views/Notification/NotificationView.xib diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 793f769973..c8029137f0 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ 3330329C20738E6000A9514D /* SubscriptionManager+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */; }; 3330329E20738EBB00A9514D /* SubscriptionManager+Typing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */; }; 333032A02073940800A9514D /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; + 3331EA102074C37500C9CE30 /* Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3331EA0F2074C37500C9CE30 /* Animation.swift */; }; 334CFFEE20668DDF003CDB99 /* EmojiCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */; }; 339B692B2050449700F97392 /* KeyboardFrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339B6929205042D300F97392 /* KeyboardFrameView.swift */; }; 33A5C9BE206A561400FE1C8F /* emojiNames.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9BD206A561400FE1C8F /* emojiNames.json */; }; @@ -103,6 +104,9 @@ 33A5C9D0206A565800FE1C8F /* food.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C7206A565800FE1C8F /* food.json */; }; 33A5C9D1206A565800FE1C8F /* activity.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C8206A565800FE1C8F /* activity.json */; }; 33A5C9D2206A565800FE1C8F /* nature.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C9206A565800FE1C8F /* nature.json */; }; + 33F73B2C2073BDF400F03F29 /* NotificationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33F73B2A2073BDF400F03F29 /* NotificationView.xib */; }; + 33F73B2D2073BDF400F03F29 /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33F73B2B2073BDF400F03F29 /* NotificationView.swift */; }; + 33F73B302073F24200F03F29 /* NotificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */; }; 35A203212022D3F900B4BE5A /* ChatMessageAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35A203202022D3F900B4BE5A /* ChatMessageAttachmentView.swift */; }; 35BCD301201A57EA00B4BE5A /* Ask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35BCD300201A57EA00B4BE5A /* Ask.swift */; }; 35BCD303201A9FB800B4BE5A /* AskSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35BCD302201A9FB800B4BE5A /* AskSpec.swift */; }; @@ -413,7 +417,6 @@ 80CFB5721F8D697100FC9715 /* ReplyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80CFB5711F8D697100FC9715 /* ReplyView.xib */; }; 80CFB5741F8DA55C00FC9715 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80CFB5731F8DA55C00FC9715 /* ReplyView.swift */; }; 80D955C2202154A300E3F281 /* CASViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D955C1202154A300E3F281 /* CASViewController.swift */; }; - 80DC9A6A20698FA100032BE0 /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; 80E99F291FD8B2B800B70B59 /* UserExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E99F281FD8B2B800B70B59 /* UserExtensions.swift */; }; 80E99F2C1FD8B4BA00B70B59 /* APIExtensionsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E99F2B1FD8B4BA00B70B59 /* APIExtensionsSpec.swift */; }; 80E99F2F1FD8B4F400B70B59 /* UserExtensionsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E99F2E1FD8B4F400B70B59 /* UserExtensionsSpec.swift */; }; @@ -574,6 +577,7 @@ 3330329920738E1500A9514D /* SubscriptionManager+Rooms.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Rooms.swift"; sourceTree = ""; }; 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Search.swift"; sourceTree = ""; }; 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Typing.swift"; sourceTree = ""; }; + 3331EA0F2074C37500C9CE30 /* Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animation.swift; sourceTree = ""; }; 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionViewCell.swift; sourceTree = ""; }; 339B6929205042D300F97392 /* KeyboardFrameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardFrameView.swift; sourceTree = ""; }; 33A5C9BD206A561400FE1C8F /* emojiNames.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emojiNames.json; sourceTree = ""; }; @@ -586,6 +590,9 @@ 33A5C9C7206A565800FE1C8F /* food.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = food.json; sourceTree = ""; }; 33A5C9C8206A565800FE1C8F /* activity.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = activity.json; sourceTree = ""; }; 33A5C9C9206A565800FE1C8F /* nature.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nature.json; sourceTree = ""; }; + 33F73B2A2073BDF400F03F29 /* NotificationView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NotificationView.xib; sourceTree = ""; }; + 33F73B2B2073BDF400F03F29 /* NotificationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; + 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationViewController.swift; sourceTree = ""; }; 35A203202022D3F900B4BE5A /* ChatMessageAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageAttachmentView.swift; sourceTree = ""; }; 35AE3FC690B1D3DC4E9DE715 /* Pods-Rocket.ChatTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Rocket.ChatTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Rocket.ChatTests/Pods-Rocket.ChatTests.release.xcconfig"; sourceTree = ""; }; 35BCD300201A57EA00B4BE5A /* Ask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ask.swift; sourceTree = ""; }; @@ -1240,6 +1247,23 @@ path = Emojis; sourceTree = ""; }; + 33F73B292073BDD800F03F29 /* Notification */ = { + isa = PBXGroup; + children = ( + 33F73B2B2073BDF400F03F29 /* NotificationView.swift */, + 33F73B2A2073BDF400F03F29 /* NotificationView.xib */, + ); + path = Notification; + sourceTree = ""; + }; + 33F73B2E2073F1FC00F03F29 /* Notification */ = { + isa = PBXGroup; + children = ( + 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */, + ); + name = Notification; + sourceTree = ""; + }; 4102E3AB1E53272C004BAA82 /* Preferences */ = { isa = PBXGroup; children = ( @@ -1343,6 +1367,7 @@ 41ADDD471E9DBAE90007A458 /* Loader */, 418C4DC41DC4C05000ABED4C /* Sections */, 41A91AED1E51C4E5005C94B1 /* Subscriptions */, + 33F73B292073BDD800F03F29 /* Notification */, 7758A7621F8FA34300FAA244 /* UIPickerView */, ); path = Views; @@ -1451,6 +1476,7 @@ 4102E3AB1E53272C004BAA82 /* Preferences */, 41E2FA031D414ED400238DFD /* Subscriptions */, 140A95E2202F5321003FD564 /* Drawing */, + 33F73B2E2073F1FC00F03F29 /* Notification */, 41865AF01FC8B1EC00A5E48F /* WebViewEmbedded */, ); name = Controllers; @@ -1804,6 +1830,7 @@ 4174CB0A1D2D990F0086DAC8 /* Controllers */, 0B3A9760202C4DE10019CA92 /* Resources */, 41DF76E21D2C50710028DBF8 /* AppDelegate.swift */, + 3331EA0F2074C37500C9CE30 /* Animation.swift */, 4174CB201D2DD4690086DAC8 /* Rocket.Chat-Bridge.h */, 41DF76EE1D2C50720028DBF8 /* Info.plist */, 41833F4D1DEF16B600E54655 /* Keys.plist */, @@ -2585,6 +2612,7 @@ 419D84FE1DF599CA0021F034 /* ChatHeaderViewStatus.xib in Resources */, 4133EDD11DA2835F005AA783 /* ChatMessageImageView.xib in Resources */, 14F8A280202E659000175FDC /* White-76@2x.png in Resources */, + 33F73B2C2073BDF400F03F29 /* NotificationView.xib in Resources */, 33A5C9CD206A565800FE1C8F /* flags.json in Resources */, 14F8A272202E653E00175FDC /* Grey-29@3x.png in Resources */, 80CFB5721F8D697100FC9715 /* ReplyView.xib in Resources */, @@ -2999,6 +3027,7 @@ 415066881EB8B541003AEA1C /* MessageTextCacheManager.swift in Sources */, 4151B45A1E2D1DD400F8AA1B /* AttachmentModelMapping.swift in Sources */, 80307E3E1FD75CB1006AD9EF /* VOLocalized.swift in Sources */, + 3331EA102074C37500C9CE30 /* Animation.swift in Sources */, 996154B1205197E7009B9857 /* NewPasswordViewModel.swift in Sources */, 411EDED51E3102CB00BC7BE3 /* UploadManager.swift in Sources */, 41D5BC311DAFBEF4009A493A /* UIViewExtentions.swift in Sources */, @@ -3068,6 +3097,7 @@ 412BCC871E55C6B800F7F4EE /* ChatMessageTextView.swift in Sources */, 140A95E6202F7074003FD564 /* DrawingControllerDelegate.swift in Sources */, 80054CF31FD951B100F5ECF9 /* MessagesClient.swift in Sources */, + 33F73B302073F24200F03F29 /* NotificationViewController.swift in Sources */, 80AE2542203E61AF00DC2867 /* ChatMessageUnreadSeparator.swift in Sources */, 8013F86D1FD6B59A00EE1A4E /* APIClient.swift in Sources */, 414D99161EA0E7CB0020F7E9 /* SignupViewController.swift in Sources */, @@ -3114,6 +3144,7 @@ 807371A01F96937100D53ADF /* LoginService.swift in Sources */, 802498F51F7ACDB7005477EC /* ChatMessageAudioView.swift in Sources */, 41EB22331E5E474200AA3AE7 /* UploadVideoCompression.swift in Sources */, + 33F73B2D2073BDF400F03F29 /* NotificationView.swift in Sources */, 806465EE1FED1AFE001F27DB /* EmojiView.swift in Sources */, D12D34031F69C76400AED992 /* SubscriptionExtensions.swift in Sources */, 1435BFA31F9B601600FB2768 /* RCTextView.swift in Sources */, diff --git a/Rocket.Chat/Animation.swift b/Rocket.Chat/Animation.swift new file mode 100644 index 0000000000..66e88eb5d6 --- /dev/null +++ b/Rocket.Chat/Animation.swift @@ -0,0 +1,47 @@ +// +// Animation.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/4/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import UIKit + +struct Animation { + let duration: TimeInterval + let delay: TimeInterval + let closure: () -> Void + + init(duration: TimeInterval, closure: @escaping () -> Void) { + self.delay = 0 + self.duration = duration + self.closure = closure + } + + init(delay: TimeInterval, duration: TimeInterval, closure: @escaping () -> Void) { + self.delay = delay + self.duration = duration + self.closure = closure + } +} + +extension UIView { + static func animate(_ animations: [Animation]) { + guard let animation = animations.first else { return } + UIView.animate( + withDuration: animation.duration, + delay: animation.delay, + options: [], + animations: { animation.closure() }, + completion: { _ in + UIView.animate(Array(animations.dropFirst())) + }) + } + + static func animate(inParallel animations: [Animation]) { + animations.forEach { + UIView.animate(withDuration: $0.duration, delay: $0.delay, options: [], animations: $0.closure, completion: nil) + } + } +} diff --git a/Rocket.Chat/AppDelegate.swift b/Rocket.Chat/AppDelegate.swift index 08eb606cda..d1c72b116b 100644 --- a/Rocket.Chat/AppDelegate.swift +++ b/Rocket.Chat/AppDelegate.swift @@ -15,6 +15,7 @@ import GoogleSignIn class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? + var notificationWindow: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Launcher().prepareToLaunch(with: launchOptions) @@ -36,9 +37,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate { WindowManager.open(.auth(serverUrl: "", credentials: nil)) } + initNotificationWindow() + return true } + func initNotificationWindow() { + notificationWindow = UIWindow(frame: UIScreen.main.bounds) + notificationWindow?.rootViewController = NotificationViewController() + notificationWindow?.windowLevel = UIWindowLevelAlert + notificationWindow?.isUserInteractionEnabled = false + notificationWindow?.makeKeyAndVisible() + } + // MARK: AppDelegate LifeCycle func applicationDidBecomeActive(_ application: UIApplication) { @@ -77,4 +88,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { Log.debug("Fail to register for notification: \(error)") } + + static func displayNotification(title: String, body: String) { + let vc = (UIApplication.shared.delegate as? AppDelegate)?.notificationWindow?.rootViewController as? NotificationViewController + vc?.displayNotification(title: title, body: body) + } } diff --git a/Rocket.Chat/Managers/LogManager.swift b/Rocket.Chat/Managers/LogManager.swift index 659430f04a..e5641855bb 100644 --- a/Rocket.Chat/Managers/LogManager.swift +++ b/Rocket.Chat/Managers/LogManager.swift @@ -13,7 +13,7 @@ final class Log { guard let text = text else { return } #if DEBUG - print(text) +// print(text) #endif } diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift index 6c35d0c907..41a6b13df0 100644 --- a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift @@ -212,6 +212,7 @@ struct SubscriptionManager { let object = response.result["fields"]["args"][0] print(object) + AppDelegate.displayNotification(title: object["title"].stringValue, body: object["text"].stringValue) // currentRealm?.execute({ (realm) in // if let rid = object["_id"].string { diff --git a/Rocket.Chat/NotificationViewController.swift b/Rocket.Chat/NotificationViewController.swift new file mode 100644 index 0000000000..954355adad --- /dev/null +++ b/Rocket.Chat/NotificationViewController.swift @@ -0,0 +1,93 @@ +// +// NotificationViewController.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/3/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import UIKit + +class NotificationViewController: UIViewController { + + var notificationView: NotificationView? { + didSet { + if let oldView = oldValue { + oldView.removeFromSuperview() + } + if let notificationView = notificationView { + view.addSubview(notificationView) + applyConstraints(to: notificationView) + } + } + } + + var notificationViewIsHidden: Bool { + get { + if let visibleConstraint = visibleConstraint, visibleConstraint.isActive { + return false + } + return true + } + + set { + switch newValue { + case true: + visibleConstraint?.isActive = false + hiddenConstraint?.isActive = true + case false: + hiddenConstraint?.isActive = false + visibleConstraint?.isActive = true + } + } + } + + private var hiddenConstraint: NSLayoutConstraint? + private var visibleConstraint: NSLayoutConstraint? + + func applyConstraints(to notificationView: NotificationView) { + notificationView.translatesAutoresizingMaskIntoConstraints = false + let widthConstraint = notificationView.widthAnchor.constraint(equalTo: view.widthAnchor) + widthConstraint.priority = UILayoutPriority.init(rawValue: 999) + NSLayoutConstraint.activate([ +// notificationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), +// notificationView.trailingAnchor.constraint(equalTo: view.trailingAnchor) + notificationView.widthAnchor.constraint(lessThanOrEqualToConstant: 500), + notificationView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + widthConstraint + ]) + visibleConstraint = notificationView.topAnchor.constraint(equalTo: view.topAnchor) + hiddenConstraint = notificationView.bottomAnchor.constraint(equalTo: view.topAnchor) + hiddenConstraint?.isActive = true + } + + override func loadView() { + super.loadView() + view = UIView() + view.layer.masksToBounds = true + } + + override func viewDidLoad() { + super.viewDidLoad() + let notificationView = Bundle.main.loadNibNamed("NotificationView", owner: self, options: nil)?.first as? NotificationView + notificationView?.translatesAutoresizingMaskIntoConstraints = false + self.notificationView = notificationView + } + + func displayNotification(title: String, body: String) { + guard let notificationView = notificationView else { return } + + notificationView.displayNotification(title: title, body: body) + + UIView.animate([ + Animation(duration: 0.3, closure: { + self.notificationViewIsHidden = false + self.view.layoutIfNeeded() + }), + Animation(delay: 3, duration: 0.3, closure: { + self.notificationViewIsHidden = true + self.view.layoutIfNeeded() + }) + ]) + } +} diff --git a/Rocket.Chat/Views/Notification/NotificationView.swift b/Rocket.Chat/Views/Notification/NotificationView.swift new file mode 100644 index 0000000000..eb9161c707 --- /dev/null +++ b/Rocket.Chat/Views/Notification/NotificationView.swift @@ -0,0 +1,21 @@ +// +// NotificationView.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 3/22/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import UIKit + +class NotificationView: UIView { + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var bodyLabel: UILabel! + + func displayNotification(title: String, body: String) { + titleLabel.text = title + bodyLabel.text = body + } + +} diff --git a/Rocket.Chat/Views/Notification/NotificationView.xib b/Rocket.Chat/Views/Notification/NotificationView.xib new file mode 100644 index 0000000000..b4b29227e0 --- /dev/null +++ b/Rocket.Chat/Views/Notification/NotificationView.xib @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2bf9dad839ce4c4e8396bafdd87e63e288397a3c Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Thu, 5 Apr 2018 08:45:38 +0530 Subject: [PATCH 04/33] Notification view constraints changed --- .../Views/Notification/NotificationView.xib | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Rocket.Chat/Views/Notification/NotificationView.xib b/Rocket.Chat/Views/Notification/NotificationView.xib index b4b29227e0..aad8cbc59f 100644 --- a/Rocket.Chat/Views/Notification/NotificationView.xib +++ b/Rocket.Chat/Views/Notification/NotificationView.xib @@ -20,24 +20,24 @@ - + - + - + - + - - - + + + From ecc11fe44c5484621806cf0d1c53dee1f0d82b86 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Fri, 6 Apr 2018 13:24:48 +0530 Subject: [PATCH 05/33] Notification view controller moved to nib. --- Rocket.Chat.xcodeproj/project.pbxproj | 5 +- Rocket.Chat/AppDelegate.swift | 9 +- .../SubscriptionManager.swift | 6 +- Rocket.Chat/NotificationViewController.swift | 97 ++++++++++------- Rocket.Chat/NotificationViewController.xib | 103 ++++++++++++++++++ .../Views/Notification/NotificationView.swift | 29 ++++- 6 files changed, 203 insertions(+), 46 deletions(-) create mode 100644 Rocket.Chat/NotificationViewController.xib diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index d2315edecb..630b0c28e3 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -92,6 +92,7 @@ 3330329E20738EBB00A9514D /* SubscriptionManager+Typing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */; }; 333032A02073940800A9514D /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; 3331EA102074C37500C9CE30 /* Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3331EA0F2074C37500C9CE30 /* Animation.swift */; }; + 333207FF20766E4F00AD3290 /* NotificationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 333207FE20766E4F00AD3290 /* NotificationViewController.xib */; }; 334CFFEE20668DDF003CDB99 /* EmojiCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */; }; 339B692B2050449700F97392 /* KeyboardFrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339B6929205042D300F97392 /* KeyboardFrameView.swift */; }; 33A5C9BE206A561400FE1C8F /* emojiNames.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9BD206A561400FE1C8F /* emojiNames.json */; }; @@ -516,7 +517,6 @@ 80D563752059325A008896D6 /* MimeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D563742059325A008896D6 /* MimeType.swift */; }; 80D5637720593533008896D6 /* ParseItemProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D5637620593533008896D6 /* ParseItemProviders.swift */; }; 80D955C2202154A300E3F281 /* CASViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D955C1202154A300E3F281 /* CASViewController.swift */; }; - 80DC9A6A20698FA100032BE0 /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; 80DC9A6C206BA95600032BE0 /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80DC9A6B206BA95600032BE0 /* Localized.swift */; }; 80DC9A6E206BA96200032BE0 /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80DC9A6B206BA95600032BE0 /* Localized.swift */; }; 80DC9A70206BAC8B00032BE0 /* mimetype.json in Resources */ = {isa = PBXBuildFile; fileRef = 80DC9A6F206BAC8B00032BE0 /* mimetype.json */; }; @@ -721,6 +721,7 @@ 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Search.swift"; sourceTree = ""; }; 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Typing.swift"; sourceTree = ""; }; 3331EA0F2074C37500C9CE30 /* Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animation.swift; sourceTree = ""; }; + 333207FE20766E4F00AD3290 /* NotificationViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationViewController.xib; sourceTree = ""; }; 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionViewCell.swift; sourceTree = ""; }; 339B6929205042D300F97392 /* KeyboardFrameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardFrameView.swift; sourceTree = ""; }; 33A5C9BD206A561400FE1C8F /* emojiNames.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emojiNames.json; sourceTree = ""; }; @@ -1504,6 +1505,7 @@ isa = PBXGroup; children = ( 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */, + 333207FE20766E4F00AD3290 /* NotificationViewController.xib */, ); name = Notification; sourceTree = ""; @@ -3138,6 +3140,7 @@ 14F8A280202E659000175FDC /* White-76@2x.png in Resources */, 33F73B2C2073BDF400F03F29 /* NotificationView.xib in Resources */, 33A5C9CD206A565800FE1C8F /* flags.json in Resources */, + 333207FF20766E4F00AD3290 /* NotificationViewController.xib in Resources */, 14F8A272202E653E00175FDC /* Grey-29@3x.png in Resources */, 80CFB5721F8D697100FC9715 /* ReplyView.xib in Resources */, 14F8A284202E659000175FDC /* White-60@2x.png in Resources */, diff --git a/Rocket.Chat/AppDelegate.swift b/Rocket.Chat/AppDelegate.swift index 148ed799e8..2ab8ebdcd2 100644 --- a/Rocket.Chat/AppDelegate.swift +++ b/Rocket.Chat/AppDelegate.swift @@ -44,7 +44,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func initNotificationWindow() { notificationWindow = UIWindow(frame: UIScreen.main.bounds) - notificationWindow?.rootViewController = NotificationViewController() +// if () { + print(NotificationViewController(nibName: "NotificationViewController", bundle: nil)) +// } + notificationWindow?.rootViewController = NotificationViewController(nibName: "NotificationViewController", bundle: nil) notificationWindow?.windowLevel = UIWindowLevelAlert notificationWindow?.isUserInteractionEnabled = false notificationWindow?.makeKeyAndVisible() @@ -89,8 +92,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Log.debug("Fail to register for notification: \(error)") } - static func displayNotification(title: String, body: String) { + static func displayNotification(title: String, body: String, user: User) { let vc = (UIApplication.shared.delegate as? AppDelegate)?.notificationWindow?.rootViewController as? NotificationViewController - vc?.displayNotification(title: title, body: body) + vc?.displayNotification(title: title, body: body, user: user) } } diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift index 41a6b13df0..7ae4e2f867 100644 --- a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift @@ -212,7 +212,11 @@ struct SubscriptionManager { let object = response.result["fields"]["args"][0] print(object) - AppDelegate.displayNotification(title: object["title"].stringValue, body: object["text"].stringValue) + if let user = User.find(withIdentifier: object["payload"]["sender"]["_id"].stringValue) { + AppDelegate.displayNotification(title: object["title"].stringValue, body: object["text"].stringValue, user: user) + print("User found!") + print(user) + } // currentRealm?.execute({ (realm) in // if let rid = object["_id"].string { diff --git a/Rocket.Chat/NotificationViewController.swift b/Rocket.Chat/NotificationViewController.swift index 954355adad..feca16213b 100644 --- a/Rocket.Chat/NotificationViewController.swift +++ b/Rocket.Chat/NotificationViewController.swift @@ -10,17 +10,7 @@ import UIKit class NotificationViewController: UIViewController { - var notificationView: NotificationView? { - didSet { - if let oldView = oldValue { - oldView.removeFromSuperview() - } - if let notificationView = notificationView { - view.addSubview(notificationView) - applyConstraints(to: notificationView) - } - } - } + @IBOutlet weak var notificationView: NotificationView! var notificationViewIsHidden: Bool { get { @@ -42,42 +32,69 @@ class NotificationViewController: UIViewController { } } - private var hiddenConstraint: NSLayoutConstraint? - private var visibleConstraint: NSLayoutConstraint? + override func viewDidLoad() { + super.viewDidLoad() + view.layer.shadowColor = UIColor.black.cgColor + view.layer.shadowOpacity = 0.2 + view.layer.shadowOffset = CGSize(width: 0, height: 0) + } + + @IBOutlet private weak var hiddenConstraint: NSLayoutConstraint! + @IBOutlet private weak var visibleConstraint: NSLayoutConstraint! + +// func applyConstraints(to notificationView: NotificationView) { +// notificationView.translatesAutoresizingMaskIntoConstraints = false +// +// NSLayoutConstraint.deactivate(constraints) +// hiddenConstraint?.isActive = false +// visibleConstraint?.isActive = false +// constraints.removeAll() +// switch traitCollection.horizontalSizeClass { +// case .compact: applyConstraintsForCompactWidth() +// case .regular: applyConstraintsForCompactWidth() +// default: break +// } +//// let widthConstraint = notificationView.widthAnchor.constraint(equalTo: view.widthAnchor) +//// widthConstraint.priority = UILayoutPriority.init(rawValue: 999) +//// NSLayoutConstraint.activate([ +////// notificationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), +////// notificationView.trailingAnchor.constraint(equalTo: view.trailingAnchor) +//// notificationView.widthAnchor.constraint(lessThanOrEqualToConstant: 500), +//// notificationView.centerXAnchor.constraint(equalTo: view.centerXAnchor), +//// widthConstraint +//// ]) +// visibleConstraint = notificationView.topAnchor.constraint(equalTo: view.topAnchor) +// hiddenConstraint = notificationView.bottomAnchor.constraint(equalTo: view.topAnchor) +// hiddenConstraint?.isActive = true +// } - func applyConstraints(to notificationView: NotificationView) { - notificationView.translatesAutoresizingMaskIntoConstraints = false - let widthConstraint = notificationView.widthAnchor.constraint(equalTo: view.widthAnchor) - widthConstraint.priority = UILayoutPriority.init(rawValue: 999) - NSLayoutConstraint.activate([ +// func applyConstraintsForCompactWidth() { +// guard let notificationView = notificationView else { return } +// +// constraints = [ // notificationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), // notificationView.trailingAnchor.constraint(equalTo: view.trailingAnchor) - notificationView.widthAnchor.constraint(lessThanOrEqualToConstant: 500), - notificationView.centerXAnchor.constraint(equalTo: view.centerXAnchor), - widthConstraint - ]) - visibleConstraint = notificationView.topAnchor.constraint(equalTo: view.topAnchor) - hiddenConstraint = notificationView.bottomAnchor.constraint(equalTo: view.topAnchor) - hiddenConstraint?.isActive = true - } - - override func loadView() { - super.loadView() - view = UIView() - view.layer.masksToBounds = true - } +// ] +// NSLayoutConstraint.activate(constraints) +// } - override func viewDidLoad() { - super.viewDidLoad() - let notificationView = Bundle.main.loadNibNamed("NotificationView", owner: self, options: nil)?.first as? NotificationView - notificationView?.translatesAutoresizingMaskIntoConstraints = false - self.notificationView = notificationView - } +// override func loadView() { +// super.loadView() +// view = UIView() +// view.layer.masksToBounds = true +// } +// +// override func viewDidLoad() { +// super.viewDidLoad() +// let notificationView = Bundle.main.loadNibNamed("NotificationView", owner: self, options: nil)?.first as? NotificationView +// notificationView?.translatesAutoresizingMaskIntoConstraints = false +// self.notificationView = notificationView +// } - func displayNotification(title: String, body: String) { + func displayNotification(title: String, body: String, user: User) { guard let notificationView = notificationView else { return } - notificationView.displayNotification(title: title, body: body) + notificationView.displayNotification(title: title, body: body, user: user) UIView.animate([ Animation(duration: 0.3, closure: { diff --git a/Rocket.Chat/NotificationViewController.xib b/Rocket.Chat/NotificationViewController.xib new file mode 100644 index 0000000000..98afeff43b --- /dev/null +++ b/Rocket.Chat/NotificationViewController.xib @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Rocket.Chat/Views/Notification/NotificationView.swift b/Rocket.Chat/Views/Notification/NotificationView.swift index eb9161c707..4a69bbcaca 100644 --- a/Rocket.Chat/Views/Notification/NotificationView.swift +++ b/Rocket.Chat/Views/Notification/NotificationView.swift @@ -13,9 +13,36 @@ class NotificationView: UIView { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var bodyLabel: UILabel! - func displayNotification(title: String, body: String) { + @IBOutlet weak var avatarViewContainer: UIView! { + didSet { + avatarViewContainer.layer.cornerRadius = 4 + if let avatarView = AvatarView.instantiateFromNib() { + avatarView.frame = avatarViewContainer.bounds + avatarViewContainer.addSubview(avatarView) + self.avatarView = avatarView + } + } + } + + weak var avatarView: AvatarView! { + didSet { + avatarView.layer.cornerRadius = 4 + avatarView.layer.masksToBounds = true + } + } + + override func awakeFromNib() { + super.awakeFromNib() +// self.layer.borderWidth = 0.5 +// self.layer.borderColor = UIColor.black.withAlphaComponent(0.1).cgColor + self.layer.cornerRadius = 12 + self.clipsToBounds = true + } + + func displayNotification(title: String, body: String, user: User) { titleLabel.text = title bodyLabel.text = body + avatarView.user = user } } From 7a66afde4e3c36a757b741e55f1106e4f4fa84aa Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Sat, 7 Apr 2018 18:51:48 +0530 Subject: [PATCH 06/33] Notification view positioned correctly --- Rocket.Chat/NotificationViewController.swift | 75 +++++++------------- Rocket.Chat/NotificationViewController.xib | 39 +++++----- 2 files changed, 43 insertions(+), 71 deletions(-) diff --git a/Rocket.Chat/NotificationViewController.swift b/Rocket.Chat/NotificationViewController.swift index feca16213b..f247a47694 100644 --- a/Rocket.Chat/NotificationViewController.swift +++ b/Rocket.Chat/NotificationViewController.swift @@ -36,60 +36,30 @@ class NotificationViewController: UIViewController { super.viewDidLoad() view.layer.shadowColor = UIColor.black.cgColor view.layer.shadowOpacity = 0.2 + view.layer.shadowRadius = 8.0 view.layer.shadowOffset = CGSize(width: 0, height: 0) + view.clipsToBounds = true } @IBOutlet private weak var hiddenConstraint: NSLayoutConstraint! @IBOutlet private weak var visibleConstraint: NSLayoutConstraint! -// func applyConstraints(to notificationView: NotificationView) { -// notificationView.translatesAutoresizingMaskIntoConstraints = false -// -// NSLayoutConstraint.deactivate(constraints) -// hiddenConstraint?.isActive = false -// visibleConstraint?.isActive = false -// constraints.removeAll() -// switch traitCollection.horizontalSizeClass { -// case .compact: applyConstraintsForCompactWidth() -// case .regular: applyConstraintsForCompactWidth() -// default: break -// } -//// let widthConstraint = notificationView.widthAnchor.constraint(equalTo: view.widthAnchor) -//// widthConstraint.priority = UILayoutPriority.init(rawValue: 999) -//// NSLayoutConstraint.activate([ -////// notificationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), -////// notificationView.trailingAnchor.constraint(equalTo: view.trailingAnchor) -//// notificationView.widthAnchor.constraint(lessThanOrEqualToConstant: 500), -//// notificationView.centerXAnchor.constraint(equalTo: view.centerXAnchor), -//// widthConstraint -//// ]) -// visibleConstraint = notificationView.topAnchor.constraint(equalTo: view.topAnchor) -// hiddenConstraint = notificationView.bottomAnchor.constraint(equalTo: view.topAnchor) -// hiddenConstraint?.isActive = true -// } + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() -// func applyConstraintsForCompactWidth() { -// guard let notificationView = notificationView else { return } -// -// constraints = [ -// notificationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), -// notificationView.trailingAnchor.constraint(equalTo: view.trailingAnchor) -// ] -// NSLayoutConstraint.activate(constraints) -// } + visibleConstraint.constant = 8 + if #available(iOS 11.0, *) { + if view.safeAreaInsets.top > 20 { + visibleConstraint.constant = 38 + } + } + } -// override func loadView() { -// super.loadView() -// view = UIView() -// view.layer.masksToBounds = true -// } -// -// override func viewDidLoad() { -// super.viewDidLoad() -// let notificationView = Bundle.main.loadNibNamed("NotificationView", owner: self, options: nil)?.first as? NotificationView -// notificationView?.translatesAutoresizingMaskIntoConstraints = false -// self.notificationView = notificationView -// } + weak var timer: Timer? { + willSet { + timer?.invalidate() + } + } func displayNotification(title: String, body: String, user: User) { guard let notificationView = notificationView else { return } @@ -100,11 +70,16 @@ class NotificationViewController: UIViewController { Animation(duration: 0.3, closure: { self.notificationViewIsHidden = false self.view.layoutIfNeeded() - }), - Animation(delay: 3, duration: 0.3, closure: { - self.notificationViewIsHidden = true - self.view.layoutIfNeeded() }) ]) + + timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false, block: { _ in + UIView.animate([ + Animation(duration: 0.3, closure: { + self.notificationViewIsHidden = true + self.view.layoutIfNeeded() + }) + ]) + }) } } diff --git a/Rocket.Chat/NotificationViewController.xib b/Rocket.Chat/NotificationViewController.xib index 98afeff43b..55dd99a995 100644 --- a/Rocket.Chat/NotificationViewController.xib +++ b/Rocket.Chat/NotificationViewController.xib @@ -27,45 +27,47 @@ - + - + - + - + - + - + + + @@ -81,20 +83,15 @@ - - - - + + + + - - - - - - + From 4cd3e16c1b2dee329245c8499751d478811705ea Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Sat, 7 Apr 2018 23:08:23 +0530 Subject: [PATCH 07/33] Notification view now responds to touches --- Rocket.Chat.xcodeproj/project.pbxproj | 4 ++++ Rocket.Chat/AppDelegate.swift | 6 +---- .../TransparentToTouchesWindow.swift | 23 +++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 Rocket.Chat/Views/Notification/TransparentToTouchesWindow.swift diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 630b0c28e3..326d9e06cb 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -93,6 +93,7 @@ 333032A02073940800A9514D /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; 3331EA102074C37500C9CE30 /* Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3331EA0F2074C37500C9CE30 /* Animation.swift */; }; 333207FF20766E4F00AD3290 /* NotificationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 333207FE20766E4F00AD3290 /* NotificationViewController.xib */; }; + 33383509207926DE006E1D0A /* TransparentToTouchesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */; }; 334CFFEE20668DDF003CDB99 /* EmojiCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */; }; 339B692B2050449700F97392 /* KeyboardFrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339B6929205042D300F97392 /* KeyboardFrameView.swift */; }; 33A5C9BE206A561400FE1C8F /* emojiNames.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9BD206A561400FE1C8F /* emojiNames.json */; }; @@ -722,6 +723,7 @@ 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Typing.swift"; sourceTree = ""; }; 3331EA0F2074C37500C9CE30 /* Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animation.swift; sourceTree = ""; }; 333207FE20766E4F00AD3290 /* NotificationViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationViewController.xib; sourceTree = ""; }; + 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransparentToTouchesWindow.swift; sourceTree = ""; }; 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionViewCell.swift; sourceTree = ""; }; 339B6929205042D300F97392 /* KeyboardFrameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardFrameView.swift; sourceTree = ""; }; 33A5C9BD206A561400FE1C8F /* emojiNames.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emojiNames.json; sourceTree = ""; }; @@ -1495,6 +1497,7 @@ 33F73B292073BDD800F03F29 /* Notification */ = { isa = PBXGroup; children = ( + 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */, 33F73B2B2073BDF400F03F29 /* NotificationView.swift */, 33F73B2A2073BDF400F03F29 /* NotificationView.xib */, ); @@ -3564,6 +3567,7 @@ 41499C8F1F2A116900790EA7 /* ServerManager.swift in Sources */, 41B554C51FBF0C71000510B7 /* UIWindowExtensions.swift in Sources */, 807C7C0620751ED2006B600E /* SpotlightClient.swift in Sources */, + 33383509207926DE006E1D0A /* TransparentToTouchesWindow.swift in Sources */, 4174CB1F1D2DB3350086DAC8 /* StringExtensions.swift in Sources */, 41852E891F92BBEC00D1C499 /* ChatControllerReplyHandler.swift in Sources */, D1C536CC1F688B2F00EBA8D9 /* MarkdownManager.swift in Sources */, diff --git a/Rocket.Chat/AppDelegate.swift b/Rocket.Chat/AppDelegate.swift index 2ab8ebdcd2..9647c9b83d 100644 --- a/Rocket.Chat/AppDelegate.swift +++ b/Rocket.Chat/AppDelegate.swift @@ -43,13 +43,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func initNotificationWindow() { - notificationWindow = UIWindow(frame: UIScreen.main.bounds) -// if () { - print(NotificationViewController(nibName: "NotificationViewController", bundle: nil)) -// } + notificationWindow = TransparentToTouchesWindow(frame: UIScreen.main.bounds) notificationWindow?.rootViewController = NotificationViewController(nibName: "NotificationViewController", bundle: nil) notificationWindow?.windowLevel = UIWindowLevelAlert - notificationWindow?.isUserInteractionEnabled = false notificationWindow?.makeKeyAndVisible() } diff --git a/Rocket.Chat/Views/Notification/TransparentToTouchesWindow.swift b/Rocket.Chat/Views/Notification/TransparentToTouchesWindow.swift new file mode 100644 index 0000000000..3392cfb716 --- /dev/null +++ b/Rocket.Chat/Views/Notification/TransparentToTouchesWindow.swift @@ -0,0 +1,23 @@ +// +// TransparentToTouchesWindow.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 10/17/17. +// Copyright © 2017 Samar Sunkaria. All rights reserved. +// + +import UIKit + +class TransparentToTouchesWindow: UIWindow { + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if let rootViewController = self.rootViewController { + for subview in rootViewController.view.subviews { + if subview.frame.contains(point) { + return super.hitTest(point, with: event) + } + } + } + return nil + } +} From 9010632132a3fe428c20b4a0d2df5ae0eb2c7d91 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Sun, 8 Apr 2018 17:21:08 +0530 Subject: [PATCH 08/33] Added notification manager --- Rocket.Chat.ShareExtension/Info.plist | 16 ++-- .../Rocket.Chat.ShareExtension.entitlements | 2 +- Rocket.Chat.xcodeproj/project.pbxproj | 9 ++ Rocket.Chat/AppDelegate.swift | 7 +- .../NotificationViewController.swift | 52 ++++++------ .../NotificationViewController.xib | 9 +- Rocket.Chat/Info.plist | 2 +- Rocket.Chat/Managers/AppManager.swift | 6 ++ Rocket.Chat/Managers/LogManager.swift | 2 +- .../SubscriptionManager.swift | 19 +---- .../Managers/NotificationManager.swift | 29 +++++++ Rocket.Chat/Models/Notification.swift | 82 +++++++++++++++++++ Rocket.Chat/Models/User/UserUtils.swift | 18 +++- Rocket.Chat/Rocket.Chat.entitlements | 2 +- Rocket.Chat/Views/Avatar/AvatarView.swift | 19 ++++- .../Views/Notification/NotificationView.swift | 6 +- 16 files changed, 211 insertions(+), 69 deletions(-) rename Rocket.Chat/{ => Controllers/Notification}/NotificationViewController.swift (61%) rename Rocket.Chat/{ => Controllers/Notification}/NotificationViewController.xib (95%) create mode 100644 Rocket.Chat/Managers/NotificationManager.swift create mode 100644 Rocket.Chat/Models/Notification.swift diff --git a/Rocket.Chat.ShareExtension/Info.plist b/Rocket.Chat.ShareExtension/Info.plist index ddc9d2153c..93c97766e2 100644 --- a/Rocket.Chat.ShareExtension/Info.plist +++ b/Rocket.Chat.ShareExtension/Info.plist @@ -22,12 +22,10 @@ 1 ITSEncryptionExportComplianceCode - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - NSExtension + NSExtensionActivationSupportsAttachmentsWithMaxCount + 1 NSExtensionAttributes NSExtensionActionWantsFullScreenPresentation @@ -44,18 +42,20 @@ 1 NSExtensionActivationSupportsText - NSExtensionActivationSupportsWebURLWithMaxCount - 1 NSExtensionActivationSupportsWebPageWithMaxCount 1 + NSExtensionActivationSupportsWebURLWithMaxCount + 1 NSExtensionMainStoryboard Main NSExtensionPointIdentifier com.apple.share-services - NSExtensionActivationSupportsAttachmentsWithMaxCount - 1 + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + diff --git a/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements b/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements index f48f06fbc6..175e8d5ca3 100644 --- a/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements +++ b/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.ios.chat.rocket + group.ios.sam.chat.rocket diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index e5720ac471..817bb861f8 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -95,6 +95,7 @@ 333207FF20766E4F00AD3290 /* NotificationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 333207FE20766E4F00AD3290 /* NotificationViewController.xib */; }; 33383509207926DE006E1D0A /* TransparentToTouchesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */; }; 334CFFEE20668DDF003CDB99 /* EmojiCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */; }; + 335F4F03207A31D3005E14AF /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335F4F02207A31D3005E14AF /* NotificationManager.swift */; }; 339B692B2050449700F97392 /* KeyboardFrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339B6929205042D300F97392 /* KeyboardFrameView.swift */; }; 33A5C9BE206A561400FE1C8F /* emojiNames.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9BD206A561400FE1C8F /* emojiNames.json */; }; 33A5C9CA206A565800FE1C8F /* symbols.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C1206A565800FE1C8F /* symbols.json */; }; @@ -106,6 +107,7 @@ 33A5C9D0206A565800FE1C8F /* food.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C7206A565800FE1C8F /* food.json */; }; 33A5C9D1206A565800FE1C8F /* activity.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C8206A565800FE1C8F /* activity.json */; }; 33A5C9D2206A565800FE1C8F /* nature.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C9206A565800FE1C8F /* nature.json */; }; + 33A7AD9E207A2F95000E9D0F /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33A7AD9D207A2F95000E9D0F /* Notification.swift */; }; 33F73B2C2073BDF400F03F29 /* NotificationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33F73B2A2073BDF400F03F29 /* NotificationView.xib */; }; 33F73B2D2073BDF400F03F29 /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33F73B2B2073BDF400F03F29 /* NotificationView.swift */; }; 33F73B302073F24200F03F29 /* NotificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */; }; @@ -725,6 +727,7 @@ 333207FE20766E4F00AD3290 /* NotificationViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationViewController.xib; sourceTree = ""; }; 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransparentToTouchesWindow.swift; sourceTree = ""; }; 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionViewCell.swift; sourceTree = ""; }; + 335F4F02207A31D3005E14AF /* NotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NotificationManager.swift; path = Managers/NotificationManager.swift; sourceTree = ""; }; 339B6929205042D300F97392 /* KeyboardFrameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardFrameView.swift; sourceTree = ""; }; 33A5C9BD206A561400FE1C8F /* emojiNames.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emojiNames.json; sourceTree = ""; }; 33A5C9C1206A565800FE1C8F /* symbols.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = symbols.json; sourceTree = ""; }; @@ -736,6 +739,7 @@ 33A5C9C7206A565800FE1C8F /* food.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = food.json; sourceTree = ""; }; 33A5C9C8206A565800FE1C8F /* activity.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = activity.json; sourceTree = ""; }; 33A5C9C9206A565800FE1C8F /* nature.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nature.json; sourceTree = ""; }; + 33A7AD9D207A2F95000E9D0F /* Notification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 33F73B2A2073BDF400F03F29 /* NotificationView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NotificationView.xib; sourceTree = ""; }; 33F73B2B2073BDF400F03F29 /* NotificationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationViewController.swift; sourceTree = ""; }; @@ -1511,6 +1515,7 @@ 333207FE20766E4F00AD3290 /* NotificationViewController.xib */, ); name = Notification; + path = Controllers/Notification; sourceTree = ""; }; 4102E3AB1E53272C004BAA82 /* Preferences */ = { @@ -1786,6 +1791,7 @@ 4101BF001F8D0A1700F67E89 /* AppManager.swift */, D1C536CB1F688B2F00EBA8D9 /* MarkdownManager.swift */, 4174CB1B1D2DB2080086DAC8 /* LogManager.swift */, + 335F4F02207A31D3005E14AF /* NotificationManager.swift */, 415DC7F51F67F5D30039FB4F /* NetworkManager.swift */, B5893BF31F6C4A5E00365768 /* UserReviewManager.swift */, 597ECBA31E3708B10041C5C5 /* PushManager.swift */, @@ -1939,6 +1945,7 @@ 41900C261D9FE35400308EF4 /* Attachment.swift */, 41A87BAC1DA66E700000EE80 /* AuthSettings.swift */, 8013F8661FD6B4F400EE1A4E /* Command.swift */, + 33A7AD9D207A2F95000E9D0F /* Notification.swift */, 8073719F1F96937100D53ADF /* LoginService.swift */, 806401301FB09DE800990572 /* Permission.swift */, 805DEC361FFC08870033151B /* CustomEmoji.swift */, @@ -3718,6 +3725,7 @@ 802A4E24204D73100072CD23 /* AppGroup.swift in Sources */, 8076FDE62048CD0600114F28 /* UserDefaults+Group.swift in Sources */, 41CABFFC1F50515100E0B289 /* ArrayExtensions.swift in Sources */, + 335F4F03207A31D3005E14AF /* NotificationManager.swift in Sources */, 35E892CA201CDD9700B4BE5A /* PreferencesViewModel.swift in Sources */, 807371A01F96937100D53ADF /* LoginService.swift in Sources */, 802498F51F7ACDB7005477EC /* ChatMessageAudioView.swift in Sources */, @@ -3818,6 +3826,7 @@ 807C7C0820751EDC006B600E /* SpotlightRequest.swift in Sources */, 41D894021F4EF64200E284D2 /* ChatDirectMessageHeaderCell.swift in Sources */, 4112DC581FFFB9B2005995E1 /* BaseModel.swift in Sources */, + 33A7AD9E207A2F95000E9D0F /* Notification.swift in Sources */, 41A87BAD1DA66E700000EE80 /* AuthSettings.swift in Sources */, 8076FDBB2048591A00114F28 /* AuthManagerRecover.swift in Sources */, 8013F8671FD6B4F400EE1A4E /* Command.swift in Sources */, diff --git a/Rocket.Chat/AppDelegate.swift b/Rocket.Chat/AppDelegate.swift index 9647c9b83d..986ead46e9 100644 --- a/Rocket.Chat/AppDelegate.swift +++ b/Rocket.Chat/AppDelegate.swift @@ -44,7 +44,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func initNotificationWindow() { notificationWindow = TransparentToTouchesWindow(frame: UIScreen.main.bounds) - notificationWindow?.rootViewController = NotificationViewController(nibName: "NotificationViewController", bundle: nil) + notificationWindow?.rootViewController = NotificationViewController.shared notificationWindow?.windowLevel = UIWindowLevelAlert notificationWindow?.makeKeyAndVisible() } @@ -87,9 +87,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { Log.debug("Fail to register for notification: \(error)") } - - static func displayNotification(title: String, body: String, user: User) { - let vc = (UIApplication.shared.delegate as? AppDelegate)?.notificationWindow?.rootViewController as? NotificationViewController - vc?.displayNotification(title: title, body: body, user: user) - } } diff --git a/Rocket.Chat/NotificationViewController.swift b/Rocket.Chat/Controllers/Notification/NotificationViewController.swift similarity index 61% rename from Rocket.Chat/NotificationViewController.swift rename to Rocket.Chat/Controllers/Notification/NotificationViewController.swift index f247a47694..887e18cb8f 100644 --- a/Rocket.Chat/NotificationViewController.swift +++ b/Rocket.Chat/Controllers/Notification/NotificationViewController.swift @@ -10,6 +10,8 @@ import UIKit class NotificationViewController: UIViewController { + static let shared = NotificationViewController(nibName: "NotificationViewController", bundle: nil) + @IBOutlet weak var notificationView: NotificationView! var notificationViewIsHidden: Bool { @@ -21,21 +23,16 @@ class NotificationViewController: UIViewController { } set { - switch newValue { - case true: - visibleConstraint?.isActive = false - hiddenConstraint?.isActive = true - case false: - hiddenConstraint?.isActive = false - visibleConstraint?.isActive = true - } + visibleConstraint?.isActive = !newValue + hiddenConstraint?.isActive = newValue + (UIApplication.shared.value(forKey: "statusBarWindow") as? UIWindow)?.alpha = newValue ? 1 : 0 } } override func viewDidLoad() { super.viewDidLoad() view.layer.shadowColor = UIColor.black.cgColor - view.layer.shadowOpacity = 0.2 + view.layer.shadowOpacity = 0.3 view.layer.shadowRadius = 8.0 view.layer.shadowOffset = CGSize(width: 0, height: 0) view.clipsToBounds = true @@ -61,25 +58,30 @@ class NotificationViewController: UIViewController { } } - func displayNotification(title: String, body: String, user: User) { + func displayNotification(title: String, body: String, username: String) { guard let notificationView = notificationView else { return } - notificationView.displayNotification(title: title, body: body, user: user) + notificationView.displayNotification(title: title, body: body, username: username) - UIView.animate([ - Animation(duration: 0.3, closure: { - self.notificationViewIsHidden = false + UIView.animate(withDuration: 0.3) { + self.notificationViewIsHidden = false + self.view.layoutIfNeeded() + } + + timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in + UIView.animate(withDuration: 0.3) { + self.notificationViewIsHidden = true self.view.layoutIfNeeded() - }) - ]) - - timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false, block: { _ in - UIView.animate([ - Animation(duration: 0.3, closure: { - self.notificationViewIsHidden = true - self.view.layoutIfNeeded() - }) - ]) - }) + } + } + } +} + +extension NotificationViewController { + @IBAction func handleTap(_ sender: UITapGestureRecognizer) { + if sender.state == .ended { + NotificationManager.didRespondToNotification() + timer?.fire() + } } } diff --git a/Rocket.Chat/NotificationViewController.xib b/Rocket.Chat/Controllers/Notification/NotificationViewController.xib similarity index 95% rename from Rocket.Chat/NotificationViewController.xib rename to Rocket.Chat/Controllers/Notification/NotificationViewController.xib index 55dd99a995..7e29e21208 100644 --- a/Rocket.Chat/NotificationViewController.xib +++ b/Rocket.Chat/Controllers/Notification/NotificationViewController.xib @@ -60,12 +60,13 @@ + - + @@ -78,6 +79,7 @@ + @@ -96,5 +98,10 @@ + + + + + diff --git a/Rocket.Chat/Info.plist b/Rocket.Chat/Info.plist index a2e28707ee..a8ccc6462a 100644 --- a/Rocket.Chat/Info.plist +++ b/Rocket.Chat/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - Rocket.Chat+ + Rocket.Test CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIcons diff --git a/Rocket.Chat/Managers/AppManager.swift b/Rocket.Chat/Managers/AppManager.swift index 32b389c5ec..c4e388d092 100644 --- a/Rocket.Chat/Managers/AppManager.swift +++ b/Rocket.Chat/Managers/AppManager.swift @@ -44,6 +44,12 @@ struct AppManager { */ static var initialRoomId: String? + /** + Room Id for the currently active room. + */ + static var currentRoomId: String? { + return ChatViewController.shared?.subscription?.rid + } } extension AppManager { diff --git a/Rocket.Chat/Managers/LogManager.swift b/Rocket.Chat/Managers/LogManager.swift index e5641855bb..659430f04a 100644 --- a/Rocket.Chat/Managers/LogManager.swift +++ b/Rocket.Chat/Managers/LogManager.swift @@ -13,7 +13,7 @@ final class Log { guard let text = text else { return } #if DEBUG -// print(text) + print(text) #endif } diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift index 7ae4e2f867..012d53b9e7 100644 --- a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift @@ -210,23 +210,10 @@ struct SubscriptionManager { SocketManager.subscribe(request, eventName: eventName) { response in guard !response.isError() else { return Log.debug(response.result.string) } - let object = response.result["fields"]["args"][0] - print(object) - if let user = User.find(withIdentifier: object["payload"]["sender"]["_id"].stringValue) { - AppDelegate.displayNotification(title: object["title"].stringValue, body: object["text"].stringValue, user: user) - print("User found!") - print(user) + if let data = try? response.result["fields"]["args"][0].rawData() { + let notification = try? JSONDecoder().decode(ChatNotification.self, from: data) + notification?.post() } - -// currentRealm?.execute({ (realm) in -// if let rid = object["_id"].string { -// if let subscription = Subscription.find(rid: rid, realm: realm) { -// subscription.mapRoom(object) -// -// realm.add(subscription, update: true) -// } -// } -// }) } } } diff --git a/Rocket.Chat/Managers/NotificationManager.swift b/Rocket.Chat/Managers/NotificationManager.swift new file mode 100644 index 0000000000..096fc05d91 --- /dev/null +++ b/Rocket.Chat/Managers/NotificationManager.swift @@ -0,0 +1,29 @@ +// +// NotificationManager.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/8/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import Foundation + +class NotificationManager { + static let shared = NotificationManager() + + var notification: ChatNotification? + + static func post(notification: ChatNotification) { + guard AppManager.currentRoomId != notification.rid else { return } + NotificationViewController.shared.displayNotification(title: notification.title, body: notification.body, username: notification.sender.username) + NotificationManager.shared.notification = notification + } + + static func didRespondToNotification() { + guard let notification = NotificationManager.shared.notification else { return } + switch notification.type { + case .channel(let name): AppManager.openChannel(name: name) + case .direct(let sender): AppManager.openDirectMessage(username: sender.username) + } + } +} diff --git a/Rocket.Chat/Models/Notification.swift b/Rocket.Chat/Models/Notification.swift new file mode 100644 index 0000000000..effac35779 --- /dev/null +++ b/Rocket.Chat/Models/Notification.swift @@ -0,0 +1,82 @@ +// +// Notification.swift +// Rocket.Chat +// +// Created by Samar Sunkaria on 4/8/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import Foundation + +struct ChatNotification { + let sender: Sender + let type: NotificationType + let title: String + let body: String + let rid: String +} + +extension ChatNotification { + // swiftlint:disable nesting + struct Sender: Codable { + let name: String + let username: String + let id: String + + enum CodingKeys: String, CodingKey { + case name + case username + case id = "_id" + } + } + + enum NotificationType { + case channel(String) + case direct(Sender) + } +} + +extension ChatNotification: Decodable { + enum CodingKeys: String, CodingKey { + case title + case body = "text" + case payload + } + + enum PayloadKeys: String, CodingKey { + case sender + case channel = "name" + case type + case rid + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.title = try container.decode(String.self, forKey: .title) + self.body = try container.decode(String.self, forKey: .body).trimmingCharacters(in: .newlines) + let payload = try container.nestedContainer(keyedBy: PayloadKeys.self, forKey: .payload) + self.sender = try payload.decode(Sender.self, forKey: .sender) + self.rid = try payload.decode(String.self, forKey: .rid) + self.type = try ChatNotification.notificationType(from: payload) + } + + static func notificationType(from container: KeyedDecodingContainer) throws -> NotificationType { + let type = try container.decode(String.self, forKey: .type) + switch type { + case "d": + let sender = try container.decode(Sender.self, forKey: .sender) + return .direct(sender) + case "c": + let channel = try container.decode(String.self, forKey: .channel) + return .channel(channel) + default: + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [PayloadKeys.type], debugDescription: "Type of notification not supported")) + } + } +} + +extension ChatNotification { + func post() { + NotificationManager.post(notification: self) + } +} diff --git a/Rocket.Chat/Models/User/UserUtils.swift b/Rocket.Chat/Models/User/UserUtils.swift index baa04caa4f..32f2a8d205 100644 --- a/Rocket.Chat/Models/User/UserUtils.swift +++ b/Rocket.Chat/Models/User/UserUtils.swift @@ -39,14 +39,12 @@ extension User { guard !isInvalidated, let username = username, - let auth = auth ?? AuthManager.isAuthenticated(), - let baseURL = auth.baseURL(), - let encodedUsername = username.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) + let auth = auth ?? AuthManager.isAuthenticated() else { return nil } - return URL(string: "\(baseURL)/avatar/\(encodedUsername)") + return User.avatarURL(forUsername: username, auth: auth) } func canViewAdminPanel(realm: Realm? = Realm.current) -> Bool { @@ -55,4 +53,16 @@ extension User { hasPermission(.viewUserAdministration, realm: realm) || hasPermission(.viewRoomAdministration, realm: realm) } + + static func avatarURL(forUsername username: String, auth: Auth? = nil) -> URL? { + guard + let auth = auth ?? AuthManager.isAuthenticated(), + let baseURL = auth.baseURL(), + let encodedUsername = username.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) + else { + return nil + } + + return URL(string: "\(baseURL)/avatar/\(encodedUsername)") + } } diff --git a/Rocket.Chat/Rocket.Chat.entitlements b/Rocket.Chat/Rocket.Chat.entitlements index 5930f012ab..4c01c0fe13 100644 --- a/Rocket.Chat/Rocket.Chat.entitlements +++ b/Rocket.Chat/Rocket.Chat.entitlements @@ -20,7 +20,7 @@ $(TeamIdentifierPrefix)$(CFBundleIdentifier) com.apple.security.application-groups - group.ios.chat.rocket + group.ios.sam.chat.rocket diff --git a/Rocket.Chat/Views/Avatar/AvatarView.swift b/Rocket.Chat/Views/Avatar/AvatarView.swift index 276d7a615d..38a2ebd228 100644 --- a/Rocket.Chat/Views/Avatar/AvatarView.swift +++ b/Rocket.Chat/Views/Avatar/AvatarView.swift @@ -51,6 +51,14 @@ final class AvatarView: UIView { } } + var username: String? { + didSet { + if username != nil { + updateAvatar() + } + } + } + func updateAvatar() { setAvatarWithInitials() @@ -68,6 +76,8 @@ final class AvatarView: UIView { self.imageURL = avatarURL } else if let avatarURL = user?.avatarURL() { self.imageURL = avatarURL + } else if let username = username, let avatarURL = User.avatarURL(forUsername: username) { + self.imageURL = avatarURL } } @@ -115,12 +125,19 @@ final class AvatarView: UIView { private func setAvatarWithInitials() { guard let user = user, !user.isInvalidated else { + if let username = self.username { + setAvatarWithInitials(forUsername: username) + return + } labelInitials?.text = "?" backgroundColor = .black return } + setAvatarWithInitials(forUsername: user.username) + } - let username = user.username ?? "?" + private func setAvatarWithInitials(forUsername username: String?) { + let username = username ?? "?" var initials = "" var color = UIColor.black diff --git a/Rocket.Chat/Views/Notification/NotificationView.swift b/Rocket.Chat/Views/Notification/NotificationView.swift index 4a69bbcaca..0a51dbe26a 100644 --- a/Rocket.Chat/Views/Notification/NotificationView.swift +++ b/Rocket.Chat/Views/Notification/NotificationView.swift @@ -33,16 +33,14 @@ class NotificationView: UIView { override func awakeFromNib() { super.awakeFromNib() -// self.layer.borderWidth = 0.5 -// self.layer.borderColor = UIColor.black.withAlphaComponent(0.1).cgColor self.layer.cornerRadius = 12 self.clipsToBounds = true } - func displayNotification(title: String, body: String, user: User) { + func displayNotification(title: String, body: String, username: String) { titleLabel.text = title bodyLabel.text = body - avatarView.user = user + avatarView.username = username } } From 01a553976f8267aa6d3d991e8fa4be2511a7a58f Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Sun, 8 Apr 2018 17:32:02 +0530 Subject: [PATCH 09/33] Removed notification view nib --- Rocket.Chat.xcodeproj/project.pbxproj | 4 - .../Views/Notification/NotificationView.xib | 77 ------------------- 2 files changed, 81 deletions(-) delete mode 100644 Rocket.Chat/Views/Notification/NotificationView.xib diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 817bb861f8..f9c798b805 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -108,7 +108,6 @@ 33A5C9D1206A565800FE1C8F /* activity.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C8206A565800FE1C8F /* activity.json */; }; 33A5C9D2206A565800FE1C8F /* nature.json in Resources */ = {isa = PBXBuildFile; fileRef = 33A5C9C9206A565800FE1C8F /* nature.json */; }; 33A7AD9E207A2F95000E9D0F /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33A7AD9D207A2F95000E9D0F /* Notification.swift */; }; - 33F73B2C2073BDF400F03F29 /* NotificationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33F73B2A2073BDF400F03F29 /* NotificationView.xib */; }; 33F73B2D2073BDF400F03F29 /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33F73B2B2073BDF400F03F29 /* NotificationView.swift */; }; 33F73B302073F24200F03F29 /* NotificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */; }; 35A203212022D3F900B4BE5A /* ChatMessageAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35A203202022D3F900B4BE5A /* ChatMessageAttachmentView.swift */; }; @@ -740,7 +739,6 @@ 33A5C9C8206A565800FE1C8F /* activity.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = activity.json; sourceTree = ""; }; 33A5C9C9206A565800FE1C8F /* nature.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nature.json; sourceTree = ""; }; 33A7AD9D207A2F95000E9D0F /* Notification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; - 33F73B2A2073BDF400F03F29 /* NotificationView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NotificationView.xib; sourceTree = ""; }; 33F73B2B2073BDF400F03F29 /* NotificationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; 33F73B2F2073F24200F03F29 /* NotificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationViewController.swift; sourceTree = ""; }; 35A203202022D3F900B4BE5A /* ChatMessageAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageAttachmentView.swift; sourceTree = ""; }; @@ -1503,7 +1501,6 @@ children = ( 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */, 33F73B2B2073BDF400F03F29 /* NotificationView.swift */, - 33F73B2A2073BDF400F03F29 /* NotificationView.xib */, ); path = Notification; sourceTree = ""; @@ -3147,7 +3144,6 @@ 419D84FE1DF599CA0021F034 /* ChatHeaderViewStatus.xib in Resources */, 4133EDD11DA2835F005AA783 /* ChatMessageImageView.xib in Resources */, 14F8A280202E659000175FDC /* White-76@2x.png in Resources */, - 33F73B2C2073BDF400F03F29 /* NotificationView.xib in Resources */, 33A5C9CD206A565800FE1C8F /* flags.json in Resources */, 333207FF20766E4F00AD3290 /* NotificationViewController.xib in Resources */, 14F8A272202E653E00175FDC /* Grey-29@3x.png in Resources */, diff --git a/Rocket.Chat/Views/Notification/NotificationView.xib b/Rocket.Chat/Views/Notification/NotificationView.xib deleted file mode 100644 index aad8cbc59f..0000000000 --- a/Rocket.Chat/Views/Notification/NotificationView.xib +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 5b02f359489c58fab2c832e61b6de805f21eaa43 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Sun, 8 Apr 2018 17:34:40 +0530 Subject: [PATCH 10/33] Removed Animation --- Rocket.Chat.xcodeproj/project.pbxproj | 4 --- Rocket.Chat/Animation.swift | 47 --------------------------- 2 files changed, 51 deletions(-) delete mode 100644 Rocket.Chat/Animation.swift diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index f9c798b805..c75b991bb8 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -91,7 +91,6 @@ 3330329C20738E6000A9514D /* SubscriptionManager+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */; }; 3330329E20738EBB00A9514D /* SubscriptionManager+Typing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */; }; 333032A02073940800A9514D /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; - 3331EA102074C37500C9CE30 /* Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3331EA0F2074C37500C9CE30 /* Animation.swift */; }; 333207FF20766E4F00AD3290 /* NotificationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 333207FE20766E4F00AD3290 /* NotificationViewController.xib */; }; 33383509207926DE006E1D0A /* TransparentToTouchesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */; }; 334CFFEE20668DDF003CDB99 /* EmojiCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */; }; @@ -722,7 +721,6 @@ 3330329920738E1500A9514D /* SubscriptionManager+Rooms.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Rooms.swift"; sourceTree = ""; }; 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Search.swift"; sourceTree = ""; }; 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Typing.swift"; sourceTree = ""; }; - 3331EA0F2074C37500C9CE30 /* Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animation.swift; sourceTree = ""; }; 333207FE20766E4F00AD3290 /* NotificationViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationViewController.xib; sourceTree = ""; }; 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransparentToTouchesWindow.swift; sourceTree = ""; }; 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionViewCell.swift; sourceTree = ""; }; @@ -2086,7 +2084,6 @@ 4174CB0A1D2D990F0086DAC8 /* Controllers */, 0B3A9760202C4DE10019CA92 /* Resources */, 41DF76E21D2C50710028DBF8 /* AppDelegate.swift */, - 3331EA0F2074C37500C9CE30 /* Animation.swift */, 4174CB201D2DD4690086DAC8 /* Rocket.Chat-Bridge.h */, 41DF76EE1D2C50720028DBF8 /* Info.plist */, 41833F4D1DEF16B600E54655 /* Keys.plist */, @@ -3598,7 +3595,6 @@ 415066881EB8B541003AEA1C /* MessageTextCacheManager.swift in Sources */, 4151B45A1E2D1DD400F8AA1B /* AttachmentModelMapping.swift in Sources */, 80307E3E1FD75CB1006AD9EF /* VOLocalized.swift in Sources */, - 3331EA102074C37500C9CE30 /* Animation.swift in Sources */, 807C7BF920740F3C006B600E /* AuthCanPinMessage.swift in Sources */, 996154B1205197E7009B9857 /* NewPasswordViewModel.swift in Sources */, 411EDED51E3102CB00BC7BE3 /* UploadManager.swift in Sources */, diff --git a/Rocket.Chat/Animation.swift b/Rocket.Chat/Animation.swift deleted file mode 100644 index 66e88eb5d6..0000000000 --- a/Rocket.Chat/Animation.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// Animation.swift -// Rocket.Chat -// -// Created by Samar Sunkaria on 4/4/18. -// Copyright © 2018 Rocket.Chat. All rights reserved. -// - -import UIKit - -struct Animation { - let duration: TimeInterval - let delay: TimeInterval - let closure: () -> Void - - init(duration: TimeInterval, closure: @escaping () -> Void) { - self.delay = 0 - self.duration = duration - self.closure = closure - } - - init(delay: TimeInterval, duration: TimeInterval, closure: @escaping () -> Void) { - self.delay = delay - self.duration = duration - self.closure = closure - } -} - -extension UIView { - static func animate(_ animations: [Animation]) { - guard let animation = animations.first else { return } - UIView.animate( - withDuration: animation.duration, - delay: animation.delay, - options: [], - animations: { animation.closure() }, - completion: { _ in - UIView.animate(Array(animations.dropFirst())) - }) - } - - static func animate(inParallel animations: [Animation]) { - animations.forEach { - UIView.animate(withDuration: $0.duration, delay: $0.delay, options: [], animations: $0.closure, completion: nil) - } - } -} From 869a982aed08c99059af3a9685af8a8c994e0453 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Sun, 8 Apr 2018 18:23:12 +0530 Subject: [PATCH 11/33] Resolved conflict --- Rocket.ChatTests/API/Clients/MessagesClientSpec.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Rocket.ChatTests/API/Clients/MessagesClientSpec.swift b/Rocket.ChatTests/API/Clients/MessagesClientSpec.swift index e029e9e06f..3fa89ca7b9 100644 --- a/Rocket.ChatTests/API/Clients/MessagesClientSpec.swift +++ b/Rocket.ChatTests/API/Clients/MessagesClientSpec.swift @@ -50,11 +50,7 @@ class MessagesClientSpec: XCTestCase, RealmTestCase { expectation.fulfill() } }) -<<<<<<< HEAD - wait(for: [expectation], timeout: 0.5) -======= wait(for: [expectation], timeout: 2) ->>>>>>> fd060fffabab275303a89f80863d6804e630d909 } func testUpdateMessage() { From 0f13d349b6543d0a5dd2931d2251e810fe653438 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Mon, 9 Apr 2018 18:22:39 +0530 Subject: [PATCH 12/33] Added notification sound. --- .../Rocket.Chat.ShareExtension.entitlements | 2 +- Rocket.Chat.xcodeproj/project.pbxproj | 4 ++++ .../NotificationViewController.swift | 9 +++++++++ Rocket.Chat/Resources/chime.mp3 | Bin 0 -> 5248 bytes Rocket.Chat/Rocket.Chat.entitlements | 2 +- 5 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Rocket.Chat/Resources/chime.mp3 diff --git a/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements b/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements index 175e8d5ca3..f48f06fbc6 100644 --- a/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements +++ b/Rocket.Chat.ShareExtension/Rocket.Chat.ShareExtension.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.ios.sam.chat.rocket + group.ios.chat.rocket diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index c75b991bb8..bf624dc0d0 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -92,6 +92,7 @@ 3330329E20738EBB00A9514D /* SubscriptionManager+Typing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */; }; 333032A02073940800A9514D /* RCEmojiKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C7DD601FF46B8000E6647C /* RCEmojiKit.strings */; }; 333207FF20766E4F00AD3290 /* NotificationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 333207FE20766E4F00AD3290 /* NotificationViewController.xib */; }; + 3336047F207B98EA004C9669 /* chime.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 3336047E207B98EA004C9669 /* chime.mp3 */; }; 33383509207926DE006E1D0A /* TransparentToTouchesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */; }; 334CFFEE20668DDF003CDB99 /* EmojiCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */; }; 335F4F03207A31D3005E14AF /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335F4F02207A31D3005E14AF /* NotificationManager.swift */; }; @@ -722,6 +723,7 @@ 3330329B20738E6000A9514D /* SubscriptionManager+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Search.swift"; sourceTree = ""; }; 3330329D20738EBB00A9514D /* SubscriptionManager+Typing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscriptionManager+Typing.swift"; sourceTree = ""; }; 333207FE20766E4F00AD3290 /* NotificationViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationViewController.xib; sourceTree = ""; }; + 3336047E207B98EA004C9669 /* chime.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = chime.mp3; sourceTree = ""; }; 33383508207926DE006E1D0A /* TransparentToTouchesWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransparentToTouchesWindow.swift; sourceTree = ""; }; 334CFFED20668DDF003CDB99 /* EmojiCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCollectionViewCell.swift; sourceTree = ""; }; 335F4F02207A31D3005E14AF /* NotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NotificationManager.swift; path = Managers/NotificationManager.swift; sourceTree = ""; }; @@ -1271,6 +1273,7 @@ 0B3A9760202C4DE10019CA92 /* Resources */ = { isa = PBXGroup; children = ( + 3336047E207B98EA004C9669 /* chime.mp3 */, 14F8A210202E5B2A00175FDC /* AlternateIcons */, 41DF76E91D2C50710028DBF8 /* Assets.xcassets */, 41EB22381E5F056600AA3AE7 /* Localizable.strings */, @@ -3119,6 +3122,7 @@ 14F8A22C202E5CBF00175FDC /* Black-76@3x.png in Resources */, 14F8A297202E65C700175FDC /* Blue-40@2x.png in Resources */, 14F8A271202E653E00175FDC /* Grey-40@3x.png in Resources */, + 3336047F207B98EA004C9669 /* chime.mp3 in Resources */, 14F8A292202E65C700175FDC /* Blue-29@3x.png in Resources */, 14F8A294202E65C700175FDC /* Blue-60@3x.png in Resources */, 41DF76EA1D2C50710028DBF8 /* Assets.xcassets in Resources */, diff --git a/Rocket.Chat/Controllers/Notification/NotificationViewController.swift b/Rocket.Chat/Controllers/Notification/NotificationViewController.swift index 887e18cb8f..776a399974 100644 --- a/Rocket.Chat/Controllers/Notification/NotificationViewController.swift +++ b/Rocket.Chat/Controllers/Notification/NotificationViewController.swift @@ -7,6 +7,7 @@ // import UIKit +import AudioToolbox class NotificationViewController: UIViewController { @@ -62,6 +63,7 @@ class NotificationViewController: UIViewController { guard let notificationView = notificationView else { return } notificationView.displayNotification(title: title, body: body, username: username) + playSound() UIView.animate(withDuration: 0.3) { self.notificationViewIsHidden = false @@ -75,6 +77,13 @@ class NotificationViewController: UIViewController { } } } + + private func playSound() { + guard let soundUrl = Bundle.main.url(forResource: "chime", withExtension: "mp3") else { return } + var soundId: SystemSoundID = 0 + AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundId) + AudioServicesPlayAlertSound(soundId) + } } extension NotificationViewController { diff --git a/Rocket.Chat/Resources/chime.mp3 b/Rocket.Chat/Resources/chime.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a874282455d952bffe1713bfcebb1f8fe7aa28d6 GIT binary patch literal 5248 zcmeI0cTiK!yT=cN8Zd+ap$P=(AfY40LJ*`&D4_{bgLD)@0Y!S}mEILXlOlrjq99VF zDZNNFQbYoX@&gp|LT-5Row5Xw|M#LiuT-{)}|t2q=Q(7@3!dL)&gi!|O#UGmmNun(4guL7X8)v<01`Z+YP{ z2nzT)UK1&Xm#cmLcozTGUk{i6=)a4)lTI*S{jnH^rSy&CZg5;apcNX3+|kB@!|(6w|Nz*d(OYr=oH>1k@CllvezO2n$8a-(n?I6sHg*! zJU0=0h7O~pgJ0qHIpzO@gborhB=QjsttDOBCFlG3gi#Y5UmB z)z8F&t1l+BG(|FlCKNrEPg>dbe^r!G%$3$)06;Cn%HR$A237CcODe4<`)a^q1-Z25 zq{6MwjPs#)b7q8%K>RVZ8t0R_qdZt-U^LCRN)00KH?TkIPj!WKUpCU_Ij(4_f&{Fi zSTISJ$xaRPBdk-cHlEtR-bFr5^sXh((X*rAHiBy9n=(0qrkMH5AcG7xjjf=Bg2qYN z#p)(=>y*P1^fiSW-i@j@)X`q9goU{U`EvEQIusxH2O1(I_v&mEYSMEa38bXE8~F8Z zpk1yD#J$)0z-yw=+(Me-q5%QVAtCB0bDFhK+k;QvgQTQoG+@!eeqQY*ua;7EQxj>w$z;KPGMkSreZb_}wNj>LI=Pj+7_>7s z+FOPK&iSlm{PDbUd}HSy+azL$(@+S=Uez+#9-!mF(FfoG0NhvPxQ463n}rDB$h)fH z2+b1noiu8AFduU{HOu|tfdfNU${RnK$|;`yuL}3y-1}yHmwn7?XlZ|e)~E~nLl4$0 zQ-!)M7qi#NIoGj&<%h^*yNM>FV+qN+r`|Olb(`b5M%Y5-s(iSe@aUkS+MNkkJ&F2g z&ANtuiN4Pj!WU96RO}bZsR*-AX3unQv4B@=agWaO^1*miZP<#x^(GK=VSmmkGmR_1 zoPyY1ipz8}ZsLbtVJrVmC09)oWCo-uwb98W8Pyqnfo{jC6eJb7=5EcXgDjjUu z7^%q7u)F-lG_4S~Om#xT_9*Rl-F`(X<1#JRh=GHY7iW*lDxYMMUUt7md!{@#sf2)p z6Xg%XJrvCfUXr0cbi>V;%XEBY!R)J9D51G>RWYC$$nDq82 zTh`fkw`rpce;#gaKC5#!x#v8}b@}`kj#g$4JIQyE6w>%uNNvTSc$Rl7dx=fB>rhs8 z6{gR~x@{c`UDm{~8#$$bxDQ34CxM!u;%M}9Ud1ufg7{n^j^<^qB^$Q# zw23yAcpObvK|e*!Px)*b%=P^jfh~>dhBLZigFQHq^Ofx>)ry$7f$6ToWXW*F(NZTE zA!@ua;$chB;3D;pst6n2??t~RCsI;Ce6}VLG_ff0600VoVHPGrQ#0HDUV6E@))N#8#kk{a zdi^MWU4eR*Fp|k&;wTAWpftn0@cA-`O(+*}ioko`bLLgdk+q)kyWRs&r3kxi zWJzs7Hs6Cc?H;i`1K5Eesf4+p`C%mU;VXl8bUd%6Q>$DU?Hb~O3n*7w`}OE;=!z>f z<~}01T;c@o>YCe-h;~lDLO{w=mJjH;mALSnC&DpyblGl7d*E+|V2jDsocageo58yk z@6(g0qP^Q|1lQ0o((}eIA1o6#GBQoh4P6vat~EBp+a@-TpdjJPv&YU8_S25rM~zeM z*Y5JU^VY1W)jsXp@u6ghpw3!C^t~MwOBR)O;+Ai*c%@;Q=g~T#(sq6}?vg8OLs<8P za<*v=@Z%;>1Esi=sak1RxR=!@k3hXvuUFB%(Rm*dv3z^S`Gg$6&3BgQbdPH3CPLS< zP{g;q$EAsx*A!rx=j4lz#|dPm+ILU4T@EzM|JXBpu6D$Hh0dxYO;LXzxpe@rVeSaO zA!e_rd?W_R{f-{kjDR_jUP6gWjnkF9>NCpxwwnlVJ0}2JOg`?KT3eo$s=gtS-p=+O zRT=zAAB?%u>bSkg{5@W`{TxSM8&@9D6>76K()ugz`Rkq)x4G64>L}Z)KSV@0>p(`W z&mlL>?W3C{i=u$iOCfWa$WYFe_e*JKqsH9WBMJgE#reYchD{t*t)8USj_`=G!N8Uw z;nXFa0#$l@xutdGvFKh!&9H+#|6aNwzULflfwixUpxMj-V6V#TZv1V^y7qv1fjaC~ znt>MP?Aoq&@FP3Qt{&pRoLfiY8LUYSm6z#o&ew?b>0Az;v1^0$gl=&&b*dgaeTlI< zU#`=IYd_oiB;ym$?%R_*ytTS-<%$x;Icp=d4|WZBxibpDOp)oj%z9b3_1moT%?E4a zLHiltrIWP#39w)UFvRoRE(kom#Yyzkhu_!~^!REQBUB8;D5c52d91$SnGuj{Q4u_P zG`mcbVOUzzWLZeJGT`#0dR!)ml{w{0gD3@MB_=FJU+7lAbv9Je(GCSQ%h|ww_)nrN z74jyBQ(a^dRW7Sn05AxlbLuZ(#9;$jr;61c9&{S?J!-DS7T%g>m(@2d5(l(v zYA&L~7Pow^@!U;zG%X!{AyL@&s_J&Y>Zc&V9Q|Q4p55DApo>LV`d(3;R-@&&UBVv0 zf3yp5DcwL)hz}F)FPvfP7`X7o9S8Mu<&6!kx(FA4v<2m|h=Sa4r0Moj3TTk&ws2j_ zAo!FvFf`r61dFJQF`Mf?MwhHjvR3dToTj{ki!x$&oRZDv6ki1 zDq3F~E}oI<{D7wmyj7oASQj6gzY-m)?(%q4zjc}bbR>1fita@fOg z_v*CL1pv$9F4|ZLY$p69=coaTZt1#f0A~L6L)M*L~sE9dTF=6jj1U^EJ+OCPtyI871_SU)|8M% z9VyZ7l7i+xCsnw6GgHP}yk7=+El$I9Y{#zFr8pr0pV6wjr`EQYvEXK2`wr>fA}h3a z!5DQM!`s{;`PRi6$_v61f$!=p9C9o zW<7C$f!|)()^P?UIpE2(Wz*+#iEh2}9d(Yukt^$DLogKVO7B~|@>}po6K-p9*c)E&N*bWhEL>K^YO5Q? z+H1uY=0>L6xTW{t%8j&=_0~b!K^sz|IXbkW)0n0#NjPE2p*lj2pP_IB_A6i7O#V6j zs5~?~0ZGFsqmK6P8&|{E(uQlD4^7M#49Rnu{a71<>gQ$Ao9&kAKn!%zob6-cykhn$ z-{L3_xhpj##?P|V!7U!Z%@767eaON6ty;6vQ~QvaRK2W%=aOk!G@Iv+98h+OX8C>vEERM)g{L$>vvjQ}FXlVK1!BKN z|KfwAJ1f`pb=Z@8$*_zhh1ck{sVf*dzlTeY-6pL+PfE`%>NJd09G(cb1F#q(Oap%D zX0apw5{}XT4(23!%mM7lk$-OoKCZA^F;me>8|&HhLJT^3PmU_7nNdA4l{)1cN>**^ zs(x~*lN&))AyjtFexo(qe8WY|B2MY)3t#2+jVBJlRPJ|;qasa5W`whH3mDwku-gya z2IHBalxkV$RB9lR@T)1amIg5dZ3=sOfLr-zK{Nz;sp6c}U4;qCC+;^g=ZDux(;FZ9 zqd*vyRj1Ma{B>S5StV@gJ8tLu2|F*743(lazHr6x(16JXN=m{xleT}fJC6w`h2 zI`Rqi_3zJXq(a3%;Uw)y01GX|JYe0Cjswr>LPbtH=_bpy2w#L@h!CDE-0xxkwWELH z``@PNM1-FqsT?Ac2kYFTya2r=dDRT)Aj7pRPlPcbcoIGTHjDXJCrTnhofZ`WK{hFgFCNCZV0P^Hks(;n@e;#Lw(jt5OUxV}?^PH=_ literal 0 HcmV?d00001 diff --git a/Rocket.Chat/Rocket.Chat.entitlements b/Rocket.Chat/Rocket.Chat.entitlements index 4c01c0fe13..5930f012ab 100644 --- a/Rocket.Chat/Rocket.Chat.entitlements +++ b/Rocket.Chat/Rocket.Chat.entitlements @@ -20,7 +20,7 @@ $(TeamIdentifierPrefix)$(CFBundleIdentifier) com.apple.security.application-groups - group.ios.sam.chat.rocket + group.ios.chat.rocket From 344c6ffe126597bd960714dfdd655361036a3de4 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Mon, 9 Apr 2018 20:23:34 +0530 Subject: [PATCH 13/33] App name corrected --- Rocket.Chat/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rocket.Chat/Info.plist b/Rocket.Chat/Info.plist index a8ccc6462a..a2e28707ee 100644 --- a/Rocket.Chat/Info.plist +++ b/Rocket.Chat/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - Rocket.Test + Rocket.Chat+ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIcons From 785dd8dd623425c1103ae71335986f3b040af8bd Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Tue, 10 Apr 2018 00:53:08 +0530 Subject: [PATCH 14/33] Added slide out --- .../NotificationViewController.swift | 58 +++++++++++++++++-- .../NotificationViewController.xib | 11 +++- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/Rocket.Chat/Controllers/Notification/NotificationViewController.swift b/Rocket.Chat/Controllers/Notification/NotificationViewController.swift index 776a399974..1149011d3c 100644 --- a/Rocket.Chat/Controllers/Notification/NotificationViewController.swift +++ b/Rocket.Chat/Controllers/Notification/NotificationViewController.swift @@ -14,6 +14,11 @@ class NotificationViewController: UIViewController { static let shared = NotificationViewController(nibName: "NotificationViewController", bundle: nil) @IBOutlet weak var notificationView: NotificationView! + @IBOutlet private weak var hiddenConstraint: NSLayoutConstraint! + @IBOutlet private weak var visibleConstraint: NSLayoutConstraint! + + var lastTouchLocation: CGPoint? + let animationDuration = 0.3 var notificationViewIsHidden: Bool { get { @@ -39,9 +44,6 @@ class NotificationViewController: UIViewController { view.clipsToBounds = true } - @IBOutlet private weak var hiddenConstraint: NSLayoutConstraint! - @IBOutlet private weak var visibleConstraint: NSLayoutConstraint! - override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() @@ -65,13 +67,13 @@ class NotificationViewController: UIViewController { notificationView.displayNotification(title: title, body: body, username: username) playSound() - UIView.animate(withDuration: 0.3) { + UIView.animate(withDuration: animationDuration) { self.notificationViewIsHidden = false self.view.layoutIfNeeded() } - timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in - UIView.animate(withDuration: 0.3) { + timer = Timer.scheduledTimer(withTimeInterval: 6.0, repeats: false) { _ in + UIView.animate(withDuration: self.animationDuration) { self.notificationViewIsHidden = true self.view.layoutIfNeeded() } @@ -84,6 +86,7 @@ class NotificationViewController: UIViewController { AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundId) AudioServicesPlayAlertSound(soundId) } + } extension NotificationViewController { @@ -93,4 +96,47 @@ extension NotificationViewController { timer?.fire() } } + + @IBAction func handlePan(_ sender: UIPanGestureRecognizer) { + guard let notificationView = notificationView, !notificationViewIsHidden else { return } + switch sender.state { + case .began: + lastTouchLocation = sender.location(in: view) + + case .changed: + guard let lastTouchLocation = lastTouchLocation else { return } + let displacement = sender.location(in: view).y - lastTouchLocation.y + let newYOffset = notificationView.frame.origin.y + displacement + + if newYOffset <= visibleConstraint.constant { + notificationView.frame.origin.y += displacement + self.lastTouchLocation = sender.location(in: view) + + } else if notificationView.bounds.contains(sender.location(in: notificationView)), + newYOffset <= visibleConstraint.constant + 16 { + notificationView.frame.origin.y += displacement / 10 + self.lastTouchLocation = sender.location(in: view) + } + + case .ended: + lastTouchLocation = nil + if sender.velocity(in: view).y < -25 { + timer?.fire() + } else { + view.setNeedsLayout() + UIView.animate(withDuration: animationDuration) { + self.view.layoutIfNeeded() + } + } + + case .cancelled: + lastTouchLocation = nil + view.setNeedsLayout() + UIView.animate(withDuration: animationDuration) { + self.view.layoutIfNeeded() + } + + default: break + } + } } diff --git a/Rocket.Chat/Controllers/Notification/NotificationViewController.xib b/Rocket.Chat/Controllers/Notification/NotificationViewController.xib index 7e29e21208..aa57469dc0 100644 --- a/Rocket.Chat/Controllers/Notification/NotificationViewController.xib +++ b/Rocket.Chat/Controllers/Notification/NotificationViewController.xib @@ -35,10 +35,11 @@ + - -