From 36910aada3c4d54d3d675f4a9e85796557f34984 Mon Sep 17 00:00:00 2001 From: cardoso Date: Fri, 20 Jul 2018 19:30:15 -0300 Subject: [PATCH 01/42] Fix search clearing when pressing search in keyboard --- .../Rooms/SERoomsViewController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift index 216672add6..cb6e53da57 100644 --- a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift +++ b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift @@ -51,14 +51,14 @@ final class SERoomsViewController: SEViewController { // MARK: UISearchBarDelegate extension SERoomsViewController: UISearchBarDelegate { - func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { - store.dispatch(.setSearchRooms(.none)) - } - func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { store.dispatch(.setSearchRooms(.started)) } + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { + store.dispatch(.setSearchRooms(.none)) + } + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { store.dispatch(.setSearchRooms(.searching(searchText))) } From 6b65281f95a32c4ef62eff4e78c8ba2b8833510e Mon Sep 17 00:00:00 2001 From: Pitstopper <18574776+Pitstopper@users.noreply.github.com> Date: Sun, 22 Jul 2018 11:01:30 +0300 Subject: [PATCH 02/42] [i18n] Improvements in Russian translation --- Rocket.Chat/Resources/ru.lproj/Localizable.strings | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Rocket.Chat/Resources/ru.lproj/Localizable.strings b/Rocket.Chat/Resources/ru.lproj/Localizable.strings index 8d3d958204..753ce108fc 100644 --- a/Rocket.Chat/Resources/ru.lproj/Localizable.strings +++ b/Rocket.Chat/Resources/ru.lproj/Localizable.strings @@ -12,8 +12,8 @@ "error.login.title" = "Упс!"; "error.login.message" = "При попытке входа в систему что-то пошло не так"; -"error.signup.title" = "Oops!"; // TODO -"error.signup.empty_input.message" = "All the fields are required for sign up."; // TODO +"error.signup.title" = "Упс!"; +"error.signup.empty_input.message" = "Все поля обязательны для заполнения."; "error.login_unauthorized.title" = "Упс!"; "error.login_unauthorized.message" = "Ваши учетные данные были отклонены! Пожалуйста, попробуйте еще раз."; @@ -168,7 +168,7 @@ "status.online" = "Онлайн"; "status.away" = "Отошел"; "status.busy" = "Занят"; -"status.offline" = "Offline"; //TODO +"status.offline" = "Офлайн"; "status.invisible" = "Невидимый"; // New Room View @@ -307,9 +307,9 @@ "chat.messages.files.list.empty" = "Файлов не найдено"; // Upload Banner -"chat.banner.upload.uploading" = "Uploading %@"; // TODO -"chat.banner.upload.error" = "Failed uploading %@"; // TODO -"chat.banner.upload.retry" = "Try again"; // TODO +"chat.banner.upload.uploading" = "Выгрузка %@"; +"chat.banner.upload.error" = "Ошибка при загрузке %@"; +"chat.banner.upload.retry" = "Попробуйте снова"; // Settings "myaccount.settings.title" = "Настройки"; @@ -373,7 +373,7 @@ "myaccount.settings.profile.new_password.password_required.placeholder" = "Пароль"; // User Action Sheet -"user_action_sheet.info" = "Information"; // TODO +"user_action_sheet.info" = "Информация"; "user_action_sheet.remove" = "Удалить с канала"; "user_action_sheet.remove_confirm.title" = "Удалить этого пользователя"; "user_action_sheet.remove_confirm.message" = "Вы действительно хотите удалить '%@' с канала?"; From f6cca43b50ff6c114c7e6f96464699505a2dba83 Mon Sep 17 00:00:00 2001 From: Pitstopper <18574776+Pitstopper@users.noreply.github.com> Date: Sun, 22 Jul 2018 11:05:32 +0300 Subject: [PATCH 03/42] [i18n] Improvements in Russian translation --- Rocket.Chat/Resources/ru.lproj/InfoPlist.strings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Rocket.Chat/Resources/ru.lproj/InfoPlist.strings b/Rocket.Chat/Resources/ru.lproj/InfoPlist.strings index 7693f0c8c0..bab8d23181 100644 --- a/Rocket.Chat/Resources/ru.lproj/InfoPlist.strings +++ b/Rocket.Chat/Resources/ru.lproj/InfoPlist.strings @@ -7,7 +7,7 @@ */ add-server-shortcut = "добавить сервер"; -NSCameraUsageDescription = "To take photos and record videos"; // TODO -NSMicrophoneUsageDescription = "To record and upload audio and videos"; // TODO -NSPhotoLibraryAddUsageDescription = "To save images to your library"; // TODO -NSPhotoLibraryUsageDescription = "To upload photos from your library"; // TODO +NSCameraUsageDescription = "Чтобы делать фотографии и записывать видео"; +NSMicrophoneUsageDescription = "Запись и загрузка аудио и видео"; +NSPhotoLibraryAddUsageDescription = "Чтобы сохранить изображения в библиотеке"; +NSPhotoLibraryUsageDescription = "Загрузка фотографий из вашей библиотеки"; From 88f677cf93927bf44ca11a9ba17dbaa8a5d95ef3 Mon Sep 17 00:00:00 2001 From: Driton Salihu Date: Sun, 22 Jul 2018 23:22:22 -0400 Subject: [PATCH 04/42] Resolves issue #2003. --- Rocket.Chat/Controllers/Chat/ChatViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatViewController.swift b/Rocket.Chat/Controllers/Chat/ChatViewController.swift index 537dc124eb..08859ed5b0 100644 --- a/Rocket.Chat/Controllers/Chat/ChatViewController.swift +++ b/Rocket.Chat/Controllers/Chat/ChatViewController.swift @@ -1251,7 +1251,7 @@ extension ChatViewController { return } - if subscription.roomReadOnly && subscription.roomOwner != currentUser && !currentUser.hasPermission(.postReadOnly) { + if subscription.roomReadOnly && subscription.roomOwner != currentUser && !currentUser.hasPermission(.postReadOnly, subscription: subscription) { blockMessageSending(reason: localized("chat.read_only")) } else if subscription.roomMuted.contains(username) { blockMessageSending(reason: localized("chat.muted")) From 49bcf20fa4692a0bcdbb961a5a70f003b832bf12 Mon Sep 17 00:00:00 2001 From: cardoso Date: Mon, 23 Jul 2018 10:01:02 -0300 Subject: [PATCH 05/42] Fix cancel button bug --- .../Rooms/SERoomsViewController.swift | 1 + .../Rooms/SERoomsViewModel.swift | 11 ++++++++++- Rocket.Chat.ShareExtension/State/SESearchState.swift | 11 +++++++++++ Rocket.Chat.ShareExtension/State/SEStore.swift | 9 ++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift index cb6e53da57..ce1be51afc 100644 --- a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift +++ b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewController.swift @@ -14,6 +14,7 @@ final class SERoomsViewController: SEViewController { didSet { title = viewModel.title navigationItem.searchController?.searchBar.text = viewModel.searchText + navigationItem.searchController?.searchBar.showsCancelButton = viewModel.showsCancelButton tableView.reloadData() } } diff --git a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift index 9937494541..64b52534f1 100644 --- a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift +++ b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift @@ -29,9 +29,15 @@ struct SERoomsViewModel { let title: String let sections: [SERoomsSection] let searchText: String + let showsCancelButton: Bool static var emptyState: SERoomsViewModel { - return SERoomsViewModel(title: "Error", sections: [], searchText: "") + return SERoomsViewModel( + title: "Error", + sections: [], + searchText: "", + showsCancelButton: false + ) } } @@ -42,10 +48,13 @@ extension SERoomsViewModel { switch state.searchRooms { case .none: searchText = "" + showsCancelButton = false case .started: searchText = "" + showsCancelButton = true case .searching(let text): searchText = text + showsCancelButton = true } let server = state.servers[state.selectedServerIndex] diff --git a/Rocket.Chat.ShareExtension/State/SESearchState.swift b/Rocket.Chat.ShareExtension/State/SESearchState.swift index 80d338db8a..556f8c5746 100644 --- a/Rocket.Chat.ShareExtension/State/SESearchState.swift +++ b/Rocket.Chat.ShareExtension/State/SESearchState.swift @@ -12,4 +12,15 @@ enum SESearchState { case none case started case searching(String) + + var text: String { + switch self { + case .none: + return "" + case .started: + return "" + case .searching(let query): + return query + } + } } diff --git a/Rocket.Chat.ShareExtension/State/SEStore.swift b/Rocket.Chat.ShareExtension/State/SEStore.swift index 97f02c8a63..4624e78d92 100644 --- a/Rocket.Chat.ShareExtension/State/SEStore.swift +++ b/Rocket.Chat.ShareExtension/State/SEStore.swift @@ -29,13 +29,20 @@ final class SEStore { case .setRooms(let rooms): state.rooms = rooms case .setSearchRooms(let search): - state.searchRooms = search + if case .started = search, !state.searchRooms.text.isEmpty { + state.searchRooms = .searching(state.searchRooms.text) + } else { + state.searchRooms = search + } case .setCurrentRoom(let room): state.currentRoom = room case .setScenes(let scenes): state.navigation.scenes = scenes case .makeSceneTransition(let transition): state.navigation.makeTransition(transition) + if state.searchRooms.text.isEmpty { + state.searchRooms = .none + } case .finish: state.navigation.makeTransition(.finish) } From f869cca908cc93217d316a643e86d43825d2c9f7 Mon Sep 17 00:00:00 2001 From: cardoso Date: Mon, 23 Jul 2018 13:40:33 -0300 Subject: [PATCH 06/42] Fetch remote subscriptions on share extension --- .../Base/SENavigationController.swift | 1 + .../Extensions/SEStateAPI.swift | 25 ++++++++++++++++++ .../State/ActionCreators/SelectServer.swift | 17 +++++++++++- .../State/ActionCreators/SubmitContent.swift | 14 ++-------- .../State/SEState.swift | 8 ++++++ Rocket.Chat.xcodeproj/project.pbxproj | 26 +++++++++++++++++++ .../Subscription/SubscriptionsRequest.swift | 8 ++++++ .../Mapping/SESubscriptionModelMapping.swift | 22 ++++++++++++++++ 8 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 Rocket.Chat.ShareExtension/Extensions/SEStateAPI.swift create mode 100644 Rocket.Chat/Models/Mapping/SESubscriptionModelMapping.swift diff --git a/Rocket.Chat.ShareExtension/Base/SENavigationController.swift b/Rocket.Chat.ShareExtension/Base/SENavigationController.swift index f8b9223976..5e1d733b0d 100644 --- a/Rocket.Chat.ShareExtension/Base/SENavigationController.swift +++ b/Rocket.Chat.ShareExtension/Base/SENavigationController.swift @@ -16,6 +16,7 @@ final class SENavigationController: UINavigationController { } ?? [] parseItemProviders(store, itemProviders) + UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation") return nil } diff --git a/Rocket.Chat.ShareExtension/Extensions/SEStateAPI.swift b/Rocket.Chat.ShareExtension/Extensions/SEStateAPI.swift new file mode 100644 index 0000000000..1ae705476a --- /dev/null +++ b/Rocket.Chat.ShareExtension/Extensions/SEStateAPI.swift @@ -0,0 +1,25 @@ +// +// SEStateAPI.swift +// Rocket.Chat.ShareExtension +// +// Created by Matheus Cardoso on 7/23/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import Foundation + +extension SEState { + var api: API? { + guard + let server = selectedServer, + let api = API(host: server.host, version: Version(0, 60, 0)) + else { + return nil + } + + api.userId = server.userId + api.authToken = server.token + + return api + } +} diff --git a/Rocket.Chat.ShareExtension/State/ActionCreators/SelectServer.swift b/Rocket.Chat.ShareExtension/State/ActionCreators/SelectServer.swift index 8c939d40a1..cabd64e21a 100644 --- a/Rocket.Chat.ShareExtension/State/ActionCreators/SelectServer.swift +++ b/Rocket.Chat.ShareExtension/State/ActionCreators/SelectServer.swift @@ -27,7 +27,22 @@ func fetchServers(store: SEStore) -> SEAction { } func fetchRooms(store: SEStore) -> SEAction { - guard let realm = DatabaseManager.databaseInstace(index: store.state.selectedServerIndex) else { return .setRooms([]) } + defer { + let request = SubscriptionsRequest(updatedSince: nil) + store.state.api?.fetch(request) { response in + switch response { + case .resource(let resource): + store.dispatch(.setRooms(resource.subscriptions ?? [])) + case .error: + store.dispatch(.setRooms([])) + } + } + } + + guard let realm = DatabaseManager.databaseInstace(index: store.state.selectedServerIndex) else { + return .setRooms([]) + } + let rooms = Array(realm.objects(Subscription.self).map(Subscription.init)) return .setRooms(rooms) } diff --git a/Rocket.Chat.ShareExtension/State/ActionCreators/SubmitContent.swift b/Rocket.Chat.ShareExtension/State/ActionCreators/SubmitContent.swift index 30f1f692e0..58ffdd4614 100644 --- a/Rocket.Chat.ShareExtension/State/ActionCreators/SubmitContent.swift +++ b/Rocket.Chat.ShareExtension/State/ActionCreators/SubmitContent.swift @@ -34,16 +34,6 @@ fileprivate extension SEStore { } }.enumerated().map { ($0, $1) } } - - var api: API? { - let server = state.servers[state.selectedServerIndex] - - let api = API(host: server.host, version: Version(0, 60, 0)) - api?.userId = server.userId - api?.authToken = server.token - - return api - } } var urlTasks: [URLSessionTask?] = [] @@ -69,7 +59,7 @@ func submitFiles(store: SEStore, completion: @escaping (() -> Void)) { store.dispatch(.setContentValue(content.withStatus(.sending), index: index)) - let task = store.api?.fetch(request) { response in + let task = store.state.api?.fetch(request) { response in switch response { case .resource(let resource): @@ -117,7 +107,7 @@ func submitMessages(store: SEStore, completion: @escaping (() -> Void)) { let content = store.state.content[index] store.dispatch(.setContentValue(content.withStatus(.sending), index: index)) - let task = store.api?.fetch(request) { response in + let task = store.state.api?.fetch(request) { response in switch response { case .resource: DispatchQueue.main.async { diff --git a/Rocket.Chat.ShareExtension/State/SEState.swift b/Rocket.Chat.ShareExtension/State/SEState.swift index 7f2c8250c7..31a6e69c2f 100644 --- a/Rocket.Chat.ShareExtension/State/SEState.swift +++ b/Rocket.Chat.ShareExtension/State/SEState.swift @@ -24,6 +24,14 @@ enum SEAction { struct SEState { var servers: [SEServer] = [] var selectedServerIndex: Int = 0 + var selectedServer: SEServer? { + guard selectedServerIndex < servers.count else { + return nil + } + + return servers[selectedServerIndex] + } + var rooms: [Subscription] = [] var currentRoom = Subscription() var searchRooms: SESearchState = .none diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 78a64ba302..1a0a814283 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -431,6 +431,13 @@ 8039442E20B342BB002F317A /* AddUsersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8039442D20B342BB002F317A /* AddUsersViewController.swift */; }; 8039443020B34B12002F317A /* DirectoryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8039442F20B34B12002F317A /* DirectoryRequest.swift */; }; 8039443220B3988F002F317A /* PagedResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8039443120B3988F002F317A /* PagedResource.swift */; }; + 803D866821062D7E00B1B697 /* SubscriptionsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8062E32820A1CAAB0044F407 /* SubscriptionsRequest.swift */; }; + 803D866C21062F7400B1B697 /* SEStateAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803D866B21062F7400B1B697 /* SEStateAPI.swift */; }; + 803D866D2106307C00B1B697 /* SubscriptionModelMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4151B4551E2D1AFF00F8AA1B /* SubscriptionModelMapping.swift */; }; + 803D866E2106309200B1B697 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41E991D31D343A9F00BDDCA8 /* DateExtension.swift */; }; + 803D866F210630A800B1B697 /* ServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41499C8E1F2A116900790EA7 /* ServerManager.swift */; }; + 803D8670210631D700B1B697 /* ModelMappeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4112DC571FFFB9B1005995E1 /* ModelMappeable.swift */; }; + 803D86762106333900B1B697 /* SESubscriptionModelMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803D86742106333500B1B697 /* SESubscriptionModelMapping.swift */; }; 8041C0402028C7A1007E21FA /* ReactorListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8041C03F2028C7A1007E21FA /* ReactorListViewController.swift */; }; 8041C0422028C7EF007E21FA /* ReactorListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8041C0412028C7EF007E21FA /* ReactorListView.swift */; }; 8041C0442028C828007E21FA /* ReactorListView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8041C0432028C828007E21FA /* ReactorListView.xib */; }; @@ -1257,6 +1264,8 @@ 8039442D20B342BB002F317A /* AddUsersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddUsersViewController.swift; sourceTree = ""; }; 8039442F20B34B12002F317A /* DirectoryRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryRequest.swift; sourceTree = ""; }; 8039443120B3988F002F317A /* PagedResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagedResource.swift; sourceTree = ""; }; + 803D866B21062F7400B1B697 /* SEStateAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SEStateAPI.swift; sourceTree = ""; }; + 803D86742106333500B1B697 /* SESubscriptionModelMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SESubscriptionModelMapping.swift; sourceTree = ""; }; 8041C03F2028C7A1007E21FA /* ReactorListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactorListViewController.swift; sourceTree = ""; }; 8041C0412028C7EF007E21FA /* ReactorListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactorListView.swift; sourceTree = ""; }; 8041C0432028C828007E21FA /* ReactorListView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReactorListView.xib; sourceTree = ""; }; @@ -2438,6 +2447,7 @@ 806401321FB09EC400990572 /* PermissionModelMapping.swift */, 999F25B4207EEB0C002E0F68 /* FileModelMapping.swift */, 4151B4551E2D1AFF00F8AA1B /* SubscriptionModelMapping.swift */, + 803D86742106333500B1B697 /* SESubscriptionModelMapping.swift */, 41BD37E01E290F2900CBC4C2 /* UserModelMapping.swift */, ); path = Mapping; @@ -2843,6 +2853,14 @@ path = VoiceOver; sourceTree = ""; }; + 803D866A21062F5B00B1B697 /* Extensions */ = { + isa = PBXGroup; + children = ( + 803D866B21062F7400B1B697 /* SEStateAPI.swift */, + ); + path = Extensions; + sourceTree = ""; + }; 8045F49920D0597500AA0F3C /* ReadReceipts */ = { isa = PBXGroup; children = ( @@ -3044,6 +3062,7 @@ 8076FDE02048A69200114F28 /* Compose */, 806C2ACE206BBAF200EE5F67 /* External */, 80D5637320593245008896D6 /* Helpers */, + 803D866A21062F5B00B1B697 /* Extensions */, 807FB56C20472B2700E21429 /* Resources */, 807FB57E2048376900E21429 /* Rooms */, 807FB5802048378500E21429 /* Servers */, @@ -4725,6 +4744,7 @@ 80D0CE6620503C860056B17F /* SERoomCell.swift in Sources */, 80FA90722056C1190069038F /* SEComposeTextCell.swift in Sources */, 80D0CE60205016B40056B17F /* SEServerCell.swift in Sources */, + 803D866821062D7E00B1B697 /* SubscriptionsRequest.swift in Sources */, 8076FDCC204863DF00114F28 /* AuthExtensions.swift in Sources */, 80D0CE64205034280056B17F /* SEServerCellModel.swift in Sources */, 8076FDD3204864A400114F28 /* MessageReaction.swift in Sources */, @@ -4734,13 +4754,16 @@ 80977AB9204EFBCC00C41435 /* SENavigation.swift in Sources */, 8076FDDA20489F5900114F28 /* SEViewController.swift in Sources */, 80977AC2204F37C200C41435 /* SEState.swift in Sources */, + 803D86762106333900B1B697 /* SESubscriptionModelMapping.swift in Sources */, 804273E1204EBD51006DF420 /* APIRequest.swift in Sources */, 8076FDCA204863B900114F28 /* Channel.swift in Sources */, 8076FDBD2048598100114F28 /* Subscription.swift in Sources */, + 803D8670210631D700B1B697 /* ModelMappeable.swift in Sources */, 4124D837209A06BD005374CD /* Permission.swift in Sources */, 41D0DA5820991BAE008649E7 /* UploadMessageRequest.swift in Sources */, 804273DE204EBD51006DF420 /* APIClient.swift in Sources */, 8076FDCB204863C500114F28 /* Attachment.swift in Sources */, + 803D866E2106309200B1B697 /* DateExtension.swift in Sources */, 804273D6204D7F38006DF420 /* AppGroup.swift in Sources */, 8076FDE22048A7C500114F28 /* SEComposeHeaderViewController.swift in Sources */, 80DC9A6E206BA96200032BE0 /* Localized.swift in Sources */, @@ -4756,6 +4779,8 @@ 8076FDA62048536800114F28 /* BaseModel.swift in Sources */, 80FA906A20569F890069038F /* SEComposeFileCell.swift in Sources */, 804273DF204EBD51006DF420 /* APIError.swift in Sources */, + 803D866D2106307C00B1B697 /* SubscriptionModelMapping.swift in Sources */, + 803D866C21062F7400B1B697 /* SEStateAPI.swift in Sources */, 806DB94320687697004ED8ED /* Alert.swift in Sources */, 80D0CE752050BFD20056B17F /* AuthUser.swift in Sources */, 8062E33620A5ED200044F407 /* APIRequestOption.swift in Sources */, @@ -4795,6 +4820,7 @@ 804273DD204EBD51006DF420 /* API.swift in Sources */, 8029B2F42059C1840067157B /* UIAlertController+StatusReport.swift in Sources */, 80D0CE742050BFBE0056B17F /* AuthManagerCurrentUser.swift in Sources */, + 803D866F210630A800B1B697 /* ServerManager.swift in Sources */, 80825F0D207EB2D800C477DE /* APIResource.swift in Sources */, 80FA9068205314040069038F /* SEServer.swift in Sources */, ); diff --git a/Rocket.Chat/API/Requests/Subscription/SubscriptionsRequest.swift b/Rocket.Chat/API/Requests/Subscription/SubscriptionsRequest.swift index 4ce17b2031..9655d90030 100644 --- a/Rocket.Chat/API/Requests/Subscription/SubscriptionsRequest.swift +++ b/Rocket.Chat/API/Requests/Subscription/SubscriptionsRequest.swift @@ -52,4 +52,12 @@ final class SubscriptionsResource: APIResource { var success: Bool? { return raw?["success"].bool } + + var subscriptions: [Subscription]? { + return update?.compactMap { + let subscription = Subscription() + subscription.map($0, realm: nil) + return subscription + } + } } diff --git a/Rocket.Chat/Models/Mapping/SESubscriptionModelMapping.swift b/Rocket.Chat/Models/Mapping/SESubscriptionModelMapping.swift new file mode 100644 index 0000000000..0498348cc2 --- /dev/null +++ b/Rocket.Chat/Models/Mapping/SESubscriptionModelMapping.swift @@ -0,0 +1,22 @@ +// +// SESubscriptionModelMapping.swift +// Rocket.Chat.ShareExtension +// +// Created by Matheus Cardoso on 7/23/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import SwiftyJSON +import RealmSwift + +extension Subscription { + static func lastMessageText(lastMessage: Message) -> String { + return "" + } +} + +extension Message { + func map(_ values: JSON, realm: Realm?) { + + } +} From 8f247f807ae40b0919e3dd88829a04fd085b6f2e Mon Sep 17 00:00:00 2001 From: cardoso Date: Mon, 23 Jul 2018 14:28:01 -0300 Subject: [PATCH 07/42] Animate present & dismiss of share extension --- .../Base/SENavigationController.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Rocket.Chat.ShareExtension/Base/SENavigationController.swift b/Rocket.Chat.ShareExtension/Base/SENavigationController.swift index 5e1d733b0d..179fe8ede2 100644 --- a/Rocket.Chat.ShareExtension/Base/SENavigationController.swift +++ b/Rocket.Chat.ShareExtension/Base/SENavigationController.swift @@ -37,9 +37,24 @@ final class SENavigationController: UINavigationController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + + view.transform = CGAffineTransform(translationX: 0, y: view.frame.size.height) + + UIView.animate(withDuration: 0.25) { [weak self] in + self?.view.transform = CGAffineTransform.identity + } + store.subscribe(self) } + override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { + UIView.animate(withDuration: 0.20, animations: { [weak self] in + self?.view.transform = CGAffineTransform(translationX: 0, y: self?.view.frame.height ?? 0) + }, completion: { [weak self] _ in + self?.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) + }) + } + override func viewDidDisappear(_ animated: Bool) { super.viewWillDisappear(animated) store.unsubscribe(self) @@ -84,7 +99,7 @@ extension SENavigationController: SEStoreSubscriber { statusReport() } case .finish: - self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) + dismiss(animated: true) store.clearSubscribers() store.dispatch(.setContent([])) } From 16dcc63580c9e1fbc68a30e4f0a34afc52812649 Mon Sep 17 00:00:00 2001 From: cardoso Date: Mon, 23 Jul 2018 14:44:38 -0300 Subject: [PATCH 08/42] Fix keyboard hidden in landscape position --- Rocket.Chat.ShareExtension/Info.plist | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Rocket.Chat.ShareExtension/Info.plist b/Rocket.Chat.ShareExtension/Info.plist index b9973dcaca..75b7a934b5 100644 --- a/Rocket.Chat.ShareExtension/Info.plist +++ b/Rocket.Chat.ShareExtension/Info.plist @@ -53,9 +53,5 @@ NSExtensionPointIdentifier com.apple.share-services - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - From d6099b2232823eb667aa7c06e0dc590991d7c9f5 Mon Sep 17 00:00:00 2001 From: cardoso Date: Mon, 23 Jul 2018 15:09:54 -0300 Subject: [PATCH 09/42] Do not display favorite rooms in other sections --- Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift index 64b52534f1..cdfacd052e 100644 --- a/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift +++ b/Rocket.Chat.ShareExtension/Rooms/SERoomsViewModel.swift @@ -67,9 +67,10 @@ extension SERoomsViewModel { ($0.type.rawValue, $0.name.lowercased()) < ($1.type.rawValue, $1.name.lowercased()) }.map(roomToCell) - let channels = state.displayedRooms.filter { $0.type == .channel }.map(roomToCell) - let groups = state.displayedRooms.filter { $0.type == .group }.map(roomToCell) - let directMessages = state.displayedRooms.filter { $0.type == .directMessage }.map(roomToCell) + let notFavorites = state.displayedRooms.filter { !$0.favorite } + let channels = notFavorites.filter { $0.type == .channel }.map(roomToCell) + let groups = notFavorites.filter { $0.type == .group }.map(roomToCell) + let directMessages = notFavorites.filter { $0.type == .directMessage }.map(roomToCell) let serverCell = SEServerCellModel(iconUrl: server.iconUrl, name: server.name, host: server.host, selected: false) let serverSection = searchText.isEmpty ? [SERoomsSection(type: .server, cells: [serverCell])] : [] From cf95ea0e63642d794b8639e5b1be52fcf6b26705 Mon Sep 17 00:00:00 2001 From: filipealva Date: Mon, 23 Jul 2018 20:15:33 -0300 Subject: [PATCH 10/42] Add function to BaseModel that checks if a BaseModel instance is valid. If valid it returns the instance otherwise it returns nil --- Rocket.Chat/Models/Base/BaseModel.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Rocket.Chat/Models/Base/BaseModel.swift b/Rocket.Chat/Models/Base/BaseModel.swift index 373b9f295b..f99925f9f4 100644 --- a/Rocket.Chat/Models/Base/BaseModel.swift +++ b/Rocket.Chat/Models/Base/BaseModel.swift @@ -35,3 +35,13 @@ class BaseModel: Object { return true } } + +extension BaseModel { + func validated() -> Self? { + guard !isInvalidated else { + return nil + } + + return self + } +} From 8e497ad3e964570bd0df896253e9e7b42f4d285c Mon Sep 17 00:00:00 2001 From: filipealva Date: Mon, 23 Jul 2018 20:16:13 -0300 Subject: [PATCH 11/42] Fix object invalidated crash when trying to load the history of an invalidated subscription --- Rocket.Chat/Controllers/Chat/ChatViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatViewController.swift b/Rocket.Chat/Controllers/Chat/ChatViewController.swift index 08859ed5b0..41b22060ee 100644 --- a/Rocket.Chat/Controllers/Chat/ChatViewController.swift +++ b/Rocket.Chat/Controllers/Chat/ChatViewController.swift @@ -765,7 +765,7 @@ final class ChatViewController: SLKTextViewController { } func loadHistoryFromRemote(date: Date?, loadNextPage: Bool = true) { - guard let subscription = subscription else { return } + guard let subscription = subscription?.validated() else { return } let tempSubscription = Subscription(value: subscription) From eb5cbd120ce87a89a1ce5f801fb8ff0af53b2291 Mon Sep 17 00:00:00 2001 From: filipealva Date: Mon, 23 Jul 2018 20:16:43 -0300 Subject: [PATCH 12/42] Fix object invalidated crash when trying to append messages to an invalidated subscription --- .../Controllers/Chat/ChatViewController.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatViewController.swift b/Rocket.Chat/Controllers/Chat/ChatViewController.swift index 41b22060ee..0d28edf716 100644 --- a/Rocket.Chat/Controllers/Chat/ChatViewController.swift +++ b/Rocket.Chat/Controllers/Chat/ChatViewController.swift @@ -846,9 +846,20 @@ final class ChatViewController: SLKTextViewController { // to the list. Also, we keep the subscription identifier in order to make sure // we're updating the same subscription, because this view controller is reused // for all the chats. + + guard !subscription.isInvalidated else { + return + } + let oldSubscriptionIdentifier = subscription.identifier DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { [weak self] in - guard oldSubscriptionIdentifier == self?.subscription?.identifier else { return } + guard + !(self?.subscription?.isInvalidated ?? true), + oldSubscriptionIdentifier == self?.subscription?.identifier + else { + return + } + self?.appendMessages(messages: messages, completion: completion) }) From b97b018892f072192d638e14814fca9d771cee6b Mon Sep 17 00:00:00 2001 From: filipealva Date: Mon, 23 Jul 2018 20:17:31 -0300 Subject: [PATCH 13/42] Fix object invalidated crash when trying to display an invalid subscription on the subscriptions list --- .../SubscriptionsList/SubscriptionsViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift b/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift index 1e77bfe4f9..0df423b84e 100644 --- a/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift +++ b/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift @@ -416,8 +416,8 @@ extension SubscriptionsViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let cell = cell as? SubscriptionCellProtocol else { return } - guard let subscription = cell.subscription else { return } - guard let selectedSubscription = MainSplitViewController.chatViewController?.subscription else { return } + guard let subscription = cell.subscription?.validated() else { return } + guard let selectedSubscription = MainSplitViewController.chatViewController?.subscription?.validated() else { return } if subscription.identifier == selectedSubscription.identifier { tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none) From e55f382b81cecc79481f94ec132d11e40c2310db Mon Sep 17 00:00:00 2001 From: filipealva Date: Mon, 23 Jul 2018 20:18:01 -0300 Subject: [PATCH 14/42] Fix object invalidated crash when trying to access auth object after refreshing its realm instance --- .../Model/SubscriptionManager/SubscriptionManager.swift | 5 +++++ Rocket.Chat/Managers/Socket/SocketManager.swift | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift index 917cb1ea1f..ab8130647d 100644 --- a/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift +++ b/Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager.swift @@ -27,6 +27,11 @@ struct SubscriptionManager { static func updateSubscriptions(_ auth: Auth, realm: Realm? = Realm.current, completion: (() -> Void)?) { realm?.refresh() + let validAuth = auth.isInvalidated ? AuthManager.isAuthenticated(realm: realm) : auth + guard let auth = validAuth else { + return + } + let client = API.current(realm: realm)?.client(SubscriptionsClient.self) let lastUpdateSubscriptions = auth.lastSubscriptionFetchWithLastMessage?.addingTimeInterval(-100000) let lastUpdateRooms = auth.lastRoomFetchWithLastMessage?.addingTimeInterval(-100000) diff --git a/Rocket.Chat/Managers/Socket/SocketManager.swift b/Rocket.Chat/Managers/Socket/SocketManager.swift index 2bf2a9115a..d0bdfa07ea 100644 --- a/Rocket.Chat/Managers/Socket/SocketManager.swift +++ b/Rocket.Chat/Managers/Socket/SocketManager.swift @@ -168,6 +168,11 @@ extension SocketManager { infoClient.fetchInfo(realm: currentRealm, completion: { SubscriptionManager.updateSubscriptions(auth, realm: currentRealm) { + let validAuth = auth.isInvalidated ? AuthManager.isAuthenticated(realm: currentRealm) : auth + guard let auth = validAuth else { + return + } + AuthSettingsManager.updatePublicSettings(auth) UserManager.userDataChanges() From 978be2feccd5369390c30e0b24c137f2658fefd8 Mon Sep 17 00:00:00 2001 From: filipealva Date: Mon, 23 Jul 2018 20:18:25 -0300 Subject: [PATCH 15/42] Fix object invalidated crash when trying to set avatar with initials for an invalidated user --- Rocket.Chat/Views/Avatar/AvatarView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rocket.Chat/Views/Avatar/AvatarView.swift b/Rocket.Chat/Views/Avatar/AvatarView.swift index d586950505..23c5490596 100644 --- a/Rocket.Chat/Views/Avatar/AvatarView.swift +++ b/Rocket.Chat/Views/Avatar/AvatarView.swift @@ -79,7 +79,7 @@ final class AvatarView: UIView { backgroundColor = .clear } else if let avatarURL = avatarURL { imageURL = avatarURL - } else if let user = user { + } else if let user = user?.validated() { setAvatarWithInitials(forUsername: user.username) if let avatarURL = user.avatarURL() { From 788e420131c5eae52a54e34313eec1a395b1d1e2 Mon Sep 17 00:00:00 2001 From: Artur Rymarz Date: Tue, 24 Jul 2018 07:16:52 +0200 Subject: [PATCH 16/42] Update CONTRIBUTING.md Should use bundler to install dependencies --- CONTRIBUTING.md | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d05e103563..4ac9770205 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,27 +20,53 @@ In case you're interested in playing around with the code or giving something ba 1. A macOS machine 2. Xcode 9.3.x or higher (Swift 4.1) -3. Install [CocoaPods](https://cocoapods.org/) (note that you will need to install at least Ruby 2.2.3 for this to work) + +### Installing dependencies + +_(NOTE: Steps 3 and 4 must be executed from project's directory)_ + +1. Clone this repo: ``` -sudo gem install cocoapods +git clone https://github.com/RocketChat/Rocket.Chat.iOS ``` -To update cocoapods (not that often needed) run +2. Install [Bundler](https://bundler.io) ``` -sudo gem update cocoapods +gem install bundler (sudo might be required in some cases) ``` -4. Clone this repo: +3. Install all gem dependencies ``` -git clone https://github.com/RocketChat/Rocket.Chat.iOS +bundle install (sudo might be required in some cases) +``` +To update all gem dependencies (not that often needed) run +``` +bundle update +``` +To update pod's repository (in case of having those oudated compared to Podfile.lock and in case of `pod install` failure) ``` -5. Download library dependencies using the cocoapods dependency manager (and update the same way): +bundle exec pod repo update ``` -pod install +4. Download library dependencies using the cocoapods dependency manager (and update the same way): ``` -6. Do NOT open the Xcode project directly, instead use the Rocket.Chat.xcworkspace file to open the Xcode workspace. -7. Build the project by ⌘ + R +bundle exec pod install +``` +5. Do NOT open the Xcode project directly, instead use the Rocket.Chat.xcworkspace file to open the Xcode workspace. +6. Build the project by ⌘ + R Also refer to [Guidelines](#project.pbxproj) for modifying files. +#### Alternative + +You can skip installing Bundler (not recommended) and just install [CocoaPods](https://cocoapods.org/) (note that you will need to install at least Ruby 2.2.3 for this to work). Make sure you have correct version of CocoaPods installed or you might be not able to build project properly. +``` +sudo gem install cocoapods +``` +Then you can call all the cocoapods actions without **bundle exe** command. + +To update cocoapods (not that often needed, you will be notified during `pod install` when new version is available) run. +``` +sudo gem update cocoapods +``` + ## Issues needing help Didn't found a bug or want a new feature not already reported? Check out [the issues with "help wanted"](https://github.com/RocketChat/Rocket.Chat.iOS/labels/help%20wanted) or other issues, for those no branch exists. From 372e15e0b5517dcb5f8f143979f0cb192ea84088 Mon Sep 17 00:00:00 2001 From: Artur Rymarz Date: Tue, 24 Jul 2018 07:20:57 +0200 Subject: [PATCH 17/42] Update CONTRIBUTING.md --- CONTRIBUTING.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4ac9770205..6da97eb53f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,13 +31,17 @@ git clone https://github.com/RocketChat/Rocket.Chat.iOS ``` 2. Install [Bundler](https://bundler.io) ``` -gem install bundler (sudo might be required in some cases) +sudo gem install bundler +``` +To update _Bundler_ (when there is new version available) +``` +sudo gem update bundler ``` 3. Install all gem dependencies ``` bundle install (sudo might be required in some cases) ``` -To update all gem dependencies (not that often needed) run +To update all gem dependencies (usually executed by maintainer) run ``` bundle update ``` From cc0d86e8b75772094ff560a2f7b4a3e1d9cf6d52 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Tue, 24 Jul 2018 11:37:54 -0300 Subject: [PATCH 18/42] Update images to the new layout --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6dfeb8a67a..2b14c7006f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ [![Rocket.Chat on Apple AppStore](https://user-images.githubusercontent.com/551004/29770691-a2082ff4-8bc6-11e7-89a6-964cd405ea8e.png)](https://geo.itunes.apple.com/us/app/rocket-chat/id1148741252?mt=8) -![Screenshots](https://user-images.githubusercontent.com/193273/35874456-d530ee04-0b6c-11e8-8c19-79dee8140114.png) +![iPad](https://rocket.chat/images/posts/2018/07/2018-07-17-ios_3_0_0_released/ipad_2.png) +![iPhone](https://rocket.chat/images/posts/2018/07/2018-07-17-ios_3_0_0_released/themes.png) # Reporting an Issue From 5a4cbaea986f46c2445f6bf4814c6b544e537856 Mon Sep 17 00:00:00 2001 From: cardoso Date: Tue, 24 Jul 2018 12:34:03 -0300 Subject: [PATCH 19/42] Update SimpleImageViewer (fix UX problems) --- Podfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 5f119604e9..b90a5db5c0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -42,7 +42,7 @@ PODS: - RealmSwift (3.7.4): - Realm (= 3.7.4) - semver (1.1.0) - - SimpleImageViewer (1.1.1): + - SimpleImageViewer (1.2.0): - FLAnimatedImage - SlackTextViewController (1.9.6) - Starscream (2.1.1) @@ -113,7 +113,7 @@ CHECKOUT OPTIONS: :commit: 43d99beabd1c39f8988d2e6631a46623b0116906 :git: https://github.com/RocketChat/RCMarkdownParser.git SimpleImageViewer: - :commit: d76f6757d29746071cb6bd17bba9e636d21b03a8 + :commit: 8222c338de0f285ca0c2d556c5d8dedd4a365b52 :git: https://github.com/cardoso/SimpleImageViewer.git SlackTextViewController: :commit: 944b7cc4de734638cdefdecb9c7d7846fc3ab252 @@ -141,7 +141,7 @@ SPEC CHECKSUMS: Realm: a469bb59e33f9926102ccaea4349822c53b9117e RealmSwift: a45861b21c180f5cf0f122144b9759fa8dde3e9e semver: 11ae3bc4a6036efbc86b5863ef5fa32c065c8bbd - SimpleImageViewer: f82e45a362e3b4b674e25508f42d534e525a73b7 + SimpleImageViewer: 6ed0d2acf7c166a5b4e795bccc7b9ea1b225ff9b SlackTextViewController: b854e62c1c156336bc4fd409c6ca79b5773e8f9d Starscream: 142bd8ef24592d985daee9fa48c936070b85b15f SwiftLint: f6b83e8d95ee1e91e11932d843af4fdcbf3fc764 From d65f6efc31cdcdfd06ee586cc20100e435e377b8 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Tue, 24 Jul 2018 13:07:36 -0300 Subject: [PATCH 20/42] Update images to the ones from App Store --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b14c7006f..abd635e06c 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ [![Rocket.Chat on Apple AppStore](https://user-images.githubusercontent.com/551004/29770691-a2082ff4-8bc6-11e7-89a6-964cd405ea8e.png)](https://geo.itunes.apple.com/us/app/rocket-chat/id1148741252?mt=8) -![iPad](https://rocket.chat/images/posts/2018/07/2018-07-17-ios_3_0_0_released/ipad_2.png) -![iPhone](https://rocket.chat/images/posts/2018/07/2018-07-17-ios_3_0_0_released/themes.png) +![iPad](https://user-images.githubusercontent.com/551004/43151426-4b2784c0-8f42-11e8-8930-8b18aa6ac075.png) +![iPhone](https://user-images.githubusercontent.com/551004/43151411-46cba65e-8f42-11e8-9a38-3efc9dd471b2.png) # Reporting an Issue From 368457e1abafdc5f11d0c584c4c5e8b94848fdaf Mon Sep 17 00:00:00 2001 From: cardoso Date: Tue, 24 Jul 2018 19:02:02 -0300 Subject: [PATCH 21/42] Fix notification reply when app is open and in other server --- Rocket.Chat/Managers/PushManager.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Rocket.Chat/Managers/PushManager.swift b/Rocket.Chat/Managers/PushManager.swift index d60daecdd2..0ef95ca84a 100644 --- a/Rocket.Chat/Managers/PushManager.swift +++ b/Rocket.Chat/Managers/PushManager.swift @@ -159,13 +159,17 @@ extension PushManager { } } + guard let realm = DatabaseManager.databaseInstace(index: index) else { + return false + } + if let reply = reply { let appendage = notification.roomType == .directMessage ? "" : " @\(notification.username)" let message = "\(reply)\(appendage)" let backgroundTask = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) - API.current()?.fetch(PostMessageRequest(roomId: notification.roomId, text: message)) { response in + API.current(realm: realm)?.fetch(PostMessageRequest(roomId: notification.roomId, text: message)) { response in switch response { case .resource: UIApplication.shared.endBackgroundTask(backgroundTask) From 3595900730ea33ee6e55df8a3ae157ce11001959 Mon Sep 17 00:00:00 2001 From: filipealva Date: Tue, 24 Jul 2018 19:41:45 -0300 Subject: [PATCH 22/42] Recognize go.rocket.chat as a valid deeplink --- Rocket.Chat/Helpers/DeepLink.swift | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Rocket.Chat/Helpers/DeepLink.swift b/Rocket.Chat/Helpers/DeepLink.swift index 75dfd9c4c3..52c28b7607 100644 --- a/Rocket.Chat/Helpers/DeepLink.swift +++ b/Rocket.Chat/Helpers/DeepLink.swift @@ -18,22 +18,22 @@ enum DeepLink { case channel(name: String) init?(url: URL) { + let isSchemeBased = url.scheme == "rocket.chat" + guard - url.scheme == "rocketchat", - let actionString = url.host + isSchemeBased || url.host == "go.rocket.chat", + let actionString = isSchemeBased ? url.host : url.path.replacingOccurrences(of: "/", with: "") else { return nil } switch actionString { - case "auth": guard let auth = DeepLink.parseAuthUrl(url) else { return nil } self = auth - case "room": guard let host = url.queryParameters?["host"], @@ -43,21 +43,18 @@ enum DeepLink { } self = .room(host: host, roomId: roomId) - case "mention": guard let name = url.queryParameters?["name"] else { return nil } self = .mention(name: name) - case "channel": guard let name = url.queryParameters?["name"] else { return nil } self = .channel(name: name) - default: return nil } From dce5729d6ee8dde30b5d0ed0448d5528a66b7de8 Mon Sep 17 00:00:00 2001 From: filipealva Date: Tue, 24 Jul 2018 20:05:53 -0300 Subject: [PATCH 23/42] Revert invalid change --- Rocket.Chat/Helpers/DeepLink.swift | 2 +- Rocket.ChatTests/Helpers/DeepLinkSpec.swift | 35 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Rocket.ChatTests/Helpers/DeepLinkSpec.swift diff --git a/Rocket.Chat/Helpers/DeepLink.swift b/Rocket.Chat/Helpers/DeepLink.swift index 52c28b7607..c8f5d93019 100644 --- a/Rocket.Chat/Helpers/DeepLink.swift +++ b/Rocket.Chat/Helpers/DeepLink.swift @@ -18,7 +18,7 @@ enum DeepLink { case channel(name: String) init?(url: URL) { - let isSchemeBased = url.scheme == "rocket.chat" + let isSchemeBased = url.scheme == "rocketchat" guard isSchemeBased || url.host == "go.rocket.chat", diff --git a/Rocket.ChatTests/Helpers/DeepLinkSpec.swift b/Rocket.ChatTests/Helpers/DeepLinkSpec.swift new file mode 100644 index 0000000000..ff247d05cd --- /dev/null +++ b/Rocket.ChatTests/Helpers/DeepLinkSpec.swift @@ -0,0 +1,35 @@ +// +// DeepLinkSpec.swift +// Rocket.ChatTests +// +// Created by Filipe Alvarenga on 24/07/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import XCTest + +class DeepLinkSpec: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} From 201aa848c5737508a4c5889e9f3a9682e017363d Mon Sep 17 00:00:00 2001 From: filipealva Date: Tue, 24 Jul 2018 20:06:35 -0300 Subject: [PATCH 24/42] Add DeepLinkSpec to test all possible URL to DeepLink parsing --- Rocket.Chat.xcodeproj/project.pbxproj | 4 +++ Rocket.ChatTests/Helpers/DeepLinkSpec.swift | 40 ++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 78a64ba302..0e9cfdea01 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -719,6 +719,7 @@ 99B802ED20BC3BD400230109 /* ImageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99B802EC20BC3BD400230109 /* ImageManager.swift */; }; 99B802EE20BC3EF700230109 /* ImageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99B802EC20BC3BD400230109 /* ImageManager.swift */; }; 99B802EF20BC3F0800230109 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4174CB1E1D2DB3350086DAC8 /* StringExtensions.swift */; }; + 99BC81102107E3020084C948 /* DeepLinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99BC810F2107E3020084C948 /* DeepLinkSpec.swift */; }; 99C577EE207E4F1500CE9B4D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C577ED207E4F1500CE9B4D /* File.swift */; }; 99D77C6B20E474BF008F2438 /* AnalyticsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D77C6A20E474BF008F2438 /* AnalyticsManager.swift */; }; 99D86ABA20D0C5240036C127 /* LoginTableViewControllerAuthenticationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D86AB920D0C5240036C127 /* LoginTableViewControllerAuthenticationHandler.swift */; }; @@ -1521,6 +1522,7 @@ 99B060CD1FB1225200F471C2 /* DraftMessageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftMessageManager.swift; sourceTree = ""; }; 99B15BCC20FD4589005A528F /* DatabaseManagerAuthSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseManagerAuthSettings.swift; sourceTree = ""; }; 99B802EC20BC3BD400230109 /* ImageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageManager.swift; sourceTree = ""; }; + 99BC810F2107E3020084C948 /* DeepLinkSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkSpec.swift; sourceTree = ""; }; 99C577ED207E4F1500CE9B4D /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; 99D77C6A20E474BF008F2438 /* AnalyticsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsManager.swift; sourceTree = ""; }; 99D86AB920D0C5240036C127 /* LoginTableViewControllerAuthenticationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginTableViewControllerAuthenticationHandler.swift; sourceTree = ""; }; @@ -2106,6 +2108,7 @@ 8013F8421FD02D8F00EE1A4E /* ChatCollectionViewFlowLayoutSpec.swift */, 41B96364207E492C0068F1A6 /* MessageTextValidatorSpec.swift */, 416296F81F41B42B00BCCEDD /* UploadHelperSpec.swift */, + 99BC810F2107E3020084C948 /* DeepLinkSpec.swift */, ); path = Helpers; sourceTree = ""; @@ -4617,6 +4620,7 @@ 411498E11FC7A85400D66542 /* ChatTitleViewModelSpec.swift in Sources */, 80E99F2F1FD8B4F400B70B59 /* UserExtensionsSpec.swift in Sources */, 80247B3F1FE8582700878833 /* MessageReactionSpec.swift in Sources */, + 99BC81102107E3020084C948 /* DeepLinkSpec.swift in Sources */, 80D41E0520924A8200034D1F /* AuthCanStarMessageSpec.swift in Sources */, 8013F8431FD02D8F00EE1A4E /* ChatCollectionViewFlowLayoutSpec.swift in Sources */, 77C2612D1F97453600724A1F /* SelectFieldSpec.swift in Sources */, diff --git a/Rocket.ChatTests/Helpers/DeepLinkSpec.swift b/Rocket.ChatTests/Helpers/DeepLinkSpec.swift index ff247d05cd..7e31cf2f8d 100644 --- a/Rocket.ChatTests/Helpers/DeepLinkSpec.swift +++ b/Rocket.ChatTests/Helpers/DeepLinkSpec.swift @@ -8,28 +8,24 @@ import XCTest +@testable import Rocket_Chat + class DeepLinkSpec: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testExample() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } + let validDeeplinkURLs = [ + "https://go.rocket.chat/auth?host=open.rocket.chat&token=lkjadfalkdj2fe0f23f802f23080283hf08hsd0f08h&userId=initialuser", + "https://go.rocket.chat/auth?host=open.rocket.chat", + "https://go.rocket.chat/room?host=open.rocket.chat&rid=asdfasdf", + "https://go.rocket.chat/mention?name=test", + "https://go.rocket.chat/channel?name=general", + "rocketchat://auth?host=open.rocket.chat&token=lkjadfalkdj2fe0f23f802f23080283hf08hsd0f08h&userId=initialuser", + "rocketchat://auth?host=open.rocket.chat", + "rocketchat://room?host=open.rocket.chat&rid=asdfasdf", + "rocketchat://mention?name=test", + "rocketchat://channel?name=general" + ] + + func testSupportedDeepLinks() { + let deeplinks = validDeeplinkURLs.compactMap({ URL(string: $0) }).compactMap { DeepLink(url: $0) } + XCTAssertEqual(deeplinks.count, validDeeplinkURLs.count, "Failed to parse one or more supported deeplink URLs") } - } From b76603f6ab9c71796366afdbf70a132ef0439e4c Mon Sep 17 00:00:00 2001 From: filipealva Date: Tue, 24 Jul 2018 20:22:22 -0300 Subject: [PATCH 25/42] Apply validated() method instead of checking isInvalidated flag when appropriated --- Rocket.Chat/API/Clients/MessagesClient.swift | 4 ++-- .../Controllers/Chat/ChatViewController.swift | 17 +++++------------ .../Subscription/BaseSubscriptionCell.swift | 2 +- .../Cells/Subscription/SubscriptionCell.swift | 3 +-- Rocket.Chat/Views/Chat/ChatTitleView.swift | 2 +- Rocket.Chat/Views/Chat/ChatTitleViewModel.swift | 5 +---- 6 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Rocket.Chat/API/Clients/MessagesClient.swift b/Rocket.Chat/API/Clients/MessagesClient.swift index 7467260be7..685dae8a1a 100644 --- a/Rocket.Chat/API/Clients/MessagesClient.swift +++ b/Rocket.Chat/API/Clients/MessagesClient.swift @@ -29,7 +29,7 @@ struct MessagesClient: APIClient { } func updateMessage(json: JSON) { - if message.isInvalidated { + if message.validated() == nil { return } @@ -50,7 +50,7 @@ struct MessagesClient: APIClient { func setMessageOffline() { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - if message.isInvalidated { + if message.validated() == nil { return } diff --git a/Rocket.Chat/Controllers/Chat/ChatViewController.swift b/Rocket.Chat/Controllers/Chat/ChatViewController.swift index 0d28edf716..7ed8e59945 100644 --- a/Rocket.Chat/Controllers/Chat/ChatViewController.swift +++ b/Rocket.Chat/Controllers/Chat/ChatViewController.swift @@ -108,10 +108,7 @@ final class ChatViewController: SLKTextViewController { var subscription: Subscription? { didSet { - guard - let subscription = subscription, - !subscription.isInvalidated - else { + guard let subscription = subscription?.validated() else { return } @@ -835,7 +832,7 @@ final class ChatViewController: SLKTextViewController { } private func appendMessages(messages: [Message], completion: VoidCompletion?) { - guard let subscription = subscription, let collectionView = collectionView, !subscription.isInvalidated else { + guard let subscription = subscription?.validated(), let collectionView = collectionView else { return } @@ -847,14 +844,10 @@ final class ChatViewController: SLKTextViewController { // we're updating the same subscription, because this view controller is reused // for all the chats. - guard !subscription.isInvalidated else { - return - } - let oldSubscriptionIdentifier = subscription.identifier DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { [weak self] in guard - !(self?.subscription?.isInvalidated ?? true), + self?.subscription?.validated() != nil, oldSubscriptionIdentifier == self?.subscription?.identifier else { return @@ -1018,7 +1011,7 @@ extension ChatViewController { dataController.data.count > indexPath.row, let subscription = subscription, let obj = dataController.itemAt(indexPath), - !(obj.message?.isInvalidated ?? false) + obj.message?.validated() != nil else { return cellForEmpty(at: indexPath) } @@ -1152,7 +1145,7 @@ extension ChatViewController: UICollectionViewDelegateFlowLayout { } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - guard let subscription = subscription, !subscription.isInvalidated else { + guard let subscription = subscription?.validated() else { return .zero } diff --git a/Rocket.Chat/Views/Cells/Subscription/BaseSubscriptionCell.swift b/Rocket.Chat/Views/Cells/Subscription/BaseSubscriptionCell.swift index ed01a1ed18..5db39dd12f 100644 --- a/Rocket.Chat/Views/Cells/Subscription/BaseSubscriptionCell.swift +++ b/Rocket.Chat/Views/Cells/Subscription/BaseSubscriptionCell.swift @@ -19,7 +19,7 @@ class BaseSubscriptionCell: UITableViewCell, SubscriptionCellProtocol { var subscription: Subscription? { didSet { - guard let subscription = subscription, !subscription.isInvalidated else { return } + guard let subscription = subscription?.validated() else { return } updateSubscriptionInformation() } } diff --git a/Rocket.Chat/Views/Cells/Subscription/SubscriptionCell.swift b/Rocket.Chat/Views/Cells/Subscription/SubscriptionCell.swift index 8ea700844f..32c7023012 100644 --- a/Rocket.Chat/Views/Cells/Subscription/SubscriptionCell.swift +++ b/Rocket.Chat/Views/Cells/Subscription/SubscriptionCell.swift @@ -56,8 +56,7 @@ final class SubscriptionCell: BaseSubscriptionCell { private func setDateColor() { guard let theme = theme, - let subscription = subscription, - !subscription.isInvalidated + let subscription = subscription?.validated() else { return } diff --git a/Rocket.Chat/Views/Chat/ChatTitleView.swift b/Rocket.Chat/Views/Chat/ChatTitleView.swift index 25b7ebde97..a4230b22f0 100644 --- a/Rocket.Chat/Views/Chat/ChatTitleView.swift +++ b/Rocket.Chat/Views/Chat/ChatTitleView.swift @@ -41,7 +41,7 @@ final class ChatTitleView: UIView { var subscription: Subscription? { didSet { - guard let subscription = subscription, !subscription.isInvalidated else { return } + guard let subscription = subscription?.validated() else { return } viewModel.subscription = subscription buttonTitle.setTitle(viewModel.title, for: .normal) diff --git a/Rocket.Chat/Views/Chat/ChatTitleViewModel.swift b/Rocket.Chat/Views/Chat/ChatTitleViewModel.swift index d8302ce28f..7e54a2ab54 100644 --- a/Rocket.Chat/Views/Chat/ChatTitleViewModel.swift +++ b/Rocket.Chat/Views/Chat/ChatTitleViewModel.swift @@ -13,10 +13,7 @@ final class ChatTitleViewModel { internal var user: User? var subscription: Subscription? { didSet { - guard - let subscription = subscription, - !subscription.isInvalidated - else { + guard let subscription = subscription?.validated() else { return } From 702c728f736851e023603e490a31eb0c41c4b838 Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Wed, 25 Jul 2018 20:47:15 +0530 Subject: [PATCH 26/42] Update screenshots --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index abd635e06c..7a7ca316dc 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,13 @@ [About Rocket.Chat](https://github.com/RocketChat/Rocket.Chat/#about-rocketchat) -# Download from the App Store +![Screenshot](https://user-images.githubusercontent.com/7317008/43209700-eb3ded88-904a-11e8-8ec4-9ac10a39f344.png) -[![Rocket.Chat on Apple AppStore](https://user-images.githubusercontent.com/551004/29770691-a2082ff4-8bc6-11e7-89a6-964cd405ea8e.png)](https://geo.itunes.apple.com/us/app/rocket-chat/id1148741252?mt=8) - -![iPad](https://user-images.githubusercontent.com/551004/43151426-4b2784c0-8f42-11e8-8930-8b18aa6ac075.png) -![iPhone](https://user-images.githubusercontent.com/551004/43151411-46cba65e-8f42-11e8-9a38-3efc9dd471b2.png) +

+ + Download on the app store + +

# Reporting an Issue From c491e41381916a3bcdc3869c89fdeaa932b8cd4e Mon Sep 17 00:00:00 2001 From: Samar Sunkaria Date: Wed, 25 Jul 2018 21:46:03 +0530 Subject: [PATCH 27/42] Rearrange screenshots --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7a7ca316dc..401e209da3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ ![Rocket.Chat logo](https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/logo-dark.svg?sanitize=true) + +![Screenshot](https://user-images.githubusercontent.com/7317008/43209700-eb3ded88-904a-11e8-8ec4-9ac10a39f344.png) + +

+ + Download on the app store + +

+ # Rocket.Chat iOS native application [![Build Status](https://circleci.com/gh/RocketChat/Rocket.Chat.iOS/tree/develop.svg?style=shield)](https://circleci.com/gh/RocketChat/Rocket.Chat.iOS/tree/develop) @@ -10,14 +19,6 @@ [About Rocket.Chat](https://github.com/RocketChat/Rocket.Chat/#about-rocketchat) -![Screenshot](https://user-images.githubusercontent.com/7317008/43209700-eb3ded88-904a-11e8-8ec4-9ac10a39f344.png) - -

- - Download on the app store - -

- # Reporting an Issue [Github Issues](https://github.com/RocketChat/Rocket.Chat.iOS/issues) are used to track todos, bugs, feature requests, and more. From ce7d2bc1bf7fa17da8f5caafd0db71649707fe6f Mon Sep 17 00:00:00 2001 From: cardoso Date: Wed, 25 Jul 2018 14:38:14 -0300 Subject: [PATCH 28/42] Fix iPad losing right-side controller after becoming fullscreen --- .../SubscriptionsList/SubscriptionsViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift b/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift index 0df423b84e..dcb76119c1 100644 --- a/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift +++ b/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift @@ -490,7 +490,7 @@ extension SubscriptionsViewController: UITableViewDelegate { // When using iPads, we override the detail controller creating // a new instance. - if splitViewController?.detailViewController as? BaseNavigationController != nil { + if UIDevice.current.userInterfaceIdiom == .pad { controller.subscription = subscription let nav = BaseNavigationController(rootViewController: controller) From afe07b8c845becf4fc3830188e772e6fb4cd2003 Mon Sep 17 00:00:00 2001 From: cardoso Date: Wed, 25 Jul 2018 14:53:45 -0300 Subject: [PATCH 29/42] Don't hide Navigation Bar on Searching Rooms on iPad --- .../SubscriptionsList/SubscriptionsViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift b/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift index 0df423b84e..502095a0b0 100644 --- a/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift +++ b/Rocket.Chat/Controllers/Subscriptions/SubscriptionsList/SubscriptionsViewController.swift @@ -199,7 +199,7 @@ final class SubscriptionsViewController: BaseViewController { func setupSearchBar() { let searchController = UISearchController(searchResultsController: nil) searchController.dimsBackgroundDuringPresentation = false - searchController.hidesNavigationBarDuringPresentation = true + searchController.hidesNavigationBarDuringPresentation = UIDevice.current.userInterfaceIdiom != .pad if #available(iOS 11.0, *) { searchBar = searchController.searchBar From a0e006791d98c0bef9433905e83ba3cdf83675b5 Mon Sep 17 00:00:00 2001 From: cardoso Date: Wed, 25 Jul 2018 16:51:41 -0300 Subject: [PATCH 30/42] Fix not being able to close reactor list in iPad compact --- .../Controllers/Chat/ChatControllerMessageCellProtocol.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift index b63715f4c0..505eea1a6b 100644 --- a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift +++ b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift @@ -44,7 +44,7 @@ extension ChatViewController: ChatMessageCellProtocol, UserActionSheetPresenter // present (push on iPhone, popover on iPad) - if UIDevice.current.userInterfaceIdiom == .phone { + if traitCollection.horizontalSizeClass == .compact { self.navigationController?.pushViewController(controller, animated: true) } else { if let presenter = controller.popoverPresentationController { From e94c9ee8d30761fabcd581d1510fd15eb4f1f6ee Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Fri, 27 Jul 2018 11:49:16 -0300 Subject: [PATCH 31/42] Fixed a bug on objects without message --- Rocket.Chat/Controllers/Chat/ChatViewController.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatViewController.swift b/Rocket.Chat/Controllers/Chat/ChatViewController.swift index 7ed8e59945..25099f69e3 100644 --- a/Rocket.Chat/Controllers/Chat/ChatViewController.swift +++ b/Rocket.Chat/Controllers/Chat/ChatViewController.swift @@ -1010,14 +1010,17 @@ extension ChatViewController { guard dataController.data.count > indexPath.row, let subscription = subscription, - let obj = dataController.itemAt(indexPath), - obj.message?.validated() != nil + let obj = dataController.itemAt(indexPath) else { return cellForEmpty(at: indexPath) } if obj.type == .message { - return cellForMessage(obj, at: indexPath) + if obj.message?.validated() != nil { + return cellForMessage(obj, at: indexPath) + } else { + return cellForEmpty(at: indexPath) + } } if obj.type == .daySeparator { @@ -1170,7 +1173,6 @@ extension ChatViewController: UICollectionViewDelegateFlowLayout { let sequential = dataController.hasSequentialMessageAt(indexPath) let height = ChatMessageCell.cellMediaHeightFor(message: message, width: fullWidth, sequential: sequential) dataController.cacheCellHeight(for: obj.identifier, value: height) - return CGSize(width: fullWidth, height: height) } } From 161ac5b2156d28781a449cd6376e1d730dd2c787 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Fri, 27 Jul 2018 11:49:31 -0300 Subject: [PATCH 32/42] Fixed the sizing of the elements based on the view size & collapses --- .../ChatControllerMessageCellProtocol.swift | 3 ++ .../Controllers/Chat/ChatDataController.swift | 3 +- .../NSAttributedStringExtensions.swift | 9 +++-- .../Chat/ChatMessageAttachmentView.swift | 4 +-- .../Cells/Chat/ChatMessageAudioView.swift | 5 ++- .../Views/Cells/Chat/ChatMessageCell.swift | 34 +++++++++++-------- .../Cells/Chat/ChatMessageImageView.swift | 7 +++- .../Cells/Chat/ChatMessageTextView.swift | 4 +-- .../Cells/Chat/ChatMessageVideoView.swift | 4 ++- 9 files changed, 47 insertions(+), 26 deletions(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift index 505eea1a6b..2b510e13e4 100644 --- a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift +++ b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift @@ -148,6 +148,9 @@ extension ChatViewController: ChatMessageCellProtocol, UserActionSheetPresenter func viewDidCollapseChange(view: UIView) { guard let origin = collectionView?.convert(CGPoint.zero, from: view) else { return } guard let indexPath = collectionView?.indexPathForItem(at: origin) else { return } + + let item = dataController.itemAt(indexPath) + dataController.invalidateLayout(for: item?.identifier) collectionView?.reloadItems(at: [indexPath]) } diff --git a/Rocket.Chat/Controllers/Chat/ChatDataController.swift b/Rocket.Chat/Controllers/Chat/ChatDataController.swift index 89fc48ca9d..a9ee7fee12 100644 --- a/Rocket.Chat/Controllers/Chat/ChatDataController.swift +++ b/Rocket.Chat/Controllers/Chat/ChatDataController.swift @@ -309,6 +309,8 @@ final class ChatDataController { func update(_ message: Message) -> Int { for (idx, obj) in data.enumerated() where obj.message?.identifier == message.identifier { + invalidateLayout(for: obj.identifier) + if obj.message?.updatedAt?.timeIntervalSince1970 == message.updatedAt?.timeIntervalSince1970 { return -1 } @@ -320,7 +322,6 @@ final class ChatDataController { } data[idx].message = message - invalidateLayout(for: obj.identifier) return obj.indexPath.row } diff --git a/Rocket.Chat/Extensions/NSAttributedStringExtensions.swift b/Rocket.Chat/Extensions/NSAttributedStringExtensions.swift index 382db566fe..5b02a5389b 100644 --- a/Rocket.Chat/Extensions/NSAttributedStringExtensions.swift +++ b/Rocket.Chat/Extensions/NSAttributedStringExtensions.swift @@ -11,9 +11,12 @@ import UIKit extension NSAttributedString { func heightForView(withWidth width: CGFloat) -> CGFloat? { let size = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) - let rect = self.boundingRect(with: size, - options: [.usesLineFragmentOrigin, .usesFontLeading], - context: nil) + + let rect = self.boundingRect( + with: size, + options: [.usesLineFragmentOrigin, .usesFontLeading], + context: nil + ) return rect.height } diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageAttachmentView.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageAttachmentView.swift index 9d89c12cdf..93d5048d7f 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageAttachmentView.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageAttachmentView.swift @@ -11,7 +11,7 @@ class ChatMessageAttachmentView: UIView { return 0 } - static func heightFor(withText description: String?) -> CGFloat { + static func heightFor(with availableWidth: CGFloat, description: String?) -> CGFloat { guard let text = description, !text.isEmpty else { return self.defaultHeight } @@ -21,7 +21,7 @@ class ChatMessageAttachmentView: UIView { attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14.0)] ) - let labelWidth = UIScreen.main.bounds.size.width - 55 + let labelWidth = availableWidth - 55 let height = attributedString.heightForView(withWidth: labelWidth) return self.defaultHeight + (height ?? -1) + 1 } diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageAudioView.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageAudioView.swift index 785e0544f1..f7948d05f2 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageAudioView.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageAudioView.swift @@ -19,9 +19,12 @@ final class ChatMessageAudioView: ChatMessageAttachmentView { self.titleLabel.text = attachment?.title self.detailText.text = attachment?.descriptionText self.detailTextIndicator.isHidden = attachment?.descriptionText?.isEmpty ?? true - let fullHeight = ChatMessageAudioView.heightFor(withText: attachment?.descriptionText) + + let availableWidth = frame.size.width + let fullHeight = ChatMessageAudioView.heightFor(with: availableWidth, description: attachment?.descriptionText) fullHeightConstraint.constant = fullHeight detailTextHeightConstraint.constant = fullHeight - ChatMessageAudioView.defaultHeight + loading = true playing = false updateAudio(attachment: attachment) diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift index 491a670960..6ea8ae2a71 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift @@ -317,12 +317,11 @@ extension ChatMessageCell: UIGestureRecognizerDelegate { extension ChatMessageCell { static func cellMediaHeightFor(message: Message, width: CGFloat, sequential: Bool = true) -> CGFloat { - let fullWidth = width let attributedString = MessageTextCacheManager.shared.message(for: message, with: nil) var total = (CGFloat)(sequential ? 8 : 29) + (message.reactions.count > 0 ? 40 : 0) if attributedString?.string ?? "" != "" { - total += (attributedString?.heightForView(withWidth: fullWidth - 61) ?? 0) + total += (attributedString?.heightForView(withWidth: width - 61) ?? 0) } if message.isBroadcastReplyAvailable() { @@ -338,24 +337,24 @@ extension ChatMessageCell { let type = attachment.type if type == .textAttachment { - total += ChatMessageTextView.heightFor(collapsed: attachment.collapsed, withText: attachment.text, isFile: attachment.isFile) + total += ChatMessageTextView.heightFor(with: width, collapsed: attachment.collapsed, text: attachment.text, isFile: attachment.isFile) } if type == .image { - total += ChatMessageImageView.heightFor(withText: attachment.descriptionText) + total += ChatMessageImageView.heightFor(with: width, description: attachment.descriptionText) } if type == .video { - total += ChatMessageVideoView.heightFor(withText: attachment.descriptionText) + total += ChatMessageVideoView.heightFor(with: width, description: attachment.descriptionText) } if type == .audio { - total += ChatMessageAudioView.heightFor(withText: attachment.descriptionText) + total += ChatMessageAudioView.heightFor(with: width, description: attachment.descriptionText) } if !attachment.collapsed { attachment.fields.forEach { - total += ChatMessageTextView.heightFor(collapsed: false, withText: $0.value) + total += ChatMessageTextView.heightFor(with: width, collapsed: false, text: $0.value) } } } @@ -412,14 +411,16 @@ extension ChatMessageCell { view.translatesAutoresizingMaskIntoConstraints = false mediaViews.addArrangedSubview(view) - var attachmentHeight = ChatMessageTextView.heightFor(collapsed: attachment.collapsed, withText: attachment.text, isFile: attachment.isFile) + + let availableWidth = frame.size.width + var attachmentHeight = ChatMessageTextView.heightFor(with: availableWidth, collapsed: attachment.collapsed, text: attachment.text, isFile: attachment.isFile) if !attachment.collapsed { attachment.fields.forEach { guard let view = ChatMessageTextView.instantiateFromNib() else { return } view.viewModel = ChatMessageAttachmentFieldViewModel(withAttachment: attachment, andAttachmentField: $0) mediaViews.addArrangedSubview(view) - attachmentHeight += ChatMessageTextView.heightFor(collapsed: false, withText: $0.value) + attachmentHeight += ChatMessageTextView.heightFor(with: availableWidth, collapsed: false, text: $0.value) } } @@ -431,9 +432,10 @@ extension ChatMessageCell { view.attachment = attachment view.delegate = delegate view.translatesAutoresizingMaskIntoConstraints = false - mediaViews.addArrangedSubview(view) - return ChatMessageImageView.heightFor(withText: attachment.descriptionText) + + let availableWidth = frame.size.width + return ChatMessageImageView.heightFor(with: availableWidth, description: attachment.descriptionText) } private func insertVideoAttachment(_ attachment: Attachment) -> CGFloat { @@ -441,18 +443,20 @@ extension ChatMessageCell { view.attachment = attachment view.delegate = delegate view.translatesAutoresizingMaskIntoConstraints = false - mediaViews.addArrangedSubview(view) - return ChatMessageVideoView.heightFor(withText: attachment.descriptionText) + + let availableWidth = frame.size.width + return ChatMessageImageView.heightFor(with: availableWidth, description: attachment.descriptionText) } private func insertAudioAttachment(_ attachment: Attachment) -> CGFloat { guard let view = ChatMessageAudioView.instantiateFromNib() else { return 0 } view.attachment = attachment view.translatesAutoresizingMaskIntoConstraints = false - mediaViews.addArrangedSubview(view) - return ChatMessageAudioView.heightFor(withText: attachment.descriptionText) + + let availableWidth = frame.size.width + return ChatMessageImageView.heightFor(with: availableWidth, description: attachment.descriptionText) } } diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.swift index db24e3424a..ab8c30e239 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.swift @@ -54,6 +54,7 @@ final class ChatMessageImageView: ChatMessageAttachmentView { guard let imageURL = attachment.fullImageURL() else { return nil } + if imageURL.absoluteString.starts(with: "http://") { isLoadable = false detailText.text = "" @@ -62,12 +63,16 @@ final class ChatMessageImageView: ChatMessageAttachmentView { imageView.image = UIImage(named: "Resource Unavailable") return nil } + labelTitle.text = attachment.title detailText.text = attachment.descriptionText detailTextIndicator.isHidden = attachment.descriptionText?.isEmpty ?? true - let fullHeight = ChatMessageImageView.heightFor(withText: attachment.descriptionText) + + let availableWidth = frame.size.width + let fullHeight = ChatMessageImageView.heightFor(with: availableWidth, description: attachment.descriptionText) fullHeightConstraint.constant = fullHeight detailTextHeightConstraint.constant = fullHeight - ChatMessageImageView.defaultHeight + return imageURL } diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageTextView.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageTextView.swift index 3bd04d8f31..af703ea7a3 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageTextView.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageTextView.swift @@ -80,12 +80,12 @@ final class ChatMessageTextView: UIView { } } - static func heightFor(collapsed: Bool, withText text: String?, isFile: Bool = false) -> CGFloat { + static func heightFor(with availableWidth: CGFloat, collapsed: Bool, text: String?, isFile: Bool = false) -> CGFloat { guard !isFile else { return defaultHeight } - let width = UIScreen.main.bounds.size.width - 73 + let width = availableWidth - 73 var textHeight: CGFloat = 1 if let text = text, text.count > 0 { diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageVideoView.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageVideoView.swift index be118c0b67..7401c90ce0 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageVideoView.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageVideoView.swift @@ -45,7 +45,9 @@ final class ChatMessageVideoView: ChatMessageAttachmentView { labelTitle.text = attachment.title detailText.text = attachment.descriptionText detailTextIndicator.isHidden = attachment.descriptionText?.isEmpty ?? true - let fullHeight = ChatMessageVideoView.heightFor(withText: attachment.descriptionText) + + let availableWidth = frame.size.width + let fullHeight = ChatMessageVideoView.heightFor(with: availableWidth, description: attachment.descriptionText) fullHeightConstraint.constant = fullHeight detailTextHeightConstraint.constant = fullHeight - ChatMessageVideoView.defaultHeight From 436ed4674c3bc6564d3c1db50547e69e024772fa Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Fri, 27 Jul 2018 12:08:03 -0300 Subject: [PATCH 33/42] Adjustments on the imageView attachments to match with the description text label sizing --- Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.xib | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.xib b/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.xib index 80548ebd50..62a659178e 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.xib +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageImageView.xib @@ -1,11 +1,11 @@ - + - + @@ -36,7 +36,7 @@ - +