diff --git a/Snikket.xcodeproj/project.pbxproj b/Snikket.xcodeproj/project.pbxproj index 55a1b8d9..ec8ff153 100644 --- a/Snikket.xcodeproj/project.pbxproj +++ b/Snikket.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 3759638626F7317D00831F4C /* Account.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3759638826F7317D00831F4C /* Account.storyboard */; }; 3759638D26F7320F00831F4C /* MIX.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3759638F26F7320F00831F4C /* MIX.storyboard */; }; 3759A58C26F8C7CC002987B2 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3759A58E26F8C7CC002987B2 /* Localizable.strings */; }; + 3763450E272C6CEF000BC01F /* CallsSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763450D272C6CEF000BC01F /* CallsSettingsViewController.swift */; }; 3776C43526EDC5F00047750B /* MessageStyling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3776C43426EDC5F00047750B /* MessageStyling.swift */; }; 3795F92426FB69370067361A /* BartyCrouch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3795F92326FB69370067361A /* BartyCrouch.swift */; }; 3797D5BD26E9E42E0091DAF8 /* AvatarColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3797D5BC26E9E42E0091DAF8 /* AvatarColors.swift */; }; @@ -334,6 +335,7 @@ 3759639426F7481200831F4C /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Base; path = Base.lproj/Info.plist; sourceTree = ""; }; 3759A58D26F8C7CC002987B2 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 3759A58F26F8C7CF002987B2 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; + 3763450D272C6CEF000BC01F /* CallsSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallsSettingsViewController.swift; sourceTree = ""; }; 3776C43426EDC5F00047750B /* MessageStyling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageStyling.swift; sourceTree = ""; }; 3795F92326FB69370067361A /* BartyCrouch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BartyCrouch.swift; sourceTree = ""; }; 3797D5BC26E9E42E0091DAF8 /* AvatarColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarColors.swift; sourceTree = ""; }; @@ -767,26 +769,27 @@ FE507A0A1CDB7B3B001A015C /* settings */ = { isa = PBXGroup; children = ( + FE6545611E9E7FDE006A14AC /* AccountDomainTableViewCell.swift */, + FE17808C23EB4C7F00A1EA76 /* AccountQRCodeController.swift */, + FEF80DB11CDBBBFE005645A7 /* AccountSettingsViewController.swift */, FE507A0B1CDB7B3B001A015C /* AccountTableViewCell.swift */, FE507A0C1CDB7B3B001A015C /* AddAccountController.swift */, - FE507A0D1CDB7B3B001A015C /* SettingsViewController.swift */, - FEF80DB11CDBBBFE005645A7 /* AccountSettingsViewController.swift */, - FE80BDAA1D953FC4001914B0 /* SetupViewController.swift */, - FE65455F1E9E7B85006A14AC /* RegisterAccountController.swift */, - FE6545611E9E7FDE006A14AC /* AccountDomainTableViewCell.swift */, - FE6545631E9E8B67006A14AC /* ServerSelectorTableViewCell.swift */, + FEDC678F238B05E4005C0FAB /* BlockedContactsController.swift */, FE9E136C1F25F5F7005C0EE5 /* ChatSettingsViewController.swift */, - FE9E136E1F26049A005C0EE5 /* NotificationSettingsViewController.swift */, FE9E13701F2606E9005C0EE5 /* ContactsSettingsViewController.swift */, FE00157E2019090300490340 /* ExperimentalSettingsViewController.swift */, - FE2809802167CE18002F5BD0 /* server_features_list.xml */, - FE2809822167CF1B002F5BD0 /* ServerFeaturesViewController.swift */, - FE719E7D2274D20D007CEEC9 /* OMEMOFingerprintsController.swift */, - FEDC678F238B05E4005C0FAB /* BlockedContactsController.swift */, - FE17808C23EB4C7F00A1EA76 /* AccountQRCodeController.swift */, FE0E31112537288A0030F8C5 /* MediaSettingsVIewController.swift */, + FE9E136E1F26049A005C0EE5 /* NotificationSettingsViewController.swift */, + FE719E7D2274D20D007CEEC9 /* OMEMOFingerprintsController.swift */, E963721126D79D3A00332482 /* PrivacyPolicyTableViewCell.swift */, + FE65455F1E9E7B85006A14AC /* RegisterAccountController.swift */, + FE2809802167CE18002F5BD0 /* server_features_list.xml */, + FE2809822167CF1B002F5BD0 /* ServerFeaturesViewController.swift */, + FE6545631E9E8B67006A14AC /* ServerSelectorTableViewCell.swift */, + FE507A0D1CDB7B3B001A015C /* SettingsViewController.swift */, + FE80BDAA1D953FC4001914B0 /* SetupViewController.swift */, 373A801F271063E1000E50FE /* TelephonyProviderViewController.swift */, + 3763450D272C6CEF000BC01F /* CallsSettingsViewController.swift */, ); path = settings; sourceTree = ""; @@ -1448,6 +1451,7 @@ 373A8020271063E1000E50FE /* TelephonyProviderViewController.swift in Sources */, FE3E38862428C21100D3A8E8 /* OSLog.swift in Sources */, FECEF29423B7933A007EC323 /* MetadataCache.swift in Sources */, + 3763450E272C6CEF000BC01F /* CallsSettingsViewController.swift in Sources */, E9D384B426CA95FF009BEAF3 /* UIDeviceExtension.swift in Sources */, FEB62C501DA80956001500D5 /* AvatarStore.swift in Sources */, FE7D293423B919FF001A877D /* DownloadManager.swift in Sources */, diff --git a/Snikket.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Snikket.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 567d414e..2a49f90d 100644 --- a/Snikket.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Snikket.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -24,8 +24,8 @@ "repositoryURL": "https://github.com/tigase/tigase-swift", "state": { "branch": null, - "revision": "028e297fa4de25ac552b9947a8ccd29ade7001e7", - "version": "2.1.2" + "revision": "d3953dcea80010ad433fa96d7ca6b989bf58850c", + "version": "2.1.3" } }, { diff --git a/Snikket/Base.lproj/Main.storyboard b/Snikket/Base.lproj/Main.storyboard index 067e71ac..52288ff1 100644 --- a/Snikket/Base.lproj/Main.storyboard +++ b/Snikket/Base.lproj/Main.storyboard @@ -776,14 +776,14 @@ - + - + @@ -808,7 +808,7 @@ - + @@ -833,7 +833,7 @@ - + @@ -858,7 +858,7 @@ - + @@ -884,7 +884,7 @@ - + @@ -912,6 +912,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -932,6 +963,7 @@ + diff --git a/Snikket/Base.lproj/Settings.storyboard b/Snikket/Base.lproj/Settings.storyboard index 799cbb3a..59fbe239 100644 --- a/Snikket/Base.lproj/Settings.storyboard +++ b/Snikket/Base.lproj/Settings.storyboard @@ -1,9 +1,9 @@ - + - + @@ -485,9 +485,36 @@ - + + + + + + + + + + + + + + + + + + + + + + @@ -1032,7 +1059,7 @@ - + @@ -1056,7 +1083,7 @@ - + @@ -1136,7 +1163,7 @@ - + @@ -1319,7 +1346,7 @@ - + @@ -1331,9 +1358,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Snikket/chat/ChatViewController.swift b/Snikket/chat/ChatViewController.swift index e5cefbfe..558e5093 100644 --- a/Snikket/chat/ChatViewController.swift +++ b/Snikket/chat/ChatViewController.swift @@ -76,6 +76,31 @@ class ChatViewController : BaseChatViewControllerWithDataSourceAndContextMenuAnd } } + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + // scrollViewShouldScrollToTop will not get called if tableview is already at top + guard var contentOffset = self.conversationLogController?.tableView.contentOffset else { return } + if contentOffset.y == 0 { + contentOffset.y = 1 + self.conversationLogController?.tableView.setContentOffset(contentOffset, animated: true) + } + } + + func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { + scrollToTop() + return false + } + + func scrollToTop() { + if let count = self.conversationLogController?.dataSource.count, count > 0 { + var currentRow = self.conversationLogController?.tableView.indexPathsForVisibleRows?.first?.row ?? 0 + currentRow = count > currentRow + 40 ? currentRow + 40 : count + let indexPath = IndexPath(row: currentRow - 1, section: 0) + DispatchQueue.main.async { + self.conversationLogController?.tableView.scrollToRow(at: indexPath, at: .none, animated: true) + } + } + } + func setupViews() { let recognizer = UITapGestureRecognizer(target: self, action: #selector(ChatViewController.showBuddyInfo)); self.titleView.isUserInteractionEnabled = true; @@ -97,7 +122,10 @@ class ChatViewController : BaseChatViewControllerWithDataSourceAndContextMenuAnd @IBAction func scrollToBottomTapped(_ sender: UIButton) { - self.conversationLogController?.tableView.setContentOffset(.zero, animated: true) + self.conversationLogController?.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .none, animated: true) + DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { + self.conversationLogController?.tableView.setContentOffset(CGPoint(x: 0, y: 1), animated: true) + } } @IBAction func rejectSubscriptionTapped(_ sender: Any) { diff --git a/Snikket/chat/ConversationLogController.swift b/Snikket/chat/ConversationLogController.swift index 2485f326..c5976678 100644 --- a/Snikket/chat/ConversationLogController.swift +++ b/Snikket/chat/ConversationLogController.swift @@ -45,7 +45,7 @@ class ConversationLogController: UIViewController, ChatViewDataSourceDelegate { tableView.rowHeight = UITableView.automaticDimension; tableView.estimatedRowHeight = 160.0; tableView.separatorStyle = .none; - tableView.scrollsToTop = false + tableView.scrollsToTop = true tableView.transform = dataSource.inverted ? CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: 0) : CGAffineTransform.identity; if let refreshControl = self.refreshControl { @@ -72,6 +72,9 @@ class ConversationLogController: UIViewController, ChatViewDataSourceDelegate { } else { self.toggleNoMessagesLabel(show: false) } + DispatchQueue.main.async { + self.tableView.setContentOffset(CGPoint(x: 0, y: 1), animated: false) + } } } } @@ -87,7 +90,10 @@ class ConversationLogController: UIViewController, ChatViewDataSourceDelegate { label.sizeToFit() self.tableView.backgroundView = label } else { - self.tableView.backgroundView = nil + DispatchQueue.main.async { + self.tableView.backgroundView = nil + } + } } @@ -95,6 +101,9 @@ class ConversationLogController: UIViewController, ChatViewDataSourceDelegate { guard rows.count > 0 else { return; } + if shouldScroll, tableView.contentOffset.y == 1 { + tableView.setContentOffset(.zero, animated: false) + } if dataSource.count == rows.count && rows.count > 1 { tableView.reloadData(); } else { @@ -105,8 +114,12 @@ class ConversationLogController: UIViewController, ChatViewDataSourceDelegate { } if shouldScroll && rows.contains(0) && (tableView.indexPathsForVisibleRows?.contains(firstRowIndexPath) ?? false) { print("added items at:", rows, "scrolling to:", firstRowIndexPath); - tableView.scrollToRow(at: firstRowIndexPath, at: .none, animated: true) + tableView.scrollToRow(at: firstRowIndexPath, at: .bottom, animated: true) + DispatchQueue.main.asyncAfter(deadline: .now()+0.2) { + self.tableView.setContentOffset(CGPoint(x: 0, y: 1), animated: false) + } } + toggleNoMessagesLabel(show: false) markAsReadUpToNewestVisibleRow(); } diff --git a/Snikket/da.lproj/Main.strings b/Snikket/da.lproj/Main.strings index b231d22d..acb145cf 100644 --- a/Snikket/da.lproj/Main.strings +++ b/Snikket/da.lproj/Main.strings @@ -22,6 +22,9 @@ /* Class = "UILabel"; text = "Message Archiving"; ObjectID = "Ckp-Mb-v0c"; */ "Ckp-Mb-v0c.text" = "Message Archiving"; +/* Class = "UITableViewSection"; headerTitle = "Invite"; ObjectID = "dib-YA-Eiz"; */ +"dib-YA-Eiz.headerTitle" = "Invite"; + /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "Dx3-QU-3cN"; */ "Dx3-QU-3cN.title" = "Back"; @@ -82,6 +85,12 @@ /* Class = "UILabel"; text = "Chat with"; ObjectID = "Qr0-8H-IJq"; */ "Qr0-8H-IJq.text" = "Chat with"; +/* Class = "UITextField"; placeholder = "Enter contact name"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.placeholder" = "Enter contact name"; + +/* Class = "UITextField"; text = "Send Invitation Link"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.text" = "Send Invitation Link"; + /* Class = "UINavigationItem"; title = "Contacts"; ObjectID = "SEz-IM-IWL"; */ "SEz-IM-IWL.title" = "Contacts"; diff --git a/Snikket/da.lproj/Settings.strings b/Snikket/da.lproj/Settings.strings index cf9f7a49..cb5e76e6 100644 --- a/Snikket/da.lproj/Settings.strings +++ b/Snikket/da.lproj/Settings.strings @@ -13,6 +13,9 @@ /* Class = "UILabel"; text = "About"; ObjectID = "3vM-ad-4ap"; */ "3vM-ad-4ap.text" = "About"; +/* Class = "UITableViewController"; title = "Notification settings"; ObjectID = "4VG-XN-BdZ"; */ +"4VG-XN-BdZ.title" = "Notification settings"; + /* Class = "UILabel"; text = "Account name"; ObjectID = "7ho-Mu-thd"; */ "7ho-Mu-thd.text" = "Account name"; @@ -109,6 +112,9 @@ /* Class = "UILabel"; text = "Blocked contacts"; ObjectID = "MJ0-kw-1Kl"; */ "MJ0-kw-1Kl.text" = "Blocked contacts"; +/* Class = "UILabel"; text = "Add to system call history"; ObjectID = "Ngk-vc-zET"; */ +"Ngk-vc-zET.text" = "Add to system call history"; + /* Class = "UILabel"; text = "\"Hidden\" group"; ObjectID = "P82-B8-768"; */ "P82-B8-768.text" = "\"Hidden\" group"; @@ -130,6 +136,12 @@ /* Class = "UILabel"; text = "20 MB"; ObjectID = "UuL-li-3gA"; */ "UuL-li-3gA.text" = "20 MB"; +/* Class = "UITableViewSection"; headerTitle = "TELEPHONY"; ObjectID = "v8T-iN-1IT"; */ +"v8T-iN-1IT.headerTitle" = "TELEPHONY"; + +/* Class = "UILabel"; text = "Calls"; ObjectID = "wfP-Tn-CDA"; */ +"wfP-Tn-CDA.text" = "Calls"; + /* Class = "UITableViewController"; title = "Contacts settings"; ObjectID = "xRS-v5-T5C"; */ "xRS-v5-T5C.title" = "Contacts settings"; diff --git a/Snikket/de.lproj/Main.strings b/Snikket/de.lproj/Main.strings index d8db4038..621bc359 100644 --- a/Snikket/de.lproj/Main.strings +++ b/Snikket/de.lproj/Main.strings @@ -22,6 +22,9 @@ /* Class = "UILabel"; text = "Message Archiving"; ObjectID = "Ckp-Mb-v0c"; */ "Ckp-Mb-v0c.text" = "Message Archiving"; +/* Class = "UITableViewSection"; headerTitle = "Invite"; ObjectID = "dib-YA-Eiz"; */ +"dib-YA-Eiz.headerTitle" = "Invite"; + /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "Dx3-QU-3cN"; */ "Dx3-QU-3cN.title" = "Back"; @@ -82,6 +85,12 @@ /* Class = "UILabel"; text = "Chat with"; ObjectID = "Qr0-8H-IJq"; */ "Qr0-8H-IJq.text" = "Chat with"; +/* Class = "UITextField"; placeholder = "Enter contact name"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.placeholder" = "Enter contact name"; + +/* Class = "UITextField"; text = "Send Invitation Link"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.text" = "Send Invitation Link"; + /* Class = "UINavigationItem"; title = "Contacts"; ObjectID = "SEz-IM-IWL"; */ "SEz-IM-IWL.title" = "Contacts"; diff --git a/Snikket/de.lproj/Settings.strings b/Snikket/de.lproj/Settings.strings index cf9f7a49..cb5e76e6 100644 --- a/Snikket/de.lproj/Settings.strings +++ b/Snikket/de.lproj/Settings.strings @@ -13,6 +13,9 @@ /* Class = "UILabel"; text = "About"; ObjectID = "3vM-ad-4ap"; */ "3vM-ad-4ap.text" = "About"; +/* Class = "UITableViewController"; title = "Notification settings"; ObjectID = "4VG-XN-BdZ"; */ +"4VG-XN-BdZ.title" = "Notification settings"; + /* Class = "UILabel"; text = "Account name"; ObjectID = "7ho-Mu-thd"; */ "7ho-Mu-thd.text" = "Account name"; @@ -109,6 +112,9 @@ /* Class = "UILabel"; text = "Blocked contacts"; ObjectID = "MJ0-kw-1Kl"; */ "MJ0-kw-1Kl.text" = "Blocked contacts"; +/* Class = "UILabel"; text = "Add to system call history"; ObjectID = "Ngk-vc-zET"; */ +"Ngk-vc-zET.text" = "Add to system call history"; + /* Class = "UILabel"; text = "\"Hidden\" group"; ObjectID = "P82-B8-768"; */ "P82-B8-768.text" = "\"Hidden\" group"; @@ -130,6 +136,12 @@ /* Class = "UILabel"; text = "20 MB"; ObjectID = "UuL-li-3gA"; */ "UuL-li-3gA.text" = "20 MB"; +/* Class = "UITableViewSection"; headerTitle = "TELEPHONY"; ObjectID = "v8T-iN-1IT"; */ +"v8T-iN-1IT.headerTitle" = "TELEPHONY"; + +/* Class = "UILabel"; text = "Calls"; ObjectID = "wfP-Tn-CDA"; */ +"wfP-Tn-CDA.text" = "Calls"; + /* Class = "UITableViewController"; title = "Contacts settings"; ObjectID = "xRS-v5-T5C"; */ "xRS-v5-T5C.title" = "Contacts settings"; diff --git a/Snikket/en-GB.lproj/Main.strings b/Snikket/en-GB.lproj/Main.strings index 9a64bb1d..e15fccc2 100644 --- a/Snikket/en-GB.lproj/Main.strings +++ b/Snikket/en-GB.lproj/Main.strings @@ -22,6 +22,9 @@ /* Class = "UILabel"; text = "Message Archiving"; ObjectID = "Ckp-Mb-v0c"; */ "Ckp-Mb-v0c.text" = "Message Archiving"; +/* Class = "UITableViewSection"; headerTitle = "Invite"; ObjectID = "dib-YA-Eiz"; */ +"dib-YA-Eiz.headerTitle" = "Invite"; + /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "Dx3-QU-3cN"; */ "Dx3-QU-3cN.title" = "Back"; @@ -82,6 +85,12 @@ /* Class = "UILabel"; text = "Chat with"; ObjectID = "Qr0-8H-IJq"; */ "Qr0-8H-IJq.text" = "Chat with"; +/* Class = "UITextField"; placeholder = "Enter contact name"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.placeholder" = "Enter contact name"; + +/* Class = "UITextField"; text = "Send Invitation Link"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.text" = "Send Invitation Link"; + /* Class = "UINavigationItem"; title = "Contacts"; ObjectID = "SEz-IM-IWL"; */ "SEz-IM-IWL.title" = "Contacts"; diff --git a/Snikket/en-GB.lproj/Settings.strings b/Snikket/en-GB.lproj/Settings.strings index cf9f7a49..cb5e76e6 100644 --- a/Snikket/en-GB.lproj/Settings.strings +++ b/Snikket/en-GB.lproj/Settings.strings @@ -13,6 +13,9 @@ /* Class = "UILabel"; text = "About"; ObjectID = "3vM-ad-4ap"; */ "3vM-ad-4ap.text" = "About"; +/* Class = "UITableViewController"; title = "Notification settings"; ObjectID = "4VG-XN-BdZ"; */ +"4VG-XN-BdZ.title" = "Notification settings"; + /* Class = "UILabel"; text = "Account name"; ObjectID = "7ho-Mu-thd"; */ "7ho-Mu-thd.text" = "Account name"; @@ -109,6 +112,9 @@ /* Class = "UILabel"; text = "Blocked contacts"; ObjectID = "MJ0-kw-1Kl"; */ "MJ0-kw-1Kl.text" = "Blocked contacts"; +/* Class = "UILabel"; text = "Add to system call history"; ObjectID = "Ngk-vc-zET"; */ +"Ngk-vc-zET.text" = "Add to system call history"; + /* Class = "UILabel"; text = "\"Hidden\" group"; ObjectID = "P82-B8-768"; */ "P82-B8-768.text" = "\"Hidden\" group"; @@ -130,6 +136,12 @@ /* Class = "UILabel"; text = "20 MB"; ObjectID = "UuL-li-3gA"; */ "UuL-li-3gA.text" = "20 MB"; +/* Class = "UITableViewSection"; headerTitle = "TELEPHONY"; ObjectID = "v8T-iN-1IT"; */ +"v8T-iN-1IT.headerTitle" = "TELEPHONY"; + +/* Class = "UILabel"; text = "Calls"; ObjectID = "wfP-Tn-CDA"; */ +"wfP-Tn-CDA.text" = "Calls"; + /* Class = "UITableViewController"; title = "Contacts settings"; ObjectID = "xRS-v5-T5C"; */ "xRS-v5-T5C.title" = "Contacts settings"; diff --git a/Snikket/en.lproj/Main.strings b/Snikket/en.lproj/Main.strings index d8db4038..621bc359 100644 --- a/Snikket/en.lproj/Main.strings +++ b/Snikket/en.lproj/Main.strings @@ -22,6 +22,9 @@ /* Class = "UILabel"; text = "Message Archiving"; ObjectID = "Ckp-Mb-v0c"; */ "Ckp-Mb-v0c.text" = "Message Archiving"; +/* Class = "UITableViewSection"; headerTitle = "Invite"; ObjectID = "dib-YA-Eiz"; */ +"dib-YA-Eiz.headerTitle" = "Invite"; + /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "Dx3-QU-3cN"; */ "Dx3-QU-3cN.title" = "Back"; @@ -82,6 +85,12 @@ /* Class = "UILabel"; text = "Chat with"; ObjectID = "Qr0-8H-IJq"; */ "Qr0-8H-IJq.text" = "Chat with"; +/* Class = "UITextField"; placeholder = "Enter contact name"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.placeholder" = "Enter contact name"; + +/* Class = "UITextField"; text = "Send Invitation Link"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.text" = "Send Invitation Link"; + /* Class = "UINavigationItem"; title = "Contacts"; ObjectID = "SEz-IM-IWL"; */ "SEz-IM-IWL.title" = "Contacts"; diff --git a/Snikket/en.lproj/Settings.strings b/Snikket/en.lproj/Settings.strings index cf9f7a49..cb5e76e6 100644 --- a/Snikket/en.lproj/Settings.strings +++ b/Snikket/en.lproj/Settings.strings @@ -13,6 +13,9 @@ /* Class = "UILabel"; text = "About"; ObjectID = "3vM-ad-4ap"; */ "3vM-ad-4ap.text" = "About"; +/* Class = "UITableViewController"; title = "Notification settings"; ObjectID = "4VG-XN-BdZ"; */ +"4VG-XN-BdZ.title" = "Notification settings"; + /* Class = "UILabel"; text = "Account name"; ObjectID = "7ho-Mu-thd"; */ "7ho-Mu-thd.text" = "Account name"; @@ -109,6 +112,9 @@ /* Class = "UILabel"; text = "Blocked contacts"; ObjectID = "MJ0-kw-1Kl"; */ "MJ0-kw-1Kl.text" = "Blocked contacts"; +/* Class = "UILabel"; text = "Add to system call history"; ObjectID = "Ngk-vc-zET"; */ +"Ngk-vc-zET.text" = "Add to system call history"; + /* Class = "UILabel"; text = "\"Hidden\" group"; ObjectID = "P82-B8-768"; */ "P82-B8-768.text" = "\"Hidden\" group"; @@ -130,6 +136,12 @@ /* Class = "UILabel"; text = "20 MB"; ObjectID = "UuL-li-3gA"; */ "UuL-li-3gA.text" = "20 MB"; +/* Class = "UITableViewSection"; headerTitle = "TELEPHONY"; ObjectID = "v8T-iN-1IT"; */ +"v8T-iN-1IT.headerTitle" = "TELEPHONY"; + +/* Class = "UILabel"; text = "Calls"; ObjectID = "wfP-Tn-CDA"; */ +"wfP-Tn-CDA.text" = "Calls"; + /* Class = "UITableViewController"; title = "Contacts settings"; ObjectID = "xRS-v5-T5C"; */ "xRS-v5-T5C.title" = "Contacts settings"; diff --git a/Snikket/fr.lproj/Main.strings b/Snikket/fr.lproj/Main.strings index 08f7b2b6..4991fc64 100644 --- a/Snikket/fr.lproj/Main.strings +++ b/Snikket/fr.lproj/Main.strings @@ -22,6 +22,9 @@ /* Class = "UILabel"; text = "Message Archiving"; ObjectID = "Ckp-Mb-v0c"; */ "Ckp-Mb-v0c.text" = "Message Archiving"; +/* Class = "UITableViewSection"; headerTitle = "Invite"; ObjectID = "dib-YA-Eiz"; */ +"dib-YA-Eiz.headerTitle" = "Invite"; + /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "Dx3-QU-3cN"; */ "Dx3-QU-3cN.title" = "Back"; @@ -82,6 +85,12 @@ /* Class = "UILabel"; text = "Chat with"; ObjectID = "Qr0-8H-IJq"; */ "Qr0-8H-IJq.text" = "Chat with"; +/* Class = "UITextField"; placeholder = "Enter contact name"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.placeholder" = "Enter contact name"; + +/* Class = "UITextField"; text = "Send Invitation Link"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.text" = "Send Invitation Link"; + /* Class = "UINavigationItem"; title = "Contacts"; ObjectID = "SEz-IM-IWL"; */ "SEz-IM-IWL.title" = "Contacts"; diff --git a/Snikket/fr.lproj/Settings.strings b/Snikket/fr.lproj/Settings.strings index cf9f7a49..cb5e76e6 100644 --- a/Snikket/fr.lproj/Settings.strings +++ b/Snikket/fr.lproj/Settings.strings @@ -13,6 +13,9 @@ /* Class = "UILabel"; text = "About"; ObjectID = "3vM-ad-4ap"; */ "3vM-ad-4ap.text" = "About"; +/* Class = "UITableViewController"; title = "Notification settings"; ObjectID = "4VG-XN-BdZ"; */ +"4VG-XN-BdZ.title" = "Notification settings"; + /* Class = "UILabel"; text = "Account name"; ObjectID = "7ho-Mu-thd"; */ "7ho-Mu-thd.text" = "Account name"; @@ -109,6 +112,9 @@ /* Class = "UILabel"; text = "Blocked contacts"; ObjectID = "MJ0-kw-1Kl"; */ "MJ0-kw-1Kl.text" = "Blocked contacts"; +/* Class = "UILabel"; text = "Add to system call history"; ObjectID = "Ngk-vc-zET"; */ +"Ngk-vc-zET.text" = "Add to system call history"; + /* Class = "UILabel"; text = "\"Hidden\" group"; ObjectID = "P82-B8-768"; */ "P82-B8-768.text" = "\"Hidden\" group"; @@ -130,6 +136,12 @@ /* Class = "UILabel"; text = "20 MB"; ObjectID = "UuL-li-3gA"; */ "UuL-li-3gA.text" = "20 MB"; +/* Class = "UITableViewSection"; headerTitle = "TELEPHONY"; ObjectID = "v8T-iN-1IT"; */ +"v8T-iN-1IT.headerTitle" = "TELEPHONY"; + +/* Class = "UILabel"; text = "Calls"; ObjectID = "wfP-Tn-CDA"; */ +"wfP-Tn-CDA.text" = "Calls"; + /* Class = "UITableViewController"; title = "Contacts settings"; ObjectID = "xRS-v5-T5C"; */ "xRS-v5-T5C.title" = "Contacts settings"; diff --git a/Snikket/groupchat/MucChatViewController.swift b/Snikket/groupchat/MucChatViewController.swift index d948a5c2..599d59ee 100644 --- a/Snikket/groupchat/MucChatViewController.swift +++ b/Snikket/groupchat/MucChatViewController.swift @@ -102,7 +102,35 @@ class MucChatViewController: BaseChatViewControllerWithDataSourceAndContextMenuA } @IBAction func scrollToBottomTapped(_ sender: RoundShadowButton) { - self.conversationLogController?.tableView.setContentOffset(.zero, animated: true) + self.conversationLogController?.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .none, animated: true) + DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { + self.conversationLogController?.tableView.setContentOffset(CGPoint(x: 0, y: 1), animated: true) + } + } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + // scrollViewShouldScrollToTop will not get called if tableview is already at top + guard var contentOffset = self.conversationLogController?.tableView.contentOffset else { return } + if contentOffset.y == 0 { + contentOffset.y = 1 + self.conversationLogController?.tableView.setContentOffset(contentOffset, animated: true) + } + } + + func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { + scrollToTop() + return false + } + + func scrollToTop() { + if let count = self.conversationLogController?.dataSource.count, count > 0 { + var currentRow = self.conversationLogController?.tableView.indexPathsForVisibleRows?.first?.row ?? 0 + currentRow = count > currentRow + 40 ? currentRow + 40 : count + let indexPath = IndexPath(row: currentRow - 1, section: 0) + DispatchQueue.main.async { + self.conversationLogController?.tableView.scrollToRow(at: indexPath, at: .none, animated: true) + } + } } func setupGroupName() { diff --git a/Snikket/roster/RosterItemEditViewController.swift b/Snikket/roster/RosterItemEditViewController.swift index fe6dd09e..1db44186 100644 --- a/Snikket/roster/RosterItemEditViewController.swift +++ b/Snikket/roster/RosterItemEditViewController.swift @@ -26,6 +26,7 @@ class RosterItemEditViewController: UITableViewController, UIPickerViewDataSourc var xmppService:XmppService! + @IBOutlet weak var invitationLinkIndicator: UIActivityIndicatorView! @IBOutlet var accountTextField: UITextField! @IBOutlet var jidTextField: UITextField! @IBOutlet var nameTextField: UITextField! @@ -69,6 +70,45 @@ class RosterItemEditViewController: UITableViewController, UIPickerViewDataSourc self.nameTextField.text = nil; } } + + func createInvitationLink() { + guard let account = BareJID(self.accountTextField.text), let client = xmppService.getClient(for: account) else { return } + + let inviteCommand = "urn:xmpp:invite#invite" + if let adHocModule: AdHocCommandsModule = client.modulesManager.getModule(AdHocCommandsModule.ID) { + adHocModule.execute(on: JID(account.domain), command: inviteCommand, action: .execute, data: nil) { response, data in + if let inviteLink = data?.getField(named: "landing-url")?.element.findChild(name: "value")?.value { + self.presentShareSheet(url: inviteLink) + } + } onError: { error in + self.toggleActivityIndicator(toggle: false) + } + + } + } + + func presentShareSheet(url: String) { + guard let url = URL(string: url) else { + self.toggleActivityIndicator(toggle: false) + return + } + + let items: [Any] = [url] + let ac = UIActivityViewController(activityItems: items, applicationActivities: nil) + DispatchQueue.main.async { + self.present(ac, animated: true) { + self.toggleActivityIndicator(toggle: false) + } + } + + } + + func toggleActivityIndicator(toggle: Bool) { + DispatchQueue.main.async { + if toggle { self.invitationLinkIndicator.startAnimating() } + else {self.invitationLinkIndicator.stopAnimating() } + } + } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() @@ -217,6 +257,13 @@ class RosterItemEditViewController: UITableViewController, UIPickerViewDataSourc func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { self.accountTextField.text = self.pickerView(pickerView, titleForRow: row, forComponent: component); + self.view.endEditing(true) } + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if indexPath.section == 4, indexPath.row == 0, !invitationLinkIndicator.isAnimating { + toggleActivityIndicator(toggle: true) + self.createInvitationLink() + } + } } diff --git a/Snikket/service/MessageEventHandler.swift b/Snikket/service/MessageEventHandler.swift index 0e26bd95..33d8f9e4 100644 --- a/Snikket/service/MessageEventHandler.swift +++ b/Snikket/service/MessageEventHandler.swift @@ -154,7 +154,7 @@ class MessageEventHandler: XmppServiceEventHandler { return; } - let encryption = encrypted ?? chat.options.encryption ?? ChatEncryption(rawValue: Settings.messageEncryption.string()!)!; + var encryption = encrypted ?? chat.options.encryption ?? ChatEncryption(rawValue: Settings.messageEncryption.string()!)!; let message = chat.createMessage(msg); message.id = stanzaId ?? UUID().uuidString; @@ -163,6 +163,11 @@ class MessageEventHandler: XmppServiceEventHandler { let account = chat.account; let jid = chat.jid.bareJid; + + // chat.options.encryption == nil means it is set to defualt + if let telephonyProvider = AccountSettings.telephonyProvider(account).getString(), jid.domain.lowercased() == telephonyProvider.lowercased(), (chat.options.encryption == nil || chat.options.encryption == ChatEncryption.none) { + encryption = ChatEncryption.none + } switch encryption { case .omemo: diff --git a/Snikket/settings/AccountSettingsViewController.swift b/Snikket/settings/AccountSettingsViewController.swift index 9d083c89..587ff9ab 100644 --- a/Snikket/settings/AccountSettingsViewController.swift +++ b/Snikket/settings/AccountSettingsViewController.swift @@ -419,11 +419,16 @@ class AccountSettingsViewController: UITableViewController { } func disablePushNotifications(completion: @escaping (Bool) -> Void) { - guard let account = self.account, let config = AccountManager.getAccount(for: account), let pushSettings = config.pushSettings else { + guard let account = self.account, let config = AccountManager.getAccount(for: account) else { completion(false) return } + guard let pushSettings = config.pushSettings else { + completion(true) + return + } + if let client = XmppService.instance.getClient(forJid: BareJID(account)), client.state == .connected, let pushModule: SiskinPushNotificationsModule = client.modulesManager.getModule(SiskinPushNotificationsModule.ID) { pushModule.unregisterDeviceAndDisable(completionHandler: { result in switch result { diff --git a/Snikket/settings/CallsSettingsViewController.swift b/Snikket/settings/CallsSettingsViewController.swift new file mode 100644 index 00000000..10b57157 --- /dev/null +++ b/Snikket/settings/CallsSettingsViewController.swift @@ -0,0 +1,53 @@ +// +// CallsSettingsViewController.swift +// Snikket +// +// Created by Muhammad Khalid on 29/10/2021. +// Copyright © 2021 Snikket. All rights reserved. +// + +import UIKit +import CallKit + +class CallsSettingsViewController: UITableViewController { + + @IBOutlet weak var callsSwitch: UISwitch! + + override func viewDidLoad() { + super.viewDidLoad() + + callsSwitch.isOn = Settings.addCallsToSystem.getBool() + } + + // MARK: - Table view data source + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 1 + } + + @IBAction func valueChanged(_ sender: UISwitch) { + Settings.addCallsToSystem.setValue(sender.isOn) + enableAddCallsToSystem(enable: sender.isOn) + } + + func enableAddCallsToSystem(enable: Bool) { + let config = CXProviderConfiguration(localizedName: "Snikket"); + if #available(iOS 13.0, *) { + if let image = UIImage(systemName: "message.fill") { + config.iconTemplateImageData = image.pngData(); + } + } else { + if let image = UIImage(named: "message.fill") { + config.iconTemplateImageData = image.pngData(); + } + } + config.includesCallsInRecents = enable; + config.supportsVideo = true; + config.maximumCallsPerCallGroup = 1; + config.maximumCallGroups = 1; + config.supportedHandleTypes = [.generic]; + + CallManager.instance?.provider = CXProvider(configuration: config); + CallManager.instance?.provider.setDelegate(CallManager.instance, queue: nil) + } +} diff --git a/Snikket/settings/SettingsViewController.swift b/Snikket/settings/SettingsViewController.swift index e61e043f..988beab3 100644 --- a/Snikket/settings/SettingsViewController.swift +++ b/Snikket/settings/SettingsViewController.swift @@ -170,6 +170,9 @@ class SettingsViewController: UITableViewController { let cell = tableView.dequeueReusableCell(withIdentifier: "ExperimentalSettingsViewCell", for: indexPath); cell.accessoryType = .disclosureIndicator; return cell; + case .calls: + let cell = tableView.dequeueReusableCell(withIdentifier: "CallsSettingsViewCell", for: indexPath) + return cell case .about: let cell = tableView.dequeueReusableCell(withIdentifier: "AboutSettingsViewCell", for: indexPath); return cell; @@ -396,13 +399,14 @@ class SettingsViewController: UITableViewController { case notifications case media case experimental + case calls case about static let groups: [SettingsGroup] = { if #available(iOS 13.0, *) { - return [.appearance, .chat, .contacts, .media, .about] + return [.appearance, .chat, .contacts, .media, .calls, .about] } else { - return [.chat, .contacts, .media, .about] + return [.chat, .contacts, .media, .calls, .about] } }() } diff --git a/Snikket/sv.lproj/Main.strings b/Snikket/sv.lproj/Main.strings index c60f1972..4d1d7975 100644 --- a/Snikket/sv.lproj/Main.strings +++ b/Snikket/sv.lproj/Main.strings @@ -22,6 +22,9 @@ /* Class = "UILabel"; text = "Message Archiving"; ObjectID = "Ckp-Mb-v0c"; */ "Ckp-Mb-v0c.text" = "Meddelandearkivering"; +/* Class = "UITableViewSection"; headerTitle = "Invite"; ObjectID = "dib-YA-Eiz"; */ +"dib-YA-Eiz.headerTitle" = "Invite"; + /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "Dx3-QU-3cN"; */ "Dx3-QU-3cN.title" = "Tillbaka"; @@ -82,6 +85,12 @@ /* Class = "UILabel"; text = "Chat with"; ObjectID = "Qr0-8H-IJq"; */ "Qr0-8H-IJq.text" = "Chat with"; +/* Class = "UITextField"; placeholder = "Enter contact name"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.placeholder" = "Enter contact name"; + +/* Class = "UITextField"; text = "Send Invitation Link"; ObjectID = "Rg7-YE-y8H"; */ +"Rg7-YE-y8H.text" = "Send Invitation Link"; + /* Class = "UINavigationItem"; title = "Contacts"; ObjectID = "SEz-IM-IWL"; */ "SEz-IM-IWL.title" = "Contacts"; diff --git a/Snikket/sv.lproj/Settings.strings b/Snikket/sv.lproj/Settings.strings index 583f5f96..f2e00bee 100644 --- a/Snikket/sv.lproj/Settings.strings +++ b/Snikket/sv.lproj/Settings.strings @@ -13,6 +13,9 @@ /* Class = "UILabel"; text = "About"; ObjectID = "3vM-ad-4ap"; */ "3vM-ad-4ap.text" = "Om"; +/* Class = "UITableViewController"; title = "Notification settings"; ObjectID = "4VG-XN-BdZ"; */ +"4VG-XN-BdZ.title" = "Notification settings"; + /* Class = "UILabel"; text = "Account name"; ObjectID = "7ho-Mu-thd"; */ "7ho-Mu-thd.text" = "Namn på kontot"; @@ -109,6 +112,9 @@ /* Class = "UILabel"; text = "Blocked contacts"; ObjectID = "MJ0-kw-1Kl"; */ "MJ0-kw-1Kl.text" = "Blockerade kontakter"; +/* Class = "UILabel"; text = "Add to system call history"; ObjectID = "Ngk-vc-zET"; */ +"Ngk-vc-zET.text" = "Add to system call history"; + /* Class = "UILabel"; text = "\"Hidden\" group"; ObjectID = "P82-B8-768"; */ "P82-B8-768.text" = "\"Dold\" grupp"; @@ -130,6 +136,12 @@ /* Class = "UILabel"; text = "20 MB"; ObjectID = "UuL-li-3gA"; */ "UuL-li-3gA.text" = "20 MB"; +/* Class = "UITableViewSection"; headerTitle = "TELEPHONY"; ObjectID = "v8T-iN-1IT"; */ +"v8T-iN-1IT.headerTitle" = "TELEPHONY"; + +/* Class = "UILabel"; text = "Calls"; ObjectID = "wfP-Tn-CDA"; */ +"wfP-Tn-CDA.text" = "Calls"; + /* Class = "UITableViewController"; title = "Contacts settings"; ObjectID = "xRS-v5-T5C"; */ "xRS-v5-T5C.title" = "Inställningar för kontakter"; diff --git a/Snikket/util/Settings.swift b/Snikket/util/Settings.swift index f0681dc6..951e74f4 100644 --- a/Snikket/util/Settings.swift +++ b/Snikket/util/Settings.swift @@ -50,6 +50,7 @@ public enum Settings: String { case EnableMarkdownFormatting = "markdown" case ShowEmoticons case messageStyling + case addCallsToSystem @available(iOS 13.0, *) case linkPreviews diff --git a/Snikket/voip/CallManager.swift b/Snikket/voip/CallManager.swift index 272cf535..4466a099 100644 --- a/Snikket/voip/CallManager.swift +++ b/Snikket/voip/CallManager.swift @@ -54,7 +54,7 @@ class CallManager: NSObject, CXProviderDelegate { private let pushRegistry: PKPushRegistry; - private let provider: CXProvider; + public var provider: CXProvider; private let callController: CXCallController; private(set) var currentCall: Call?; @@ -92,7 +92,7 @@ class CallManager: NSObject, CXProviderDelegate { config.iconTemplateImageData = image.pngData(); } } - config.includesCallsInRecents = false; + config.includesCallsInRecents = Settings.addCallsToSystem.getBool() config.supportsVideo = true; config.maximumCallsPerCallGroup = 1; config.maximumCallGroups = 1; @@ -125,7 +125,11 @@ class CallManager: NSObject, CXProviderDelegate { update.supportsHolding = false provider.configuration.supportsVideo = call.media.contains(.video) update.hasVideo = AVCaptureDevice.authorizationStatus(for: .video) == .authorized && call.media.contains(.video) - update.remoteHandle = call.media.contains(.video) ? CXHandle(type: .generic, value: call.jid.stringValue) : nil + + let telephonyProvider = AccountSettings.telephonyProvider(call.account).getString() ?? "" + let handle = telephonyProvider == call.jid.domain ? CXHandle(type: .phoneNumber, value: (call.jid.localPart ?? "Unknown")) : CXHandle(type: .generic, value: call.jid.stringValue) + + update.remoteHandle = handle configureAudioSession() provider.reportNewIncomingCall(with: call.uuid, update: update, completion: { err in guard let error = err else { @@ -168,7 +172,10 @@ class CallManager: NSObject, CXProviderDelegate { let rosterModule: RosterModule? = XmppService.instance.getClient(for: call.account)?.modulesManager.getModule(RosterModule.ID); let name = rosterModule?.rosterStore.get(for: JID(call.jid))?.name ?? call.jid.stringValue; - let startCallAction = CXStartCallAction(call: call.uuid, handle: CXHandle(type: .generic, value: call.jid.stringValue)); + let telephonyProvider = AccountSettings.telephonyProvider(call.account).getString() ?? "" + let handle = telephonyProvider == call.jid.domain ? CXHandle(type: .phoneNumber, value: (call.jid.localPart ?? "Unknown")) : CXHandle(type: .generic, value: call.jid.stringValue) + + let startCallAction = CXStartCallAction(call: call.uuid, handle: handle) startCallAction.isVideo = call.media.contains(.video); startCallAction.contactIdentifier = name; let transaction = CXTransaction(action: startCallAction);