diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..dc5c981972f2240ba620ca3b4f5bb9108d8157d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +.DS_Store +PrivacyDemo.xcodeproj/project.xcworkspace/xcuserdata/ahmedshehata.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/PrivacyDemo.xcodeproj/project.pbxproj b/PrivacyDemo.xcodeproj/project.pbxproj index d58fbbc2c5f2633e82476414af72fb60d02464d9..5dd263ae7818e6a402c69b6348fb20ea1469c4bb 100644 --- a/PrivacyDemo.xcodeproj/project.pbxproj +++ b/PrivacyDemo.xcodeproj/project.pbxproj @@ -23,6 +23,8 @@ 6CB9D340284EBFC6000D53C1 /* Password+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CB9D33F284EBFC6000D53C1 /* Password+Extension.swift */; }; 6CB9D342284EF4B9000D53C1 /* FAQ.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CB9D341284EF4B9000D53C1 /* FAQ.swift */; }; 6CB9D346284F0CE5000D53C1 /* MessageContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CB9D345284F0CE5000D53C1 /* MessageContent.swift */; }; + 6CC614C128754E5200354B01 /* ProviderNameConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC614C028754E5200354B01 /* ProviderNameConstants.swift */; }; + 6CCAB02028750CDC0018315C /* RequestTypeConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCAB01F28750CDC0018315C /* RequestTypeConstants.swift */; }; 6CE7BA57284930A0003DE341 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE7BA56284930A0003DE341 /* AppDelegate.swift */; }; 6CE7BA59284930A0003DE341 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE7BA58284930A0003DE341 /* SceneDelegate.swift */; }; 6CE7BA60284930A2003DE341 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CE7BA5F284930A2003DE341 /* Assets.xcassets */; }; @@ -54,6 +56,8 @@ 6CB9D33F284EBFC6000D53C1 /* Password+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Password+Extension.swift"; sourceTree = "<group>"; }; 6CB9D341284EF4B9000D53C1 /* FAQ.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQ.swift; sourceTree = "<group>"; }; 6CB9D345284F0CE5000D53C1 /* MessageContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageContent.swift; sourceTree = "<group>"; }; + 6CC614C028754E5200354B01 /* ProviderNameConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderNameConstants.swift; sourceTree = "<group>"; }; + 6CCAB01F28750CDC0018315C /* RequestTypeConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTypeConstants.swift; sourceTree = "<group>"; }; 6CE7BA53284930A0003DE341 /* PrivacyDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PrivacyDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6CE7BA56284930A0003DE341 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 6CE7BA58284930A0003DE341 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; }; @@ -197,6 +201,8 @@ 6CE7BA84284979B5003DE341 /* ColorsConstants.swift */, 6CE7BA8928497A43003DE341 /* AppConstants.swift */, 6CE7BA8B28497CDD003DE341 /* StoryboardConstants.swift */, + 6CCAB01F28750CDC0018315C /* RequestTypeConstants.swift */, + 6CC614C028754E5200354B01 /* ProviderNameConstants.swift */, ); path = Constants; sourceTree = "<group>"; @@ -327,6 +333,7 @@ buildActionMask = 2147483647; files = ( 6CE7BA57284930A0003DE341 /* AppDelegate.swift in Sources */, + 6CCAB02028750CDC0018315C /* RequestTypeConstants.swift in Sources */, 6CABA00D284D509A00F0200B /* ProvidersViewController.swift in Sources */, 6CB9D339284EAED3000D53C1 /* ElixxirHandler.swift in Sources */, 6CE7BA7828493DFC003DE341 /* ChatViewController.swift in Sources */, @@ -335,6 +342,7 @@ 6CE7BA85284979B5003DE341 /* ColorsConstants.swift in Sources */, 6CB9D342284EF4B9000D53C1 /* FAQ.swift in Sources */, 6CB9D33C284EBF02000D53C1 /* AlertsHandler.swift in Sources */, + 6CC614C128754E5200354B01 /* ProviderNameConstants.swift in Sources */, 6CB9D340284EBFC6000D53C1 /* Password+Extension.swift in Sources */, 6CB9D33E284EBF79000D53C1 /* LoadingIndicatorHandler.swift in Sources */, 6CB9D346284F0CE5000D53C1 /* MessageContent.swift in Sources */, @@ -412,7 +420,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -466,7 +474,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.4; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -483,11 +491,14 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = S6JDM2WW29; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PrivacyDemo/AppResources/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Shielded Help"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Splash; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( @@ -495,7 +506,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.elixxir.PrivacyDemo.PrivacyDemo; + PRODUCT_BUNDLE_IDENTIFIER = com.elixxir.shieldedhelp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -510,11 +521,14 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = S6JDM2WW29; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PrivacyDemo/AppResources/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Shielded Help"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Splash; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( @@ -522,7 +536,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.elixxir.PrivacyDemo.PrivacyDemo; + PRODUCT_BUNDLE_IDENTIFIER = com.elixxir.shieldedhelp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; diff --git a/PrivacyDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/PrivacyDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 72b71486c894733b1b48f088654b038f4b97642a..c7810b8a72889dd2d7c54f836ed9e36f21abd18a 100644 --- a/PrivacyDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/PrivacyDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,7 +6,7 @@ "location" : "https://git.xx.network/elixxir/elixxir-dapps-sdk-swift", "state" : { "branch" : "main", - "revision" : "a65d6542c9ffd5d0751b4509a445d621615b3493" + "revision" : "f428d6b3c5416783779968a6121f0a0678ac911f" } }, { diff --git a/PrivacyDemo.xcodeproj/project.xcworkspace/xcuserdata/ahmedshehata.xcuserdatad/UserInterfaceState.xcuserstate b/PrivacyDemo.xcodeproj/project.xcworkspace/xcuserdata/ahmedshehata.xcuserdatad/UserInterfaceState.xcuserstate index ceac2cab3d3a919578c6077b66dadaa1b83d6c8e..496c0fdf76a79c1be649e4de4ad1bfebef1eb0ec 100644 Binary files a/PrivacyDemo.xcodeproj/project.xcworkspace/xcuserdata/ahmedshehata.xcuserdatad/UserInterfaceState.xcuserstate and b/PrivacyDemo.xcodeproj/project.xcworkspace/xcuserdata/ahmedshehata.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/PrivacyDemo.xcodeproj/xcuserdata/ahmedshehata.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/PrivacyDemo.xcodeproj/xcuserdata/ahmedshehata.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 194e69ed4f13baf589fc60d43fc231c907d95bcd..573aee813ff68a024070aac47d3eaa2b9dff0f4b 100644 --- a/PrivacyDemo.xcodeproj/xcuserdata/ahmedshehata.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/PrivacyDemo.xcodeproj/xcuserdata/ahmedshehata.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -3,4 +3,118 @@ uuid = "11772AE9-A52D-4B02-92ED-3C9FB13D23BE" type = "1" version = "2.0"> + <Breakpoints> + <BreakpointProxy + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> + <BreakpointContent + uuid = "47C5D786-B61E-47A7-AAE3-8FE75941290B" + shouldBeEnabled = "No" + ignoreCount = "0" + continueAfterRunningActions = "No" + filePath = "PrivacyDemo/Chat/ChatViewController.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "168" + endingLineNumber = "168" + landmarkName = "loadFirstMessages()" + landmarkType = "7"> + </BreakpointContent> + </BreakpointProxy> + <BreakpointProxy + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> + <BreakpointContent + uuid = "3F6894AF-21B3-4F30-AC90-E2F8F32166AC" + shouldBeEnabled = "No" + ignoreCount = "0" + continueAfterRunningActions = "No" + filePath = "PrivacyDemo/Chat/ChatViewController.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "339" + endingLineNumber = "339" + landmarkName = "didSelectMention(_:)" + landmarkType = "7"> + </BreakpointContent> + </BreakpointProxy> + <BreakpointProxy + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> + <BreakpointContent + uuid = "BE0B1388-23FC-425C-8A54-2B63535F28E2" + shouldBeEnabled = "Yes" + ignoreCount = "0" + continueAfterRunningActions = "No" + filePath = "PrivacyDemo/Chat/ChatViewController.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "197" + endingLineNumber = "197" + landmarkName = "setSuggestedProviderValues(from:)" + landmarkType = "7"> + </BreakpointContent> + </BreakpointProxy> + <BreakpointProxy + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> + <BreakpointContent + uuid = "51E9DF34-9929-4107-93CA-A1B3AF258AFC" + shouldBeEnabled = "Yes" + ignoreCount = "0" + continueAfterRunningActions = "No" + filePath = "PrivacyDemo/PrivateProviders/ProvidersViewController.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "206" + endingLineNumber = "206" + landmarkName = "setupProvidersButtonMenu(initialSelection:)" + landmarkType = "7"> + </BreakpointContent> + </BreakpointProxy> + <BreakpointProxy + BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> + <BreakpointContent + uuid = "9E1AC49C-AFBA-4B55-9927-EB937625FFCC" + shouldBeEnabled = "Yes" + ignoreCount = "0" + continueAfterRunningActions = "No" + filePath = "PrivacyDemo/PrivateProviders/ProvidersViewController.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "132" + endingLineNumber = "132" + landmarkName = "prefillIfNecessary()" + landmarkType = "7"> + <Locations> + <Location + uuid = "9E1AC49C-AFBA-4B55-9927-EB937625FFCC - d21fedeed63f3745" + shouldBeEnabled = "Yes" + ignoreCount = "0" + continueAfterRunningActions = "No" + symbolName = "PrivacyDemo.ProvidersViewController.prefillIfNecessary() -> ()" + moduleName = "PrivacyDemo" + usesParentBreakpointCondition = "Yes" + urlString = "file:///Users/ahmedshehata/XR/elixxir-dapp-demo/PrivacyDemo/PrivateProviders/ProvidersViewController.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "132" + endingLineNumber = "132" + offsetFromSymbolStart = "136"> + </Location> + <Location + uuid = "9E1AC49C-AFBA-4B55-9927-EB937625FFCC - d21fedeed63f3745" + shouldBeEnabled = "Yes" + ignoreCount = "0" + continueAfterRunningActions = "No" + symbolName = "PrivacyDemo.ProvidersViewController.prefillIfNecessary() -> ()" + moduleName = "PrivacyDemo" + usesParentBreakpointCondition = "Yes" + urlString = "file:///Users/ahmedshehata/XR/elixxir-dapp-demo/PrivacyDemo/PrivateProviders/ProvidersViewController.swift" + startingColumnNumber = "9223372036854775807" + endingColumnNumber = "9223372036854775807" + startingLineNumber = "132" + endingLineNumber = "132" + offsetFromSymbolStart = "196"> + </Location> + </Locations> + </BreakpointContent> + </BreakpointProxy> + </Breakpoints> </Bucket> diff --git a/PrivacyDemo/AppResources/Base.lproj/LaunchScreen.storyboard b/PrivacyDemo/AppResources/Base.lproj/LaunchScreen.storyboard index c295d37af1822a1888d4a8b5a67d1f992220984a..33569d9d0595526aa823fc7913459c52dfb48e64 100644 --- a/PrivacyDemo/AppResources/Base.lproj/LaunchScreen.storyboard +++ b/PrivacyDemo/AppResources/Base.lproj/LaunchScreen.storyboard @@ -20,13 +20,13 @@ <rect key="frame" x="28.333333333333343" y="326.66666666666669" width="333.33333333333326" height="200.66666666666669"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shielded Help" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="VEv-7L-Rqy"> - <rect key="frame" x="20" y="19.999999999999996" width="293.33333333333331" height="34.666666666666657"/> + <rect key="frame" x="20" y="20" width="293.33333333333331" height="72.333333333333329"/> <fontDescription key="fontDescription" name="Menlo-Bold" family="Menlo" pointSize="40"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Shield" translatesAutoresizingMaskIntoConstraints="NO" id="OAP-yW-yO6"> - <rect key="frame" x="107.66666666666669" y="62.666666666666629" width="118" height="118"/> + <rect key="frame" x="126.66666666666669" y="100.33333333333331" width="80" height="80.333333333333314"/> <constraints> <constraint firstAttribute="width" secondItem="OAP-yW-yO6" secondAttribute="height" multiplier="1:1" id="T6P-YG-bf7"/> </constraints> @@ -34,6 +34,7 @@ </subviews> <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> + <constraint firstItem="OAP-yW-yO6" firstAttribute="height" secondItem="Lif-fS-EPO" secondAttribute="height" multiplier="0.4" id="BFQ-Cg-M0c"/> <constraint firstAttribute="bottom" secondItem="OAP-yW-yO6" secondAttribute="bottom" constant="20.000000000000057" id="FeM-WW-YQn"/> <constraint firstItem="VEv-7L-Rqy" firstAttribute="top" secondItem="Lif-fS-EPO" secondAttribute="top" constant="20" symbolic="YES" id="GDZ-fj-fQl"/> <constraint firstItem="OAP-yW-yO6" firstAttribute="centerX" secondItem="Lif-fS-EPO" secondAttribute="centerX" id="Mll-dB-W8F"/> diff --git a/PrivacyDemo/Chat/ChatViewController.swift b/PrivacyDemo/Chat/ChatViewController.swift index e77064cfc8de7d2f83225d2f2aeec1d68ab0fa6c..b574618fcb3cf9f9294aefcf3c56f6422e2f413a 100644 --- a/PrivacyDemo/Chat/ChatViewController.swift +++ b/PrivacyDemo/Chat/ChatViewController.swift @@ -2,6 +2,7 @@ import UIKit import MessageKit import InputBarAccessoryView import ElixxirDAppsSDK +import SafariServices class ChatViewController: MessagesViewController { @@ -9,11 +10,15 @@ class ChatViewController: MessagesViewController { private lazy var messageList: [ChatMessage] = [] private let helperUser = User(senderId: Constants.helperUserId, - displayName: "Your anonymouse helper") + displayName: "Your anonymous helper") private let currentUser = User(senderId: Constants.currentUserId, displayName: "You") private var connection: Connection? private var loadingIndicator: LoadingIndicatorView! + private var suggestedProviders = [String: (name:String?, requestType: String?, code: String?)?]() + private let receivedChatMessageAttributes = [NSAttributedString.Key.font: UIFont(name: "Menlo", size: 16.0)!] + private let sentChatMessageAttributes = [NSAttributedString.Key.font: UIFont(name: "Menlo", size: 16.0)!, + NSAttributedString.Key.foregroundColor: UIColor.white] // MARK: - Lifecycle @@ -37,7 +42,7 @@ class ChatViewController: MessagesViewController { // MARK: - SDK func sendE2EMessage(message: String) { - DispatchQueue.global(qos: .background).async { [weak self] in + DispatchQueue.global(qos: .userInteractive).async { [weak self] in guard let self = self else { return } do { let sendReport = try self.connection!.send(messageType: 1, @@ -60,15 +65,16 @@ class ChatViewController: MessagesViewController { print("JK E2E delivered with roundResults reposne ",roundResults) messageInputBar.sendButton.stopAnimating() messageInputBar.inputTextView.placeholder = "Aa" - let message = ChatMessage(kind: .text(message), user: currentUser, messageId: UUID().uuidString, date: Date.now) - insertMessage(message) + let attributedMessage = NSAttributedString(string: message, attributes: sentChatMessageAttributes) + let chatMessage = ChatMessage(kind: .attributedText(attributedMessage), user: currentUser, messageId: UUID().uuidString, date: Date.now) + insertMessage(chatMessage) case .notDelivered: self.handleError("Message sending timed out, please try again.") } } func listenToMessages() { - DispatchQueue.global(qos: .background).async { [weak self] in + DispatchQueue.global(qos: .userInteractive).async { [weak self] in guard let self = self else { return } self.connection!.listen(messageType: 1) { message in DispatchQueue.main.async { [weak self] in @@ -81,7 +87,20 @@ class ChatViewController: MessagesViewController { func handleReceivedMessage(_ message: Message) { let payload = String(decoding: message.payload, as: UTF8.self) - let chatMessage = ChatMessage(kind: .text(payload), + let pattern = "<[^\"]+>" + var replacement = "@Provider" + if let rangeOfValues = payload.range(of: pattern, options: .regularExpression) { + let valuesText = payload[rangeOfValues] + let name = setSuggestedProviderValues(from: valuesText) + replacement = "@\(name)" + } + let formattedPayload = payload.replacingOccurrences( + of: pattern, + with: replacement, + options: .regularExpression + ) + let attributedPayload = NSAttributedString(string: formattedPayload, attributes: receivedChatMessageAttributes) + let chatMessage = ChatMessage(kind: .attributedText(attributedPayload), user: self.helperUser, messageId: UUID().uuidString, date: .now) @@ -89,13 +108,15 @@ class ChatViewController: MessagesViewController { } func initConnection() { - loadingIndicator.startAnimating(inView: self.view, shouldDisableInteraction: true, text: "Initiating...") - DispatchQueue.global(qos: .background).async { [weak self] in + loadingIndicator.startAnimating(inView: self.view, shouldDisableInteraction: true, text: "Initiating & securing connection") + DispatchQueue.global(qos: .userInteractive).async { [weak self] in guard let self = self else { return } do { + let clientE2E = try ClientE2ELogin.live(with: ElixxirHandler.shared.client!) + self.connection = try ElixxirHandler.shared.client!.connect(withAuthentication: false, recipientContact: Data(Constants.chatRecipentContact.utf8), - myIdentity: ElixxirHandler.shared.myIdentity) + e2eId: clientE2E.getId()) DispatchQueue.main.async { [weak self] in guard let self = self else { return } self.loadingIndicator.stopAnimating() @@ -120,6 +141,7 @@ class ChatViewController: MessagesViewController { messagesCollectionView.messagesDataSource = self messagesCollectionView.messagesLayoutDelegate = self messagesCollectionView.messagesDisplayDelegate = self + messagesCollectionView.messageCellDelegate = self messagesCollectionView.contentInset.top = 40 scrollsToLastItemOnKeyboardBeginsEditing = true maintainPositionOnInputBarHeightChanged = true @@ -147,8 +169,8 @@ class ChatViewController: MessagesViewController { } func loadFirstMessages() { - let welcomeText = "Welcome to the anonymouse help chat" - let welcomeMessage = ChatMessage(kind: .text(welcomeText), + let welcomeText = NSAttributedString(string: "Welcome to the anonymous help chat. How can we help you?", attributes: receivedChatMessageAttributes) + let welcomeMessage = ChatMessage(kind: .attributedText(welcomeText), user: self.helperUser, messageId: UUID().uuidString, date: .now) @@ -169,6 +191,17 @@ class ChatViewController: MessagesViewController { }) } + func setSuggestedProviderValues(from text: Substring) -> String { + let text = String(text) + let suggestedProviderValues = text.components(separatedBy: ":") + let name = String(suggestedProviderValues[0].dropFirst()) + let requestType = suggestedProviderValues[1] + let code = String(suggestedProviderValues[2].dropLast()) + let displayName = name.filter {!$0.isWhitespace} + suggestedProviders[displayName] = (name.lowercased().filter {!$0.isWhitespace},requestType,code) + return displayName + } + func isLastSectionVisible() -> Bool { guard !messageList.isEmpty else { return false } let lastIndexPath = IndexPath(item: 0, section: messageList.count - 1) @@ -208,7 +241,7 @@ extension ChatViewController: MessagesDataSource { func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { if isTimeLabelVisible(at: indexPath) { - return NSAttributedString(string: MessageKitDateFormatter.shared.string(from: message.sentDate), attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 10), NSAttributedString.Key.foregroundColor: UIColor.darkGray]) + return NSAttributedString(string: MessageKitDateFormatter.shared.string(from: message.sentDate), attributes: [NSAttributedString.Key.font: UIFont(name: "Menlo Bold", size: 10.0)!, NSAttributedString.Key.foregroundColor: UIColor.darkGray]) } return nil } @@ -216,7 +249,7 @@ extension ChatViewController: MessagesDataSource { func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { if !isPreviousMessageSameSender(at: indexPath) { let name = message.sender.displayName - return NSAttributedString(string: name, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption1)]) + return NSAttributedString(string: name, attributes: [NSAttributedString.Key.font: UIFont(name: "Menlo", size: 10.0)!]) } return nil } @@ -247,7 +280,7 @@ extension ChatViewController: InputBarAccessoryViewDelegate { inputBar.inputTextView.text = String() inputBar.invalidatePlugins() inputBar.sendButton.startAnimating() - inputBar.inputTextView.placeholder = "Sending..." + inputBar.inputTextView.placeholder = "Sending via secure channel..." inputBar.inputTextView.resignFirstResponder() sendE2EMessage(message: textToSend ?? "") } @@ -281,4 +314,39 @@ extension ChatViewController: MessagesDisplayDelegate, MessagesLayoutDelegate { func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat { return !isPreviousMessageSameSender(at: indexPath) ? 20 : 0 } + + func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] { + if !isFromCurrentSender(message: message) { + return [.url,.mention] + } + return [.url] + } + + func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedString.Key : Any] { + if detector == .mention && !isFromCurrentSender(message: message) { + return [NSAttributedString.Key.font: UIFont(name: "Menlo", size: 14.0)!, + NSAttributedString.Key.foregroundColor: Constants.AppColors.appMainColor] + } + return [NSAttributedString.Key.foregroundColor : Constants.AppColors.appMainColor] + } +} + +// MARK: - Message Cell Delegate + +extension ChatViewController: MessageCellDelegate { + func didSelectURL(_ url: URL) { + let safariController = SFSafariViewController(url: url) + present(safariController, animated: true, completion: nil) + } + + func didSelectMention(_ mention: String) { + let providerName = String(mention.dropFirst()) + if let provider = suggestedProviders[providerName] { + let providersStoryBoard = UIStoryboard(name: Constants.Storyboard.providers, bundle: nil) + guard let providersViewController = providersStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardId.providersViewController) as? ProvidersViewController else { return } + providersViewController.suggestedProvider = provider + self.present(providersViewController, animated: true) + } + } } + diff --git a/PrivacyDemo/PrivateProviders/Model/MessageContent.swift b/PrivacyDemo/PrivateProviders/Model/MessageContent.swift index a9581a4ff8f82677481d4a2ba9f484afc70cf38f..bc18fd3815c47c6dc1905f59ebda8ca47592b9e4 100644 --- a/PrivacyDemo/PrivateProviders/Model/MessageContent.swift +++ b/PrivacyDemo/PrivateProviders/Model/MessageContent.swift @@ -4,16 +4,22 @@ public struct MessageContent: Equatable { public init( name: String, xxmessengerUsername: String, - message: String + message: String, + code: String? = nil, + date: String? = nil ) { self.name = name self.xxmessengerUsername = xxmessengerUsername self.message = message + self.code = code + self.date = date } public var name: String? public var xxmessengerUsername: String? public var message: String? + public var code: String? + public var date: String? } extension MessageContent: Codable { @@ -21,6 +27,8 @@ extension MessageContent: Codable { case name = "name" case xxmessengerUsername = "xxmessengerUsername" case message = "message" + case code = "code" + case date = "date" } public init(from decoder: Decoder) throws { @@ -28,5 +36,7 @@ extension MessageContent: Codable { name = try container.decodeIfPresent(String.self, forKey: .name) xxmessengerUsername = try container.decodeIfPresent(String.self, forKey: .xxmessengerUsername) message = try container.decodeIfPresent(String.self, forKey: .message) + code = try container.decodeIfPresent(String.self, forKey: .code) + date = try container.decodeIfPresent(String.self, forKey: .date) } } diff --git a/PrivacyDemo/PrivateProviders/Providers.storyboard b/PrivacyDemo/PrivateProviders/Providers.storyboard index bbad0bf9476ba1abd2df78ad5c482c2d3bf36a6e..15d97ac842d0ca629ba665e53ec9954a0fe4808f 100644 --- a/PrivacyDemo/PrivateProviders/Providers.storyboard +++ b/PrivacyDemo/PrivateProviders/Providers.storyboard @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX"> - <device id="retina6_1" orientation="portrait" appearance="light"/> + <device id="retina4_0" orientation="portrait" appearance="light"/> <dependencies> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> @@ -13,67 +13,137 @@ <objects> <viewController storyboardIdentifier="ProvidersViewController" id="Y6W-OH-hqX" customClass="ProvidersViewController" customModule="PrivacyDemo" customModuleProvider="target" sceneMemberID="viewController"> <view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc"> - <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <rect key="frame" x="0.0" y="0.0" width="320" height="568"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="Vww-MZ-8MO"> - <rect key="frame" x="41.5" y="341" width="331" height="224"/> - <color key="backgroundColor" systemColor="systemBackgroundColor"/> - <color key="textColor" red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="18"/> - <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> - </textView> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dXz-cC-kkF" userLabel="SendMessage"> - <rect key="frame" x="41.5" y="601" width="331" height="60"/> - <constraints> - <constraint firstAttribute="height" constant="60" id="W00-F5-5jk"/> - </constraints> - <state key="normal" title="Button"/> - <buttonConfiguration key="configuration" style="filled"> - <attributedString key="attributedTitle"> - <fragment content="Send Message"> - <attributes> - <font key="NSFont" size="24" name="Menlo-Bold"/> - <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> - </attributes> - </fragment> - </attributedString> - <color key="baseBackgroundColor" red="0.99607843139999996" green="0.46666666670000001" blue="0.31764705879999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - </buttonConfiguration> - <connections> - <action selector="sendMessageButton:" destination="Y6W-OH-hqX" eventType="touchUpInside" id="vjJ-de-fEy"/> - </connections> - </button> - <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="raM-TN-zb4"> - <rect key="frame" x="41.5" y="207" width="232.5" height="30"/> + <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="207-KC-jJc"> + <rect key="frame" x="0.0" y="100" width="320" height="468"/> + <subviews> + <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="Vww-MZ-8MO"> + <rect key="frame" x="20" y="561" width="280" height="136.5"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <color key="textColor" red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="18"/> + <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> + </textView> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dXz-cC-kkF" userLabel="SendMessage"> + <rect key="frame" x="20" y="733.5" width="280" height="60"/> + <constraints> + <constraint firstAttribute="height" constant="60" id="W00-F5-5jk"/> + </constraints> + <state key="normal" title="Button"/> + <buttonConfiguration key="configuration" style="filled"> + <attributedString key="attributedTitle"> + <fragment content="Send Message"> + <attributes> + <font key="NSFont" size="24" name="Menlo-Bold"/> + <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> + </attributes> + </fragment> + </attributedString> + <color key="baseBackgroundColor" red="0.99607843139999996" green="0.46666666670000001" blue="0.31764705879999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </buttonConfiguration> + <connections> + <action selector="sendMessageButton:" destination="Y6W-OH-hqX" eventType="touchUpInside" id="vjJ-de-fEy"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="raM-TN-zb4"> + <rect key="frame" x="20" y="20" width="232.5" height="30"/> + <constraints> + <constraint firstAttribute="height" constant="30" id="IBe-eV-O5x"/> + </constraints> + <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <state key="normal" title="Button"/> + <buttonConfiguration key="configuration" style="plain" image="DropDown" imagePlacement="trailing" imagePadding="10"> + <attributedString key="attributedTitle"> + <fragment content="Select providers"> + <attributes> + <font key="NSFont" size="18" name="Menlo-Bold"/> + <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> + </attributes> + </fragment> + </attributedString> + </buttonConfiguration> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BAb-jC-Suy"> + <rect key="frame" x="20" y="60" width="189.5" height="30"/> + <constraints> + <constraint firstAttribute="height" constant="30" id="JcI-mw-Jgy"/> + </constraints> + <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <state key="normal" title="Button"/> + <buttonConfiguration key="configuration" style="plain" image="DropDown" imagePlacement="trailing" imagePadding="10"> + <attributedString key="attributedTitle"> + <fragment content="Request type"> + <attributes> + <font key="NSFont" size="18" name="Menlo-Bold"/> + <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> + </attributes> + </fragment> + </attributedString> + </buttonConfiguration> + </button> + <stackView opaque="NO" contentMode="center" axis="vertical" alignment="top" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="GfZ-Tv-X5x"> + <rect key="frame" x="20" y="100" width="280" height="445"/> + <subviews> + <datePicker contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" datePickerMode="dateAndTime" minuteInterval="1" style="compact" translatesAutoresizingMaskIntoConstraints="NO" id="24c-bd-huV"> + <rect key="frame" x="0.0" y="0.0" width="280" height="313"/> + </datePicker> + <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your name" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="zDu-Pl-IVh"> + <rect key="frame" x="0.0" y="323" width="280" height="34"/> + <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="18"/> + <textInputTraits key="textInputTraits"/> + </textField> + <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your xx messenger username" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="fht-oq-DuJ"> + <rect key="frame" x="0.0" y="367" width="280" height="34"/> + <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="18"/> + <textInputTraits key="textInputTraits"/> + </textField> + <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Code (Optional)" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="UCN-AH-edz"> + <rect key="frame" x="0.0" y="411" width="280" height="34"/> + <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="18"/> + <textInputTraits key="textInputTraits"/> + </textField> + </subviews> + <constraints> + <constraint firstItem="UCN-AH-edz" firstAttribute="width" secondItem="fht-oq-DuJ" secondAttribute="width" id="04Q-Wf-ySl"/> + <constraint firstItem="zDu-Pl-IVh" firstAttribute="width" secondItem="fht-oq-DuJ" secondAttribute="width" id="bKv-jX-fw1"/> + </constraints> + </stackView> + </subviews> <constraints> - <constraint firstAttribute="height" constant="30" id="IBe-eV-O5x"/> + <constraint firstItem="raM-TN-zb4" firstAttribute="leading" secondItem="Vww-MZ-8MO" secondAttribute="leading" id="5IO-oG-Q5U"/> + <constraint firstItem="GfZ-Tv-X5x" firstAttribute="leading" secondItem="207-KC-jJc" secondAttribute="leading" id="5Yu-vE-XKo"/> + <constraint firstItem="raM-TN-zb4" firstAttribute="trailing" relation="lessThanOrEqual" secondItem="Vww-MZ-8MO" secondAttribute="trailing" id="BMA-PB-Mnd"/> + <constraint firstItem="BAb-jC-Suy" firstAttribute="top" secondItem="raM-TN-zb4" secondAttribute="bottom" constant="10" id="DIU-EY-Bbk"/> + <constraint firstItem="BAb-jC-Suy" firstAttribute="leading" secondItem="Vww-MZ-8MO" secondAttribute="leading" id="DUK-XX-dbH"/> + <constraint firstAttribute="bottom" secondItem="dXz-cC-kkF" secondAttribute="bottom" constant="20" symbolic="YES" id="FKs-XM-bMF"/> + <constraint firstItem="GfZ-Tv-X5x" firstAttribute="top" secondItem="BAb-jC-Suy" secondAttribute="bottom" constant="10" id="G2l-2m-BzO"/> + <constraint firstItem="dXz-cC-kkF" firstAttribute="top" secondItem="Vww-MZ-8MO" secondAttribute="bottom" constant="36" id="HdW-kh-HMW"/> + <constraint firstItem="dXz-cC-kkF" firstAttribute="leading" secondItem="Vww-MZ-8MO" secondAttribute="leading" id="J3x-M9-7Qr"/> + <constraint firstItem="raM-TN-zb4" firstAttribute="top" secondItem="207-KC-jJc" secondAttribute="top" constant="20" symbolic="YES" id="Q7k-qx-WXG"/> + <constraint firstItem="dXz-cC-kkF" firstAttribute="trailing" secondItem="Vww-MZ-8MO" secondAttribute="trailing" id="QUv-cC-4Ac"/> + <constraint firstAttribute="trailing" secondItem="GfZ-Tv-X5x" secondAttribute="trailing" id="TTn-st-9M0"/> + <constraint firstItem="Vww-MZ-8MO" firstAttribute="top" secondItem="GfZ-Tv-X5x" secondAttribute="bottom" constant="16" id="Tm2-PC-Loe"/> + <constraint firstItem="Vww-MZ-8MO" firstAttribute="leading" secondItem="GfZ-Tv-X5x" secondAttribute="leading" id="Y3E-uZ-BgW"/> + <constraint firstItem="Vww-MZ-8MO" firstAttribute="trailing" secondItem="GfZ-Tv-X5x" secondAttribute="trailing" id="jQV-f2-sXz"/> + <constraint firstItem="BAb-jC-Suy" firstAttribute="trailing" relation="lessThanOrEqual" secondItem="Vww-MZ-8MO" secondAttribute="trailing" id="tsm-T1-38I"/> </constraints> - <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <state key="normal" title="Button"/> - <buttonConfiguration key="configuration" style="plain" image="DropDown" imagePlacement="trailing" imagePadding="10"> - <attributedString key="attributedTitle"> - <fragment content="Select providers"> - <attributes> - <font key="NSFont" size="18" name="Menlo-Bold"/> - <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> - </attributes> - </fragment> - </attributedString> - </buttonConfiguration> - </button> + <viewLayoutGuide key="contentLayoutGuide" id="CHi-rC-iOK"/> + <viewLayoutGuide key="frameLayoutGuide" id="4XX-Zs-1Pl"/> + </scrollView> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vOM-Mw-K7C"> - <rect key="frame" x="0.0" y="44" width="414" height="100"/> + <rect key="frame" x="0.0" y="0.0" width="320" height="100"/> <subviews> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Shield" translatesAutoresizingMaskIntoConstraints="NO" id="8G1-Iy-COh"> - <rect key="frame" x="112" y="25" width="50" height="50"/> + <rect key="frame" x="65" y="25" width="50" height="50"/> <constraints> <constraint firstAttribute="height" constant="50" id="K2o-uo-3pr"/> <constraint firstAttribute="width" secondItem="8G1-Iy-COh" secondAttribute="height" multiplier="1:1" id="UVi-Mc-J0N"/> </constraints> </imageView> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Provider" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Elu-Y7-8Yc"> - <rect key="frame" x="167" y="35.5" width="120.5" height="29.5"/> + <rect key="frame" x="120" y="35.5" width="120.5" height="29.5"/> <fontDescription key="fontDescription" name="Menlo-Bold" family="Menlo" pointSize="25"/> <nil key="textColor"/> <nil key="highlightedColor"/> @@ -88,45 +158,30 @@ <constraint firstItem="Elu-Y7-8Yc" firstAttribute="centerY" secondItem="8G1-Iy-COh" secondAttribute="centerY" id="myG-Ln-kwb"/> </constraints> </view> - <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your xx messenger username" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="fht-oq-DuJ"> - <rect key="frame" x="41.5" y="291" width="331" height="34"/> - <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="18"/> - <textInputTraits key="textInputTraits"/> - </textField> - <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Your name" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="zDu-Pl-IVh"> - <rect key="frame" x="41.5" y="247" width="331" height="34"/> - <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="18"/> - <textInputTraits key="textInputTraits"/> - </textField> </subviews> <viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> - <constraint firstItem="dXz-cC-kkF" firstAttribute="top" secondItem="Vww-MZ-8MO" secondAttribute="bottom" constant="36" id="68U-0w-jBi"/> - <constraint firstItem="fht-oq-DuJ" firstAttribute="leading" secondItem="Vww-MZ-8MO" secondAttribute="leading" id="7Sj-YL-8yk"/> - <constraint firstItem="Vww-MZ-8MO" firstAttribute="centerX" secondItem="vDu-zF-Fre" secondAttribute="centerX" id="9eH-eW-R82"/> - <constraint firstItem="zDu-Pl-IVh" firstAttribute="trailing" secondItem="fht-oq-DuJ" secondAttribute="trailing" id="HNJ-Z0-GyF"/> - <constraint firstItem="raM-TN-zb4" firstAttribute="width" relation="lessThanOrEqual" secondItem="Vww-MZ-8MO" secondAttribute="width" id="Ie9-F6-ue2"/> - <constraint firstItem="dXz-cC-kkF" firstAttribute="width" secondItem="Vww-MZ-8MO" secondAttribute="width" id="J5l-SC-nru"/> - <constraint firstItem="fht-oq-DuJ" firstAttribute="top" secondItem="zDu-Pl-IVh" secondAttribute="bottom" constant="10" id="Lvh-B1-c3o"/> - <constraint firstItem="Vww-MZ-8MO" firstAttribute="top" secondItem="fht-oq-DuJ" secondAttribute="bottom" constant="16" id="O71-nW-5zY"/> - <constraint firstItem="Vww-MZ-8MO" firstAttribute="centerY" secondItem="vDu-zF-Fre" secondAttribute="centerY" id="PQ0-WF-UfT"/> - <constraint firstItem="Vww-MZ-8MO" firstAttribute="width" secondItem="5EZ-qb-Rvc" secondAttribute="width" multiplier="0.8" id="RyW-x9-mFT"/> - <constraint firstItem="fht-oq-DuJ" firstAttribute="trailing" secondItem="Vww-MZ-8MO" secondAttribute="trailing" id="VtU-ov-bNd"/> + <constraint firstItem="207-KC-jJc" firstAttribute="leading" secondItem="vDu-zF-Fre" secondAttribute="leading" id="0g2-XH-C0g"/> + <constraint firstItem="vDu-zF-Fre" firstAttribute="trailing" secondItem="GfZ-Tv-X5x" secondAttribute="trailing" constant="20" id="1Sv-k8-bi6"/> + <constraint firstItem="GfZ-Tv-X5x" firstAttribute="leading" secondItem="vDu-zF-Fre" secondAttribute="leading" constant="20" id="ByN-7E-WEW"/> + <constraint firstItem="Vww-MZ-8MO" firstAttribute="height" secondItem="5EZ-qb-Rvc" secondAttribute="height" multiplier="0.24" id="PIq-po-ROC"/> + <constraint firstItem="vDu-zF-Fre" firstAttribute="trailing" secondItem="207-KC-jJc" secondAttribute="trailing" id="Qcg-Js-NFJ"/> <constraint firstItem="vOM-Mw-K7C" firstAttribute="centerX" secondItem="vDu-zF-Fre" secondAttribute="centerX" id="cN6-hE-XFm"/> - <constraint firstItem="Vww-MZ-8MO" firstAttribute="height" secondItem="5EZ-qb-Rvc" secondAttribute="height" multiplier="0.25" id="dQr-ea-6cw"/> - <constraint firstItem="dXz-cC-kkF" firstAttribute="centerX" secondItem="Vww-MZ-8MO" secondAttribute="centerX" id="eN1-Tq-eiq"/> - <constraint firstItem="zDu-Pl-IVh" firstAttribute="centerX" secondItem="fht-oq-DuJ" secondAttribute="centerX" id="lmD-mP-820"/> <constraint firstItem="vOM-Mw-K7C" firstAttribute="width" secondItem="vDu-zF-Fre" secondAttribute="width" id="oNX-QH-d9U"/> <constraint firstItem="vOM-Mw-K7C" firstAttribute="top" secondItem="vDu-zF-Fre" secondAttribute="top" id="pgu-fk-f1w"/> - <constraint firstItem="zDu-Pl-IVh" firstAttribute="top" secondItem="raM-TN-zb4" secondAttribute="bottom" constant="10" id="r7n-PX-fSu"/> - <constraint firstItem="raM-TN-zb4" firstAttribute="leading" secondItem="Vww-MZ-8MO" secondAttribute="leading" id="tvX-5Y-pVY"/> + <constraint firstItem="207-KC-jJc" firstAttribute="top" secondItem="vOM-Mw-K7C" secondAttribute="bottom" id="qpN-k5-j0U"/> + <constraint firstItem="207-KC-jJc" firstAttribute="bottom" secondItem="vDu-zF-Fre" secondAttribute="bottom" id="tTp-L6-9tA"/> </constraints> </view> <connections> + <outlet property="codeTextField" destination="UCN-AH-edz" id="zFZ-9Q-xQs"/> + <outlet property="datePickerView" destination="24c-bd-huV" id="2dF-ij-tMC"/> + <outlet property="fieldsStackView" destination="GfZ-Tv-X5x" id="xW6-zz-j9p"/> <outlet property="messageTextView" destination="Vww-MZ-8MO" id="oAL-41-38h"/> <outlet property="nameTextField" destination="zDu-Pl-IVh" id="cTW-62-ghk"/> <outlet property="selectProviderButton" destination="raM-TN-zb4" id="hrj-fE-bQN"/> + <outlet property="selectRequestTypeButton" destination="BAb-jC-Suy" id="W5R-VD-gIj"/> <outlet property="xxmessengerTextField" destination="fht-oq-DuJ" id="QYB-Vd-Px6"/> </connections> </viewController> diff --git a/PrivacyDemo/PrivateProviders/ProvidersViewController.swift b/PrivacyDemo/PrivateProviders/ProvidersViewController.swift index cc83639cdcaaeeb8729f2f23dc7e732cb69bd2eb..66aa541c01b497c7814fc20dcca0d0abcf947db2 100644 --- a/PrivacyDemo/PrivateProviders/ProvidersViewController.swift +++ b/PrivacyDemo/PrivateProviders/ProvidersViewController.swift @@ -6,23 +6,32 @@ class ProvidersViewController: UIViewController { // MARK: - Outlets + @IBOutlet weak var fieldsStackView: UIStackView! + @IBOutlet weak var selectRequestTypeButton: UIButton! @IBOutlet weak var messageTextView: UITextView! @IBOutlet weak var selectProviderButton: UIButton! @IBOutlet weak var xxmessengerTextField: UITextField! @IBOutlet weak var nameTextField: UITextField! + @IBOutlet weak var datePickerView: UIDatePicker! + @IBOutlet weak var codeTextField: UITextField! + + // MARK: - Public properties + + public var suggestedProvider: (name:String?, requestType: String?, code: String?)? + // MARK: - Private properties - private let messageTextViewPlaceholder = "Type your message here to send it anonymously to your selected provider" + private let messageTextViewPlaceholder = "Type your message here to send it securely to your selected provider" private var connection: Connection? private var loadingIndicator: LoadingIndicatorView! + private var requestType = Constants.RequestType.appointment // MARK: - View LifeCycle override func viewDidLoad() { super.viewDidLoad() setupUI() - initConnection(with: Constants.restlikeRecipentContact1) } override func viewWillDisappear(_ animated: Bool) { @@ -39,7 +48,7 @@ class ProvidersViewController: UIViewController { func sendRestLikeMessage(name: String, username: String, message: String) { let requetToSend = createRequest(name: name, username: username, message: message) - DispatchQueue.global(qos: .background).async { [weak self] in + DispatchQueue.global(qos: .userInteractive).async { [weak self] in guard let self = self else { return } do { let restLikeRequestSender = RestlikeRequestSender.live(authenticated: false) @@ -58,30 +67,44 @@ class ProvidersViewController: UIViewController { } func createRequest(name: String, username: String, message: String) -> RestlikeMessage { - let content = MessageContent(name: name, xxmessengerUsername: username, message: message) + var uri = String() + var date: String? + if requestType == .request { + uri = Constants.requestURI + date = nil + } else { + uri = Constants.appointmentURI + date = datePickerView.date.formatted(date: .abbreviated, time: .shortened) + } + let content = MessageContent(name: name, + xxmessengerUsername: username, + message: message, + code: codeTextField.text, + date: date) let contentEncoded = try! JSONEncoder().encode(content) let restLikeMessage = RestlikeMessage(version: 0, headers: Data("".utf8), content: contentEncoded, method: 1, - uri: "xx://provider", + uri: uri, error: "") return restLikeMessage } func initConnection(with providerIdentity: String) { - loadingIndicator.startAnimating(inView: self.view, shouldDisableInteraction: true, text: "Initiating...") - DispatchQueue.global(qos: .background).async { [weak self] in + loadingIndicator.startAnimating(inView: self.view, shouldDisableInteraction: true, text: "Initiating & securing connection") + DispatchQueue.global(qos: .userInteractive).async { [weak self] in guard let self = self else { return } do { if self.connection != nil { try self.connection!.close() } + let clientE2E = try ClientE2ELogin.live(with: ElixxirHandler.shared.client!) self.connection = try ElixxirHandler.shared.client!.connect(withAuthentication: false, recipientContact: Data(providerIdentity.utf8), - myIdentity: ElixxirHandler.shared.myIdentity) + e2eId: clientE2E.getId()) DispatchQueue.main.async { [weak self] in guard let self = self else { return } self.loadingIndicator.stopAnimating() @@ -100,6 +123,28 @@ class ProvidersViewController: UIViewController { setupMessageTextView() setupTextFields() setupProvidersButton() + setupRequestTypeButton() + setupDatePickerView() + prefillIfNecessary() + } + + func prefillIfNecessary() { + guard let suggestedProvider = suggestedProvider else { + setupProvidersButtonMenu() + return + } + if let requestType = suggestedProvider.requestType, let type = Constants.RequestType(rawValue: requestType) { + setupRequestTypeButtonMenu(initialSelection: type) + + } + if let code = suggestedProvider.code { + codeTextField.text = code + } + if let name = suggestedProvider.name, let type = Constants.ProviderNames(rawValue: name) { + setupProvidersButtonMenu(initialSelection: type) + } else { + setupProvidersButtonMenu() + } } func setupMessageTextView() { @@ -110,6 +155,13 @@ class ProvidersViewController: UIViewController { setMessageTextViewPlaceholder() } + func setupDatePickerView() { + let minDate = Calendar.current.date(byAdding: .day, value: +1, to: Date()) + datePickerView.minimumDate = minDate + datePickerView.maximumDate = Calendar.current.date(byAdding: .month, value: +1, to: Date()) + datePickerView.setDate(minDate!, animated: true) + } + func setupTextFields() { nameTextField.layer.borderWidth = 0.5 nameTextField.layer.borderColor = Constants.AppColors.appBlackColor.cgColor @@ -117,18 +169,27 @@ class ProvidersViewController: UIViewController { xxmessengerTextField.layer.borderWidth = 0.5 xxmessengerTextField.layer.borderColor = Constants.AppColors.appBlackColor.cgColor xxmessengerTextField.layer.cornerRadius = 5.0 + codeTextField.layer.borderWidth = 0.5 + codeTextField.layer.borderColor = Constants.AppColors.appBlackColor.cgColor + codeTextField.layer.cornerRadius = 5.0 } func setupProvidersButton() { selectProviderButton.layer.borderWidth = 0.5 selectProviderButton.layer.borderColor = Constants.AppColors.appBlackColor.cgColor selectProviderButton.layer.cornerRadius = 5.0 - setupProvidersButtonMenu() - selectProviderButton.changesSelectionAsPrimaryAction = true - selectProviderButton.showsMenuAsPrimaryAction = true } - func setupProvidersButtonMenu() { + func setupRequestTypeButton() { + selectRequestTypeButton.layer.borderWidth = 0.5 + selectRequestTypeButton.layer.borderColor = Constants.AppColors.appBlackColor.cgColor + selectRequestTypeButton.layer.cornerRadius = 5.0 + setupRequestTypeButtonMenu() + selectRequestTypeButton.changesSelectionAsPrimaryAction = true + selectRequestTypeButton.showsMenuAsPrimaryAction = true + } + + func setupProvidersButtonMenu(initialSelection: Constants.ProviderNames = .provider1) { let providerOneAction = UIAction(title: "Provider 1", handler: { [weak self] (action: UIAction) in guard let self = self else { return } self.initConnection(with: Constants.restlikeRecipentContact1) @@ -141,8 +202,42 @@ class ProvidersViewController: UIViewController { guard let self = self else { return } self.initConnection(with: Constants.restlikeRecipentContact3) }) - let providersMenu = UIMenu(title: "", options: .displayInline, children: [providerOneAction, providerTwoAction, providerThreeAction]) + var menuChildren = [UIMenuElement]() + if initialSelection == .provider1 { + menuChildren = [providerOneAction, providerTwoAction, providerThreeAction] + self.initConnection(with: Constants.restlikeRecipentContact1) + } else if initialSelection == .provider2 { + menuChildren = [providerTwoAction, providerOneAction, providerThreeAction] + self.initConnection(with: Constants.restlikeRecipentContact2) + } else if initialSelection == .provider3 { + menuChildren = [providerThreeAction, providerOneAction, providerTwoAction, ] + self.initConnection(with: Constants.restlikeRecipentContact3) + } + let providersMenu = UIMenu(title: "", options: .displayInline, children: menuChildren) selectProviderButton.menu = providersMenu + selectProviderButton.changesSelectionAsPrimaryAction = true + selectProviderButton.showsMenuAsPrimaryAction = true + } + + func setupRequestTypeButtonMenu(initialSelection: Constants.RequestType = .appointment) { + let requestAction = UIAction(title: "Request", handler: { [weak self] (action: UIAction) in + guard let self = self else { return } + self.updateUIForRequestType(.request) + }) + let appointmentAction = UIAction(title: "Appointment", handler: { [weak self] (action: UIAction) in + guard let self = self else { return } + self.updateUIForRequestType(.appointment) + }) + var menuChildren = [UIMenuElement]() + if initialSelection == .appointment { + menuChildren = [appointmentAction, requestAction] + updateUIForRequestType(.appointment) + } else { + menuChildren = [requestAction, appointmentAction] + updateUIForRequestType(.request) + } + let requestTypesMenu = UIMenu(title: "", options: .displayInline, children: menuChildren) + selectRequestTypeButton.menu = requestTypesMenu } func setMessageTextViewPlaceholder() { @@ -172,16 +267,16 @@ class ProvidersViewController: UIViewController { @IBAction func sendMessageButton(_ sender: Any) { view.endEditing(true) guard connection != nil else { - AlertsHandler.shared.showAlert(in: self, title: "Error", message: "A connection is being created, please try again later") + AlertsHandler.shared.showAlert(in: self, title: "Error", message: "A secure connection is being created, please try again later") return } guard let name = nameTextField.text, let username = xxmessengerTextField.text, let message = messageTextView.text, message != messageTextViewPlaceholder else { AlertsHandler.shared.showAlert(in: self, title: "Error", - message: "All fields are mandatory") + message: "Name and Message fields are mandatory") return } - loadingIndicator.startAnimating(inView: self.view, shouldDisableInteraction: true, text: "Sending...") + loadingIndicator.startAnimating(inView: self.view, shouldDisableInteraction: true, text: "Sending through secure channel") sendRestLikeMessage(name: name, username: username, message: message) } @@ -195,7 +290,16 @@ class ProvidersViewController: UIViewController { } let responseMessage = String(decoding: responseMessageData, as: UTF8.self) loadingIndicator.stopAnimating() - AlertsHandler.shared.showAlert(in: self, title: "Success!", message: responseMessage ) + AlertsHandler.shared.showAlert(in: self, title: "Success ✅", message: responseMessage ) + } + + func updateUIForRequestType( _ type: Constants.RequestType) { + self.requestType = type + if type == .request { + self.fieldsStackView.removeArrangedSubview(self.datePickerView) + } else { + self.fieldsStackView.insertArrangedSubview(self.datePickerView, at: 0) + } } } diff --git a/PrivacyDemo/Shared/Constants/AppConstants.swift b/PrivacyDemo/Shared/Constants/AppConstants.swift index 1d78a9b4468d668bcc9af6a838f3d97a38c72eed..8a81b73008d3d97fac17142c4133d2ac5327791d 100644 --- a/PrivacyDemo/Shared/Constants/AppConstants.swift +++ b/PrivacyDemo/Shared/Constants/AppConstants.swift @@ -1,8 +1,10 @@ enum Constants { static let helperUserId = "helperUserId" static let currentUserId = "currentUserId" - static let restlikeRecipentContact1 = "<xxc(2)2hbFZO100M/Ez0hs8VmDhz/damrQaFrD00YKQ0D6bdsDkAZiB9kZo+Dl3ZV7qL8KjTfjD/JOYqoiD2+8LEeiJE9Gs8W4o42CwDuB4j1SeEdoailWEMGfFZN1/f+ekelnSpMXFsJwiOS3V71ABqqqHscXDPKwW28jB9y/lKu3+egIggQtu2wcZFxZH+i6djrumFMhbpso1YKARVlotw8KlTPFu5XyZWYXwtFqhAMapY/IfDesQ6EDZS42G2c8RilGZKPPpatJzdvZVklh214OcBVjHixGY/eTi5NteyWddbG6GfyGyL7o/14q0VpnGUSaRPdHChfmetTJSdHFVcYRTXZR0LtAiLn3xZjGiv7hgR/vf+sek3GtZD9Xfvne/6MotJEKWXUxnKEuBIQjbkY0QDf43a62VzAcaxR6rCOZne0Lju5izB3GUWdfRmmPDGO4TVGqRCctMqGPyt6kadVoBT0VGxpx+ib/1uzM0A8lcs5TsaT+vuIeurYjginj8L8/yIxPXaNxWKq5FsvDUr6goWGCNmbWCXNdQx5YddqiliU7i8iTO4kVLimsjgAAAgA77W6a0Ty6I84GZWU2cEuXzA==xxc>" - static let restlikeRecipentContact2 = "<xxc(2)bKdnNxhdt9zn4k289I8DRe/ivUfSORt9Mu6qBOPZzOADkAZiB9kZo+Dl3Rf7jvn1nonhao4F4EanQj7qDrDUa4MPvdno+06RaY7YO9MgnMGUTZwfKkNwWYGygAUGR6/KFCbjJm8ElFzxV0lO/pKH6jYxQfPfHy0reALK7HmHmugFiufBiNDrq9G1dpXlqziiXA6E3ypXZNqE7JwF5QBFL87K2KuZxYMBBiFkbtqCFPcsQe/w4p8cbn1MlmhKJooD2XWe6MRVYF8lgrddmv1yqymg6fgn85usF1pgRAREYFqUawIvUU0eEKvOQKtlw1jf6Jo8ujtNJ+DbpTz8CxDh3Xb/nInKwV7IzKjVXAyB7tJv6A3SNrr94N4MrX99NFe6zYCiqbxDdQ4tHzABOzOlTdSwnXl7GBWdHHfmSu2CqrH4MBzf5ka93/Wx91UoNUN5HBak+WxC7m6vc+5NJkMAmJyp/9vH3gOEHa/VW0wCGzFJznStiQmayA1eaCzPvck/1qNpJIy5UTgiqkQhF65+OFKjg1pV/kNe1zz7lf5QjfBZ9fS6wkD9yvPDaAAAAgA7VwTH7U6UlSlreTjGDE8Tlw==xxc>" + static let requestURI = "xx://provider/requests" + static let appointmentURI = "xx://provider/appointments" + static let restlikeRecipentContact1 = "<xxc(2)Xx5yf7AmhChGjVPUWta9ujXw8dXZZ5K7PDLn/9rgCvoDkAZiB9kZo+Dl3UYXp3CvGc5hG/7OiQzr4RWUEOOmNUd1uTb3X5ouFXk5PMsN026NvP35stjo3g2aR9KM++AW5PjFGQdhJjttFtLpnm54606K4EI5o4hE7R7crlUd+vMeH7tJGA0S3jzKmPmaUnXEFowiyqzKWy6GdQF7D8iSs1P4sKrA8XEbECy482yDEWS2k9P11PmqGjf4hlAHYW5BVk/S5+0l8mkVk1mXZzx+N9c9MfZcJDHHO5hpmr2h5PDD3c1CwdiUAdrB/gUU966zfrQZD5h1d6ISYwvhO166+kxQZch8aeblMSx4georu2WwWwi9HFIi0FF8VX4VG7uQRTJ794Ivwl/Sd8S3xittKDuVYdmpom3Yjlvih9H/oXfbynGboquwnJ/0De7avIv8x/pchtyMdQXGTt4AR3lXPsiDR8IrEanOc8rV6x08b07H/sanMW003RFhrAswnN+8AV+yypD+nsQZMV7KZu7v0H7dw7ptRbB0oC8kCjWSQoE9ozXchZcW/eBNYAAAAgA7vIMzZPFY/MyRq8I3nCihsg==xxc>" + static let restlikeRecipentContact2 = "<xxc(2)64RnR1Xq6LeZVmW594jTOeLE/O2sXmaxW+LL7tCkmd4DkAZiB9kZo+Dl3Z46FMEwwfKhT7aUpFZIx4ofFfugGEur0+B7tX0etmFBjuCXo12VmBWgQIs/AsMGOedLDn7x0RE6lEaHMj5M2Fvo0aFdznPRVeiDBUU4+yOCqxQOKnWHhI8xnpOo19txVA/16Kki5+x/M2HIK45vTkp4yyE3lM/3omRiQ+SYs+x4FrwsqJg7ytgMiaN/O3oO0s/fLPEVhH6jB3SmU6Zxw4ruEXdJtIsSiTggh2Cb50X0/id2s43e9CClb/N4ZiRJFVhvoyN17SZps0K4uR5U0IpiiZrHaBNaKjTi95vfu2BYWiHAoMZha+vvghbYzKx3DJoQ+wQAzCwykoW7z+5Kmhs8RMxiKFx0/QjGvoUGeBm+EV6d/Ucj7OVXPSrBcygno3qRWom83fA4tMpN/bdWTBX20bbsXHc6xvc39jVdKk66A00Z+6yXK+XCPMuC92FfoxPEB9HB+A43psa7VsHcK3pozCZjbpNCROnjr0XcUSM3UvInOQ1D4jzqOyPqwCPrxgAAAgA7grQe3h9oOykEor9/LtTeFw==xxc>" static let restlikeRecipentContact3 = "<xxc(2)DrJkB6ZkJuUQnYUHuD0mhinEljftAHqgbYaNZsKgfs0DkAZiB9kZo+Dl3eOV7F5C13jtMlPfOza96+VDcfvE6Tb/LzEpwo1dGyhyDvIIoLBMHwqQKgVu4WQV+S0JQjcipGifBFVzOL8/eOY/6mUd+QPTvVGCqjSznc7jIswts1eyXAAh1q2acD7/i6H6YkKLll6RCfplPM8S6eFNeAkv/sNSvha0c5vG45e7xGx2welkBk9gZeRZcrk5ujJ6QEzHXAV6a2tY/AfncxLfYEHcAxhtWXZ5Jt9/Mnbt0EAoa4wIYpymwQCPIbj59a0UN91+VrLeU7qG0tB012zRR0cBorLRKGlEpbZjsEpixdgk8WHvXRwuGhnNt3OI1YTflQFwnGJBXOR4hfjze5M57wxmwk69KVRpL8Ti9QUxPCPdSvqcsLJP6iTn5vNUkIrU2aBKKeWPm/xx89ogOmcBpM9BET3U7aoAhOt2p64GAyDbRXSE54jmn8hGQN0krTlpv7n3GyO9tdD7TsEFtCERhjCDhX+wDmaCLBt/+34w5b2yLT261QMLsaf0U1C8AAAAAgA7MySITSJY9K5kqDri4PqUQg==xxc>" - static let chatRecipentContact = "<xxc(2)0pUtZWXUWcM3DiehwBSyOV8v6zt+0ljPTfNasM25JogDkAZiB9kZo+Dl3eDk09HOEXCOhL8HZA3MUwsW1r5CxKpAgB+G36Yn//VOgMEi3p5pAs/NJSdR9X9gc3P9qgOD1/OeHD4VPYJRIP94mnQYpERx75zY3JBcnWo33ttimDc2OxcGbHaUW95hGp19hCfyH7Gyi4Y9BQWIYfl9+8rKbuhm23TPVyB1UWo8PAlPZzfzSUDHKrys5Q4mIUBvmbWQEIOVsTIXLrXRYfXetZwfJPa0L5LAkcwkhLgHm52T8riKvAaWzfHuy5dxoun7ZgXhGTPrfMT8aBjQxlzAwDVbCikRfIr5/PINP/QFCMLjEgzO8O72LNCGyrWrGIY/NVwJtV9F52KSoDc2ekFEI+PCODnfVnpTfPfnrcyCVHarjbjgWXeSezZC228phijN4+RUOpAAGm0wrBTxd2CgGcgXkh7s1FdnJJVedXCUmCpV71CluQw3pdWs+xFgaOS4Bya2ZgeCgkJ2VP2CLJGEBczv9rdA6Cw3T+B6qpEv2lKd+0SkuTwBPWFRy22YVwAAAgA7rdCx8oMNgZkEpV0IiK2uSQ==xxc>" + static let chatRecipentContact = "<xxc(2)2furAbBfohn6J7XXuie8pD7bSb7vdnuw5pMAzixeu6MDkAZiB9kZo+Dl3cSC5nUj/ufGeOUqjBS34nckc48ex+NcMBymebmwFmCkX9iamYcV2xfc38RCQLQof4OZ+72ZPHYuw5n2+tzUCtFPIg/OqtHFLUxiioNb1QNe9hfwIn0QCPur7rc5wQyC2WDIkzp68M++WsVucn5R0bOfbloKLgExwnGt/S5CtPt3E2sTLQ8+LAJyzx08FGBwiniQv3qG2/q1mtdRTDQSGugt95ygxLX1LODyavi3DbWic3kRxjhIFrCl47r/L8ZuKbY34pJGKyMIfwwyRwSr8pgUu1IMaqY/xeEd3unpcov062KpkPKySVO4vHqnpas6mrvQVzhEmWZw6gS7SiHOydegkJPfeSb7QBkMPtCD4BQ26wVQ9HrRYLfyT76IgJbuQ7kBFGL4tjn9LN3/q4N9MzTffLkSDaLnJCDQhrdXMJNH7DPQIdzwexf2DgF80wRsoV+TlFySchA0FYjFqmzytkzAmVtepqIF0KvEo59mWwxSei01wbtIr9fGeYDVjZkZ6QAAAgA7D7/T5liW+QnfCLlYeNLhkg==xxc>" } diff --git a/PrivacyDemo/Shared/Constants/ProviderNameConstants.swift b/PrivacyDemo/Shared/Constants/ProviderNameConstants.swift new file mode 100644 index 0000000000000000000000000000000000000000..6c5d901c803fb1101742303da8057a055d0885a9 --- /dev/null +++ b/PrivacyDemo/Shared/Constants/ProviderNameConstants.swift @@ -0,0 +1,8 @@ +import UIKit +extension Constants { + enum ProviderNames: String { + case provider1 = "providerone" + case provider2 = "providertwo" + case provider3 = "providerthree" + } +} diff --git a/PrivacyDemo/Shared/Constants/RequestTypeConstants.swift b/PrivacyDemo/Shared/Constants/RequestTypeConstants.swift new file mode 100644 index 0000000000000000000000000000000000000000..9761f5030203799da9314b692712d6772990cbd5 --- /dev/null +++ b/PrivacyDemo/Shared/Constants/RequestTypeConstants.swift @@ -0,0 +1,7 @@ +import UIKit +extension Constants { + enum RequestType: String { + case request = "req" + case appointment = "apt" + } +} diff --git a/PrivacyDemo/Shared/ElixxirHandler/ElixxirHandler.swift b/PrivacyDemo/Shared/ElixxirHandler/ElixxirHandler.swift index 77e6e874cbd08235db62ea888f2569834025206a..d028c3db7c3f7962b807246577fafda2c1659cba 100644 --- a/PrivacyDemo/Shared/ElixxirHandler/ElixxirHandler.swift +++ b/PrivacyDemo/Shared/ElixxirHandler/ElixxirHandler.swift @@ -5,27 +5,23 @@ final class ElixxirHandler { static let shared = ElixxirHandler() private var clientStorage: ClientStorage! var client: Client! - var myIdentity: Identity! private init(){ clientStorage = ClientStorage.live(passwordStorage: .keychain) } func initClient(completion: @escaping (Error?) -> Void ) { - DispatchQueue.global(qos: .background).async { + DispatchQueue.global(qos: .userInteractive).async { [weak self] in + guard let self = self else { return } do { if self.clientStorage.hasStoredClient() { self.client = try self.clientStorage.loadClient() - self.myIdentity = try self.client.makeIdentity() } else { self.client = try self.clientStorage.createClient() - self.myIdentity = try self.client.makeIdentity() } - DispatchQueue.main.async { completion(nil) } - } catch (let error) { DispatchQueue.main.async { completion(error) diff --git a/PrivacyDemo/Shared/Helpers/LoadingIndicatorHandler.swift b/PrivacyDemo/Shared/Helpers/LoadingIndicatorHandler.swift index 03da9c20b84f2c06e2843e06139c1c4fd6816965..88a9e7829c9941d87b32730fc6bce54794a38a60 100644 --- a/PrivacyDemo/Shared/Helpers/LoadingIndicatorHandler.swift +++ b/PrivacyDemo/Shared/Helpers/LoadingIndicatorHandler.swift @@ -5,13 +5,13 @@ struct LoadingIndicatorView { private var view: NVActivityIndicatorView! private var label: UILabel? - init(frame: CGRect = CGRect(x: UIScreen.main.bounds.midX-50, - y: UIScreen.main.bounds.midY-50, - width: 100.0, - height: 100.0), + init(frame: CGRect = CGRect(x: UIScreen.main.bounds.midX-100, + y: UIScreen.main.bounds.midY-100, + width: 200.0, + height: 200.0), color: UIColor = Constants.AppColors.appMainColor, type: NVActivityIndicatorType = .ballScaleRippleMultiple, - padding: CGFloat = 20.0, + padding: CGFloat = 50.0, background: UIColor = .white, cornerRadius: CGFloat = 10.0) { self.view = NVActivityIndicatorView(frame: frame, @@ -43,11 +43,12 @@ struct LoadingIndicatorView { } private func createLabel(_ text: String) -> UILabel { - let label = UILabel(frame: CGRect(x: self.view.frame.minX, y: self.view.frame.maxY-20, width: self.view.bounds.width, height: 20)) - label.font = UIFont(name: "Menlo", size: 10.0)! + let label = UILabel(frame: CGRect(x: self.view.frame.minX, y: self.view.frame.maxY-50, width: self.view.bounds.width, height: 50)) + label.font = UIFont(name: "Menlo", size: 12.0)! label.textColor = .black label.textAlignment = .center label.text = text + label.numberOfLines = 0 return label } } diff --git a/PrivacyDemo/Splash/Splash.storyboard b/PrivacyDemo/Splash/Splash.storyboard index 1d006885626a422021c2fbfee05cf7f03ea535b9..835ab1889724de5dc94bfeccf15c2d8653d1d7b6 100644 --- a/PrivacyDemo/Splash/Splash.storyboard +++ b/PrivacyDemo/Splash/Splash.storyboard @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX"> - <device id="retina6_0" orientation="portrait" appearance="light"/> + <device id="retina5_9" orientation="portrait" appearance="light"/> <dependencies> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> @@ -13,20 +13,20 @@ <objects> <viewController storyboardIdentifier="SplashViewController" id="Y6W-OH-hqX" customClass="SplashViewController" customModule="PrivacyDemo" customModuleProvider="target" sceneMemberID="viewController"> <view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc"> - <rect key="frame" x="0.0" y="0.0" width="390" height="844"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="812"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PhY-jf-b1c"> - <rect key="frame" x="39" y="321.66666666666669" width="312" height="211.00000000000006"/> + <rect key="frame" x="37.666666666666657" y="313.66666666666669" width="300" height="194.66666666666669"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shielded Help" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="UBa-19-Yu1"> - <rect key="frame" x="20" y="20" width="272" height="45"/> + <rect key="frame" x="20" y="20" width="260" height="68.666666666666671"/> <fontDescription key="fontDescription" name="Menlo-Bold" family="Menlo" pointSize="40"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Shield" translatesAutoresizingMaskIntoConstraints="NO" id="D7F-Eb-J26"> - <rect key="frame" x="97" y="73" width="118" height="118"/> + <rect key="frame" x="111" y="96.666666666666629" width="77.666666666666686" height="78"/> <constraints> <constraint firstAttribute="width" secondItem="D7F-Eb-J26" secondAttribute="height" multiplier="1:1" id="2ms-fm-Oqg"/> </constraints> @@ -36,6 +36,7 @@ <constraints> <constraint firstAttribute="bottom" secondItem="D7F-Eb-J26" secondAttribute="bottom" constant="20.000000000000057" id="6O4-Ra-2Tl"/> <constraint firstItem="D7F-Eb-J26" firstAttribute="top" secondItem="UBa-19-Yu1" secondAttribute="bottom" constant="8" symbolic="YES" id="B4g-WV-dci"/> + <constraint firstItem="D7F-Eb-J26" firstAttribute="height" secondItem="PhY-jf-b1c" secondAttribute="height" multiplier="0.4" id="KAc-d0-9oB"/> <constraint firstAttribute="trailing" secondItem="UBa-19-Yu1" secondAttribute="trailing" constant="20" symbolic="YES" id="WTq-eX-9BT"/> <constraint firstItem="UBa-19-Yu1" firstAttribute="top" secondItem="PhY-jf-b1c" secondAttribute="top" constant="20" symbolic="YES" id="X9g-iq-vPs"/> <constraint firstItem="D7F-Eb-J26" firstAttribute="centerX" secondItem="PhY-jf-b1c" secondAttribute="centerX" id="cBC-BW-go2"/> @@ -47,7 +48,7 @@ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <constraints> <constraint firstItem="PhY-jf-b1c" firstAttribute="width" secondItem="5EZ-qb-Rvc" secondAttribute="width" multiplier="0.8" id="CpH-Np-Kaf"/> - <constraint firstItem="PhY-jf-b1c" firstAttribute="height" secondItem="5EZ-qb-Rvc" secondAttribute="height" multiplier="0.25" id="HXv-O6-yzw"/> + <constraint firstItem="PhY-jf-b1c" firstAttribute="height" secondItem="5EZ-qb-Rvc" secondAttribute="height" multiplier="0.24" id="HXv-O6-yzw"/> <constraint firstItem="PhY-jf-b1c" firstAttribute="centerX" secondItem="vDu-zF-Fre" secondAttribute="centerX" id="ct5-ri-gX9"/> <constraint firstItem="PhY-jf-b1c" firstAttribute="centerY" secondItem="vDu-zF-Fre" secondAttribute="centerY" id="o35-bW-hCF"/> </constraints>